package main import ( "bytes" "compress/zlib" "encoding/json" "errors" "fmt" "log" "regexp" "strconv" "sync" "time" ) var ( cacheObjCastle *sync.Map cacheObjGuild *sync.Map cacheObjUser *sync.Map cacheObjMsg *sync.Map cacheObjType map[string]int64 cacheObjSubType map[string]int64 cacheObjItem map[string]ChatWarsItem muxObjItem sync.Mutex cacheObjItemId map[int64]ChatWarsItem muxObjItemId sync.Mutex cacheObjJob map[int64]Job muxObjJob sync.Mutex ) func initCache() { var err error log.Println("Caching obj_type ..") err = loadObjType() logOnError(err, "initCache : caching obj_type") log.Println("Caching obj_sub_type ..") err = loadObjSubType() logOnError(err, "initCache : caching obj_sub_type") log.Println("Filling message parsing rules...") resetMsgParsingRules() msgParsingRules, err = loadMsgParsingRules() logOnError(err, "initCache : message parsing rules") log.Println("Caching guilds ..") err = loadObjGuild() logOnError(err, "initCache : caching guilds") log.Println("Caching users ..") err = loadObjUser() logOnError(err, "initCache : caching user") log.Println("Caching items ..") err = loadObjItem2() logOnError(err, "initCache : caching items") log.Println("Caching messages ..") err = loadObjMsg() logOnError(err, "initCache : caching msgs") log.Println("Caching jobs ..") err = loadObjJob() logOnError(err, "initCache : caching jobs") } func loadObjType() error { var obj []ObjType b, err := Asset("data/code_obj_type.json") logOnError(err, "loadObjType : load data/code_obj_type.json") if err != nil { return err } err = json.Unmarshal(b, &obj) logOnError(err, "loadObjType : Unmarshal") if err != nil { return err } cacheObjType = make(map[string]int64) for _, v := range obj { id, err := codeObjTypeId(v.IntlId) if err == nil { cacheObjType[v.IntlId] = id } else { err = insertObjType(v.IntlId, v.Name) logOnError(err, "loadObjType : insertObjType") if err == nil { id, err = codeObjTypeId(v.IntlId) if err == nil { cacheObjType[v.IntlId] = id } else { logOnError(err, "loadObjType : codeObjTypeId") } } } } return nil } func loadObjSubType() error { var obj []ObjSubType b, err := Asset("data/code_obj_sub_type.json") logOnError(err, "loadObjSubType : load data/code_obj_sub_type.json") if err != nil { return err } err = json.Unmarshal(b, &obj) logOnError(err, "loadObjSubType : Unmarshal") if err != nil { return err } cacheObjSubType = make(map[string]int64) for _, v := range obj { id, err := codeObjSubTypeId(v.IntlId) if err == nil { cacheObjSubType[v.IntlId] = id } else { err = insertObjSubType(v.IntlId, v.Name, v.ObjType) logOnError(err, "loadObjSubType : insertObjSubType") if err == nil { id, err = codeObjSubTypeId(v.IntlId) if err == nil { cacheObjSubType[v.IntlId] = id } else { logOnError(err, "loadObjSubType : codeObjSubTypeId") } } } } return nil } func codeObjTypeId(intlId string) (int64, error) { var objTypeId int64 stmt, err := db.Prepare(`SELECT c.id FROM code_obj_type c WHERE c.intl_id = ?`) if err != nil { return 0, err } defer stmt.Close() err = stmt.QueryRow(intlId).Scan(&objTypeId) if err != nil { return 0, err } return objTypeId, nil } func codeObjSubTypeId(intlId string) (int64, error) { var objSubTypeId int64 stmt, err := db.Prepare(`SELECT c.id FROM code_obj_sub_type c WHERE c.intl_id = ?`) if err != nil { return 0, err } defer stmt.Close() err = stmt.QueryRow(intlId).Scan(&objSubTypeId) if err != nil { return 0, err } return objSubTypeId, nil } func getObjTypeId(objId int64) (int64, error) { var objTypeId int64 stmt, err := db.Prepare(`SELECT o.obj_type_id FROM obj o WHERE o.id = ?`) if err != nil { return 0, err } defer stmt.Close() err = stmt.QueryRow(objId).Scan(&objTypeId) if err != nil { return 0, err } return objTypeId, nil } func getObjSubTypeId(objId int64) (int64, error) { var objSubTypeId int64 stmt, err := db.Prepare(`SELECT o.obj_sub_type_id FROM obj o WHERE o.id = ?`) if err != nil { return 0, err } defer stmt.Close() err = stmt.QueryRow(objId).Scan(&objSubTypeId) if err != nil { return 0, err } return objSubTypeId, nil } func setObjSubTypeId(objId int64, objSubTypeID64 int64) error { stmt, err := db.Prepare(`UPDATE obj o SET o.obj_sub_type_id = ? WHERE o.id = ?;`) logOnError(err, "setObjSubTypeId : prepare update") if err != nil { return err } defer stmt.Close() _, err = stmt.Exec(objSubTypeID64, objId) logOnError(err, "setObjSubTypeId : exec update ("+strconv.FormatInt(objId, 10)+", "+strconv.FormatInt(objSubTypeID64, 10)+")") return err } func objAddName(objID64 int64, name string) error { stmt, err := db.Prepare(`INSERT INTO obj_name (obj_id, name, priority) SELECT ? obj_id, ? name, (SELECT MAX(priority) + 1 FROM obj_name WHERE obj_id = ?) priority FROM DUAL;`) _, err = stmt.Exec(objID64, name, objID64) return err } func addObjMsg(msgID64 int64, msgChatID64 int64, msgTGUserID64 int64, msgTGSenderUserID64 int64, msgDate time.Time, msgText string) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjMsg : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`msg`], 10) + `,` + strconv.FormatInt(cacheObjSubType[`msg`], 10) + `);`) if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjMsg : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjMsg : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_msg (obj_id, msg_id, chat_id, user_id, sender_user_id, date, text) VALUES (?, ?, ?, ?, ?, ?, ?);`) if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjMsg : rollback prepare insert obj_msg") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, msgID64, msgChatID64, msgTGUserID64, msgTGSenderUserID64, msgDate, msgText) if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjMsg : rollback exec insert obj_msg") return 0, err } err = tx.Commit() if err != nil { return 0, err } m := new(ChatWarsMessage) m.ObjID64 = objId m.TGUserID64 = msgTGUserID64 m.TGSenderUserID64 = msgTGSenderUserID64 m.Date = msgDate m.ID64 = msgID64 m.ChatID64 = msgChatID64 m.Text = msgText cacheObjMsg.Store(objId, *m) return objId, nil } func getObjMsg(objId int64) (*ChatWarsMessage, error) { if v, ok := cacheObjMsg.Load(objId); ok { m := v.(ChatWarsMessage) return &m, nil } var m *ChatWarsMessage stmt, err := db.Prepare(`SELECT om.msg_id, om.chat_id, om.user_id, om.sender_user_id, om.date, om.text FROM obj_msg om WHERE om.obj_id = ?`) if err != nil { return m, err } defer stmt.Close() m = new(ChatWarsMessage) err = stmt.QueryRow(objId).Scan(&m.ID64, &m.ChatID64, &m.TGUserID64, &m.TGSenderUserID64, &m.Date, &m.Text) if err != nil { return m, err } m.ObjID64 = objId cacheObjMsg.Store(objId, *m) return m, nil } func loadObjMsg() error { cacheObjMsg = new(sync.Map) return nil } func delObj(objId int64) error { objSubTypeId, err := getObjSubTypeId(objId) if err != nil { return err } if objSubTypeId != cacheObjSubType[`msg_auction_announce`] { return errors.New("Can only delete cacheObjSubType[`msg_auction_announce`].") } cacheObjMsg.Delete(objId) // better delete from cache before, worst case we reload after stmt, err := db.Prepare(`DELETE FROM obj WHERE id = ?`) if err != nil { return err } defer stmt.Close() res, err := stmt.Exec(objId) if err != nil { return err } count, err := res.RowsAffected() if err != nil { return err } if count > 1 { return errors.New("More than one row impacted.") } else if count == 0 { return errors.New("No row impacted.") } return nil } func addObjCastle(logo string, name string) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjCastle : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`castle`], 10) + `,` + strconv.FormatInt(cacheObjSubType[`castle`], 10) + `);`) logOnError(err, "addObjCastle : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjCastle : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjCastle : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_castle (obj_id, logo, name) VALUES (?, ?, ?);`) logOnError(err, "addObjCastle : prepare insert obj_castle") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjCastle : rollback prepare insert obj_castle") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, logo, name) logOnError(err, "addObjCastle : exec insert obj_castle") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjCastle : rollback exec insert obj_castle") return 0, err } err = tx.Commit() logOnError(err, "addObjCastle : commit") if err != nil { return 0, err } return objId, nil } func getObjCastleID(s string) int64 { if v, ok := cacheObjCastle.Load(s); ok { c := v.(ChatWarsCastle) return c.ObjID64 } else { v, _ := cacheObjCastle.Load(`⛔`) c := v.(ChatWarsCastle) return c.ObjID64 } } func loadObjCastle() error { var ( id int64 logo string name string ) cacheObjCastle = new(sync.Map) castles, err := db.Query(`SELECT oc.obj_id, oc.logo, oc.name FROM obj_castle oc;`) if err != nil { return err } defer castles.Close() for castles.Next() { err = castles.Scan(&id, &logo, &name) if err != nil { return err } c := new(ChatWarsCastle) c.ObjID64 = id c.Logo = logo c.Name = name cacheObjCastle.Store(logo, *c) cacheObjCastle.Store(name, *c) } return nil } func addObjGuild(tag string, name string) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjGuild : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`guild`], 10) + `,` + strconv.FormatInt(cacheObjSubType[`guild`], 10) + `);`) logOnError(err, "addObjGuild : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjGuild : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjGuild : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_guild (obj_id, tag, name, chat_id, deposit_chat_id) VALUES (?, ?, ?, NULL, NULL);`) logOnError(err, "addObjGuild : prepare insert obj_guild") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjGuild : rollback prepare insert obj_guild") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, tag, name) logOnError(err, "addObjGuild : exec insert obj_guild") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjGuild : rollback exec insert obj_guild") return 0, err } err = tx.Commit() logOnError(err, "addObjGuild : commit") if err != nil { return 0, err } return objId, nil } func getObjGuildID(s string) int64 { if v, ok := cacheObjGuild.Load(s); ok { g := v.(ChatWarsGuild) return g.ObjID64 } else { objID64, err := addObjGuild(s, ``) logOnError(err, "getObjGuildID") g := new(ChatWarsGuild) g.ObjID64 = objID64 g.Tag = s g.Name = `` cacheObjGuild.Store(s, *g) return objID64 } } func loadObjGuild() error { var ( id int64 tag string name string ) cacheObjGuild = new(sync.Map) guilds, err := db.Query(`SELECT og.obj_id, og.tag, og.name FROM obj_guild og;`) if err != nil { return err } defer guilds.Close() for guilds.Next() { err = guilds.Scan(&id, &tag, &name) if err != nil { return err } g := new(ChatWarsGuild) g.ObjID64 = id g.Tag = tag g.Name = name cacheObjGuild.Store(tag, *g) } return nil } func addObjUser(name string) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjUser : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`user`], 10) + `,` + strconv.FormatInt(cacheObjSubType[`user`], 10) + `);`) logOnError(err, "addObjUser : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjUser : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjUser : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_user (obj_id, name) VALUES (?, ?);`) logOnError(err, "addObjUser : prepare insert obj_user") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjUser : rollback prepare insert obj_user") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, name) logOnError(err, "addObjUser : exec insert obj_user") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjUser : rollback exec insert obj_user") return 0, err } err = tx.Commit() logOnError(err, "addObjUser : commit") if err != nil { return 0, err } return objId, nil } func getObjUserID(s string) int64 { if v, ok := cacheObjUser.Load(s); ok { u := v.(ChatWarsUser) return u.ObjID64 } else { objID64, err := addObjUser(s) logOnError(err, "getObjUserID") u := new(ChatWarsUser) u.ObjID64 = objID64 u.Name = s cacheObjUser.Store(s, *u) return objID64 } } func loadObjUser() error { var ( id int64 name string ) cacheObjUser = new(sync.Map) users, err := db.Query(`SELECT ou.obj_id, ou.name FROM obj_user ou;`) if err != nil { return err } defer users.Close() for users.Next() { err = users.Scan(&id, &name) if err != nil { return err } u := new(ChatWarsUser) u.ObjID64 = id u.Name = name cacheObjUser.Store(name, *u) } return nil } func getObjMsgDate(objID64 int64) (time.Time, error) { m, err := getObjMsg(objID64) if err != nil { return time.Now(), err } else { return m.Date, nil } } func addObjXP(userID64 int64, expNow int64, expLvl int64, level int64, date time.Time) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjXP : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`xp`], 10) + `,` + strconv.FormatInt(cacheObjSubType[`xp`], 10) + `);`) logOnError(err, "addObjXP : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjXP : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjXP : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_xp (obj_id, user_id, val, target, level, date) VALUES (?, ?, ?, ?, ?, ?);`) logOnError(err, "addObjXP : prepare insert obj_xp") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjXP : rollback prepare insert obj_xp") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, userID64, expNow, expLvl, level, date) logOnError(err, "addObjXP : exec insert obj_xp") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjXP : rollback exec insert obj_xp") return 0, err } err = tx.Commit() logOnError(err, "addObjXP : commit") if err != nil { return 0, err } return objId, nil } func addObjQuest(userID64 int64, questTypeID64 int64, duration time.Duration, date time.Time) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjQuest : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`quest`], 10) + `,` + strconv.FormatInt(questTypeID64, 10) + `);`) logOnError(err, "addObjQuest : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjQuest : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjQuest : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_quest (obj_id, user_id, duration, date, exp, gold) VALUES (?, ?, ?, ?, 0, 0);`) logOnError(err, "addObjQuest : prepare insert obj_quest") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjQuest : rollback prepare insert obj_quest") return 0, err } defer stmt.Close() _, err = stmt.Exec(objId, userID64, duration, date) logOnError(err, "addObjQuest : exec insert obj_quest") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjQuest : rollback exec insert obj_quest") return 0, err } err = tx.Commit() logOnError(err, "addObjQuest : commit") if err != nil { return 0, err } return objId, nil } func addObjItem(code string, name string, itemTypeID64 int64, weight int64, exchange string, auction bool) (int64, error) { tx, err := db.Begin() logOnError(err, "addObjItem : start transaction") if err != nil { return 0, err } res, err := tx.Exec(`INSERT INTO obj (obj_type_id, obj_sub_type_id) VALUES (` + strconv.FormatInt(cacheObjType[`item`], 10) + `,` + fmt.Sprintf("%d", itemTypeID64) + `);`) logOnError(err, "addObjItem : exec insert obj") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjItem : rollback insert obj") return 0, err } objId, err := res.LastInsertId() if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjItem : rollback get lastInsertId") return 0, err } stmt, err := tx.Prepare(`INSERT INTO obj_item (obj_id, intl_id, weight, exchange, auction) VALUES (?, ?, ?, ?, ?);`) logOnError(err, "addObjItem : prepare insert obj_item") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjItem : rollback prepare insert obj_item") return 0, err } defer stmt.Close() var e, a int if exchange != `` { e = 1 } else { e = 0 } if auction { a = 1 } else { a = 0 } _, err = stmt.Exec(objId, code, weight, e, a) logOnError(err, "addObjItem : exec insert obj_item") if err != nil { err2 := tx.Rollback() logOnError(err2, "addObjItem : rollback exec insert obj_item") return 0, err } err = tx.Commit() logOnError(err, "addObjItem : commit") if err != nil { return 0, err } err = objAddName(objId, name) logOnError(err, "addObjItem : add name") return objId, nil } func getObjItemID(c string, n string) int64 { i := getSilentObjItemID(c, n) if i == 0 { w := TGCommand{ Type: commandSendMsg, Text: fmt.Sprintf("Object unknown : %s - %s\n", c, n), ToUserID64: cfg.Bot.Admin, } TGCmdQueue <- w } return i } func getObjItem(objItemID64 int64) (*ChatWarsItem, error) { muxObjItemId.Lock() defer muxObjItemId.Unlock() muxObjItem.Lock() defer muxObjItem.Unlock() if obj, ok := cacheObjItemId[objItemID64]; ok { //log.Printf("Matching item name %s with %s.\n", name, obj.Name) return &obj, nil } else { return nil, errors.New("Item not found.") } } func getSilentObjItemID(code string, name string) int64 { muxObjItem.Lock() defer muxObjItem.Unlock() if len(code) > 0 { if obj, ok := cacheObjItem[code]; ok { //log.Printf("Matching item code %s with %s.\n", code, obj.Code) return obj.ObjID64 } if ok, _ := regexp.MatchString(`^(a|w)[0-9]+[a-e]$`, code); ok { // log.Printf("Matching quality item code %s with %s.\n", code, code[:len(code)-1]) if obj, ok := cacheObjItem[code[:len(code)-1]]; ok { return obj.ObjID64 } } if ok, _ := regexp.MatchString(`^u[0-9]+`, code); !ok { return 0 } } if len(name) == 0 { return 0 } if obj, ok := cacheObjItem[name]; ok { //log.Printf("Matching item name %s with %s.\n", name, obj.Name) return obj.ObjID64 } if ok, _ := regexp.MatchString(`^((u|e)[0-9]+|(a|w)[0-9]+[a-e]{0,1})$`, code); ok || len(code) == 0 { r := regexp.MustCompile(`^((?P⚡\+[0-9]+) ){0,1}(?P.+?)( \+(?P[0-9]+)⚔){0,1}( \+(?P[0-9]+)🛡){0,1}( \+(?P[0-9]+)💧){0,1}$`) basename := r.ReplaceAllString(name, "${BaseName}") if obj, ok := cacheObjItem[basename]; ok && len(basename) > 0 { //log.Printf("Matching item full basename %s with %s.\n", basename, obj.Name) return obj.ObjID64 } i := ChatWarsItem{ ObjID64: 0, } for _, obj := range cacheObjItem { if ok, _ := regexp.MatchString(`^(a|e|w)[0-9]+$`, obj.Code); ok { //only gear can be custom named m := fmt.Sprintf("^((%s.*)|(.*%s))$", regexp.QuoteMeta(obj.Names[0]), regexp.QuoteMeta(obj.Names[0])) if ok, _ := regexp.MatchString(m, basename); ok { //log.Printf("LOOP : Matching item modified basename %s with %s (%d).\n", basename, item.Name, item.ObjID64) i = obj break } } } if i.ObjID64 != 0 { //log.Printf("RETURN : Matching item modified basename %s with %s (%d).\n", basename, item.Name, item.ObjID64) return i.ObjID64 } else { /* fmt.Printf("silentGetObjItemID : Modifier : `%s`\n", r.ReplaceAllString(name, "${Modifier}")) fmt.Printf("silentGetObjItemID : BaseName : `%s`\n", r.ReplaceAllString(name, "${BaseName}")) fmt.Printf("silentGetObjItemID : Atk : `%s`\n", r.ReplaceAllString(name, "${Atk}")) fmt.Printf("silentGetObjItemID : Def : `%s`\n", r.ReplaceAllString(name, "${Def}")) fmt.Printf("silentGetObjItemID : Mana : `%s`\n", r.ReplaceAllString(name, "${Mana}")) */ } } return 0 } func loadObjItem2() error { var ( id int64 type_id int64 intl_id string name string weight int64 items []ChatWarsItem ) muxObjItem.Lock() defer muxObjItem.Unlock() cacheObjItem = make(map[string]ChatWarsItem) muxObjItemId.Lock() defer muxObjItemId.Unlock() cacheObjItemId = make(map[int64]ChatWarsItem) b, err := Asset("data/obj_item.json") logOnError(err, "loadObjItem2 : load data/obj_item.json") if err != nil { return err } err = json.Unmarshal(b, &items) for _, i := range items { if len(i.Names) == 0 { log.Printf("loadObjItems2 : %s : name missing.\n", i.Code) } else { if obj, ok := cacheObjItem[i.Code]; ok { log.Printf("loadObjItem2 : %s : duplicate code found. Belong to %s\n", i.Code, n, obj.Code) } else { i2 := ChatWarsItem{ Auction: i.Auction, Code: i.Code, Exchange: i.Exchange, ItemTypeID: i.ItemTypeID, Weight: i.Weight, Craft: ChatWarsItemCraft{}, Names: make([]string, 1), } for _, n := range i.Names { if obj, ok := cacheObjItem[n]; ok { log.Printf("loadObjItem2 : %s - %s : duplicate name found. Belongs to %s\n", i2.Code, n, obj.Code) } else { i2.Names = append(i2.Names, n) } } cacheObjItem[i.Code] = i2 for _, n := range i.Names { cacheObjItem[n] = i2 } } } } objs, err := db.Query(`SELECT oi.obj_id, o.obj_sub_type_id, oi.intl_id, oi.weight FROM obj o, obj_item oi WHERE o.id = oi.obj_id;`) if err != nil { logOnError("loadObjItem2 : querying items") return err } defer objs.Close() for objs.Next() { err = objs.Scan(&id, &type_id, &intl_id, &weight) if err != nil { logOnError("loadObjItem2 : scanning items") return err } if obj, ok := cacheObjItem[intl_id]; !ok { log.Printf("loadObjItem2 : %s : orphaned item in database (id : %d)\n", intl_id, id) } else { obj.ObjID64 = id cacheObjItem[intl_id] = obj for _, n := range obj.Names { cacheObjItem[n] = obj } if weight != obj.Weight { log.Printf("loadObjItem2 : %s : weight changed : %d => %d\n", weight, obj.Weight) } cacheObjItemID[id] = obj } } names, err := db.Query(`SELECT oi.obj_id, obn.name FROM obj_item oi, obj_name obn WHERE oi.obj_id = obn.obj_id;`) if err != nil { logOnError("loadObjItem2 : querying names") return err } defer names.Close() for names.Next() { err = names.Scan(&id, &name) if err != nil { logOnError("loadObjItem2 : scanning names") return err } if obj, ok := cacheObjItem[name]; !ok { if obj2, ok := cacheObjItemId[id]; ok { log.Printf("loadObjItem2 : %s : orphaned name in database for item %s\n", name, obj2.Code) } } } for _, i := range cacheObjItem { if i.ObjID64 == 0 { id, err := addObjItem(i.Code, i.Names[0], i.ItemTypeID, i.Weight, i.Exchange, i.Auction) i.ObjID64 = id cacheObjItemID[id] = obj count := 0 for _, n := range i.Names { if count == 0 { cacheObjItemID[n] = obj continue } else { objAddName(id, n) cacheObjItem[n] = obj } } } } log.Printf("%d items loaded.\n", len(items)) for _, v := range cacheObjItemId { log.Printf("Item cached : %d\n", v.ObjID64) for _, n := range v.Names { log.Printf("cacheObjItemId[%d] : %s : %s.\n", v.ObjID64, v.Names[0], n) } } return nil } func loadObjItem() error { var ( id int64 type_id int64 intl_id string name string weight int64 ) muxObjItem.Lock() cacheObjItem = make(map[string]ChatWarsItem) muxObjItem.Unlock() muxObjItemId.Lock() cacheObjItemId = make(map[int64]ChatWarsItem) muxObjItemId.Unlock() items, err := db.Query(`SELECT oi.obj_id, o.obj_sub_type_id, oi.intl_id, obn.name, oi.weight FROM obj o, obj_item oi, obj_name obn WHERE o.id = oi.obj_id AND obn.obj_id = oi.obj_id AND obn.priority = 0;`) if err != nil { return err } defer items.Close() for items.Next() { err = items.Scan(&id, &type_id, &intl_id, &name, &weight) if err != nil { return err } c := new(ChatWarsItem) c.ObjID64 = id c.ItemTypeID = type_id c.Code = intl_id n := make([]string, 1) n = append(n, name) c.Names = n c.Weight = weight muxObjItem.Lock() cacheObjItem[intl_id] = *c cacheObjItem[name] = *c muxObjItem.Unlock() muxObjItemId.Lock() cacheObjItemId[id] = *c muxObjItemId.Unlock() } items2, err := db.Query(`SELECT oi.obj_id, oi.intl_id, obn.name, oi.weight FROM obj_item oi, obj_name obn WHERE obn.obj_id = oi.obj_id AND obn.priority > 0;`) if err != nil { return err } defer items2.Close() for items2.Next() { err = items2.Scan(&id, &intl_id, &name, &weight) if err != nil { return err } if c, ok := cacheObjItem[intl_id]; ok { n := c.Names n = append(n, name) c.Names = n muxObjItem.Lock() cacheObjItem[intl_id] = c for _, n := range c.Names { cacheObjItem[n] = c } muxObjItem.Unlock() } else { log.Printf("loadObjItem : orphaned obj_name for `%s` : %s.\n", intl_id, name) } } return nil } func loadObjJob() error { var ( id int64 type_id int64 trigger int64 timeout time.Time user int64 zpayload []byte ) muxObjJob.Lock() cacheObjJob = make(map[int64]Job) muxObjJob.Unlock() jobs, err := db.Query(`SELECT o.id, o.obj_sub_type_id, oj.trigger_id, oj.timeout, oj.user_id, oj.payload FROM obj o, obj_job oj WHERE o.id = oj.obj_id;;`) if err != nil { return err } defer jobs.Close() for jobs.Next() { err = jobs.Scan(&id, &type_id, &trigger, &timeout, &user, &zpayload) if err != nil { return err } j := new(Job) j.ID64 = id j.JobTypeID64 = type_id j.Trigger = trigger j.Timeout = timeout j.UserID64 = user zb := bytes.NewReader(zpayload) zr, err := zlib.NewReader(zb) if err != nil { logOnError(err, "loadObjJob : zlib.NewReader") continue } b := new(bytes.Buffer) b.ReadFrom(zr) payload := b.Bytes() j.Payload = payload muxObjJob.Lock() cacheObjJob[id] = *j muxObjJob.Unlock() } return nil }