package main import ( "fmt" "html" "io/ioutil" "os" "strings" "time" "golang-fave/engine/mysqlpool" "golang-fave/engine/sqlw" "golang-fave/engine/wrapper/config" "golang-fave/utils" ) func xml_gen_currencies(db *sqlw.DB, conf *config.Config) string { result := `` rows, err := db.Query( `SELECT code, coefficient FROM shop_currencies ORDER BY id ASC ;`, ) if err == nil { defer rows.Close() values := make([]string, 2) scan := make([]interface{}, len(values)) for i := range values { scan[i] = &values[i] } for rows.Next() { err = rows.Scan(scan...) if err == nil { result += `` } } } return result } func xml_gen_categories(db *sqlw.DB, conf *config.Config) string { result := `` rows, err := db.Query( `SELECT data.id, data.user, data.name, data.alias, data.lft, data.rgt, MAX(data.parent_id) AS parent_id FROM ( SELECT node.id, node.user, node.name, node.alias, node.lft, node.rgt, parent.id AS parent_id FROM shop_cats AS node, shop_cats AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.id > 1 ORDER BY node.lft ASC ) AS data WHERE data.id <> data.parent_id GROUP BY data.id ORDER BY data.lft ASC ;`, ) if err == nil { defer rows.Close() values := make([]string, 7) scan := make([]interface{}, len(values)) for i := range values { scan[i] = &values[i] } for rows.Next() { err = rows.Scan(scan...) if err == nil { if utils.StrToInt(string(values[6])) > 1 { result += `` + html.EscapeString(string(values[2])) + `` } else { result += `` + html.EscapeString(string(values[2])) + `` } } } } return result } func xml_gen_offer_pictures(db *sqlw.DB, conf *config.Config, product_id int) string { result := `` rows, err := db.Query( `SELECT shop_product_images.product_id, shop_product_images.filename FROM shop_product_images WHERE shop_product_images.product_id = ? ORDER BY shop_product_images.ord ASC ;`, product_id, ) if err == nil { defer rows.Close() values := make([]string, 2) scan := make([]interface{}, len(values)) for i := range values { scan[i] = &values[i] } for rows.Next() { err = rows.Scan(scan...) if err == nil { result += `` + html.EscapeString((*conf).API.XML.Url) + `products/images/` + html.EscapeString(string(values[0])) + `/` + html.EscapeString(string(values[1])) + `` } } } return result } func xml_gen_offer_attributes(db *sqlw.DB, conf *config.Config, product_id int) string { result := `` filter_ids := []int{} filter_names := map[int]string{} filter_values := map[int][]string{} rows, err := db.Query( `SELECT shop_filters.id, shop_filters.filter, shop_filters_values.name FROM shop_filter_product_values LEFT JOIN shop_filters_values ON shop_filters_values.id = shop_filter_product_values.filter_value_id LEFT JOIN shop_filters ON shop_filters.id = shop_filters_values.filter_id WHERE shop_filter_product_values.product_id = ? ORDER BY shop_filters.filter ASC, shop_filters_values.name ASC ;`, product_id, ) if err == nil { defer rows.Close() values := make([]string, 3) scan := make([]interface{}, len(values)) for i := range values { scan[i] = &values[i] } for rows.Next() { err = rows.Scan(scan...) if err == nil { if !utils.InArrayInt(filter_ids, utils.StrToInt(string(values[0]))) { filter_ids = append(filter_ids, utils.StrToInt(string(values[0]))) } filter_names[utils.StrToInt(string(values[0]))] = html.EscapeString(string(values[1])) filter_values[utils.StrToInt(string(values[0]))] = append(filter_values[utils.StrToInt(string(values[0]))], string(values[2])) } } } for _, filter_id := range filter_ids { result += `` + html.EscapeString(strings.Join(filter_values[filter_id], ", ")) + `` } return result } func xml_gen_offers(db *sqlw.DB, conf *config.Config) string { result := `` rows, err := db.Query( `SELECT shop_products.id, shop_currencies.code, shop_products.price, shop_products.name, shop_products.alias, shop_products.vendor, shop_products.quantity, shop_products.category, shop_products.content FROM shop_products LEFT JOIN shop_currencies ON shop_currencies.id = shop_products.currency WHERE shop_products.active = 1 AND shop_products.category > 1 ORDER BY shop_products.id ;`, ) if err == nil { defer rows.Close() values := make([]string, 9) scan := make([]interface{}, len(values)) for i := range values { scan[i] = &values[i] } for rows.Next() { err = rows.Scan(scan...) if err == nil { result += `` result += `` + html.EscapeString((*conf).API.XML.Url) + `shop/` + html.EscapeString(string(values[4])) + `/` result += `` + utils.Float64ToStrF(utils.StrToFloat64(string(values[2])), "%.2f") + `` result += `` + html.EscapeString(string(values[1])) + `` result += `` + html.EscapeString(string(values[7])) + `` result += xml_gen_offer_pictures(db, conf, utils.StrToInt(string(values[0]))) result += `` + html.EscapeString(string(values[5])) + `` result += `` + html.EscapeString(string(values[6])) + `` result += `` + html.EscapeString(string(values[3])) + `` result += `` result += xml_gen_offer_attributes(db, conf, utils.StrToInt(string(values[0]))) result += `` } } } return result } func xml_generate(db *sqlw.DB, conf *config.Config) string { return `` + `` + `` + `` + `` + html.EscapeString((*conf).API.XML.Name) + `` + `` + html.EscapeString((*conf).API.XML.Company) + `` + `` + html.EscapeString((*conf).API.XML.Url) + `` + `` + xml_gen_currencies(db, conf) + `` + `` + xml_gen_categories(db, conf) + `` + `` + xml_gen_offers(db, conf) + `` + `` + `` } func xml_create(dir, host string, db *sqlw.DB) { conf := config.ConfigNew() if err := conf.ConfigRead(strings.Join([]string{dir, "config", "config.json"}, string(os.PathSeparator))); err == nil { if (*conf).API.XML.Enabled == 1 { if file, err := os.Create(strings.Join([]string{dir, "htdocs", "products.xml"}, string(os.PathSeparator))); err == nil { file.Write([]byte(xml_generate(db, conf))) file.Close() } else { fmt.Printf("Xml generation error (file): %v\n", err) } } } else { fmt.Printf("Xml generation error (config): %v\n", err) } } func xml_detect(dir, host string, mp *mysqlpool.MySqlPool) { db := mp.Get(host) if db != nil { trigger := strings.Join([]string{dir, "tmp", "trigger.xml.run"}, string(os.PathSeparator)) if utils.IsFileExists(trigger) { if err := db.Ping(); err == nil { xml_create(dir, host, db) os.Remove(trigger) } } } } func xml_loop(www_dir string, stop chan bool, mp *mysqlpool.MySqlPool) { dirs, err := ioutil.ReadDir(www_dir) if err == nil { for _, dir := range dirs { select { case <-stop: break default: if mp != nil { target_dir := strings.Join([]string{www_dir, dir.Name()}, string(os.PathSeparator)) if utils.IsDirExists(target_dir) { xml_detect(target_dir, dir.Name(), mp) } } } } } } func xml_start(www_dir string, mp *mysqlpool.MySqlPool) (chan bool, chan bool) { ch := make(chan bool) stop := make(chan bool) // Run at start xml_loop(www_dir, stop, mp) go func() { for { select { case <-time.After(5 * time.Second): // Run every 5 seconds xml_loop(www_dir, stop, mp) case <-ch: ch <- true return } } }() return ch, stop } func xml_stop(ch, stop chan bool) { for { select { case stop <- true: case ch <- true: <-ch return case <-time.After(3 * time.Second): fmt.Println("Xml error: force exit by timeout after 3 seconds") return } } }