package main import ( "encoding/json" "errors" "fmt" "io/ioutil" "log" "strings" "time" "github.com/jinzhu/copier" ) func loadClients() error { var clts []ChirpClient b, err := ioutil.ReadFile("./clients.json") logOnError(err, "loadClients : ReadFile(./clients.json)") if err != nil { return err } err = json.Unmarshal(b, &clts) logOnError(err, "loadClients : Unmarshal(./clients.json)") if err != nil { return err } muxClients.Lock() for _, c := range clts { cx := ChirpClient{} copier.Copy(&cx, &c) cx.Active = false if cx.Config.Wartime == `` { cx.Config.Wartime = `🛡Defend` } /* cx.MQ.Connection, err = amqp.Dial("amqp://" + cx.MQ.User + ":" + cx.MQ.Password + "@" + cx.MQ.Host + "/" + cx.MQ.Path) logOnError(err, "loadClients : Failed to connect to RabbitMQ") */ clients[cx.TGUserID64] = &cx log.Printf("loadClients[%s] : done\n", cx.Login) } muxClients.Unlock() return nil } func getLockedRoleClient(role string) (*ChirpClient, error) { muxClients.RLock() defer muxClients.RUnlock() ids := make([]int64, 0) for _, c := range clients { if c.CWRole == role { ids = append(ids, c.TGUserID64) fmt.Printf("getLockedRoleClient(%s) : appending %s (%d).\n", role, c.Login, c.TGUserID64) } } if len(ids) == 0 { return nil, errors.New("No client for the role.") } RndMux.Lock() id := RndSrc.Intn(len(ids)) RndMux.Unlock() clients[ids[id]].Mux.Lock() return clients[ids[id]], nil } func getLockedRandomClient() (*ChirpClient, error) { muxClients.RLock() ids := make([]int64, 0) for _, c := range clients { if c.Active { ids = append(ids, c.TGUserID64) } } muxClients.RUnlock() if len(ids) == 0 { return nil, errors.New("No active client.") } RndMux.Lock() id := RndSrc.Intn(len(ids)) RndMux.Unlock() clients[ids[id]].Mux.Lock() return clients[ids[id]], nil } func setClientBusy(userID64 int64, from time.Time, duration time.Duration) error { if clt, ok := getLockedClient(userID64, false); ok { if from.UTC().Add(duration).After(time.Now().UTC()) { clt.CWIdle = false clt.CWBusyUntil = from.UTC().Add(duration) log.Printf("setClientBusy[%s] : set for %s.\n", clt.Login, duration.String()) } else { log.Printf("setClientBusy[%s] : not updated.\n", clt.Login) } clt.Mux.Unlock() return nil } else { return errors.New("Client not found.") } } func setClientIdle(userID64 int64, from time.Time) error { if clt, ok := getLockedClient(userID64, false); ok { if from.UTC().After(clt.CWLastUpdate.UTC()) { clt.CWBusyUntil = from clt.CWIdle = true clt.CWLastUpdate = from } else { } clt.Mux.Unlock() return nil } else { return errors.New("Client not found.") } } func getLockedIdleClient() (*ChirpClient, error) { muxClients.RLock() ids := make([]int64, 0) for _, c := range clients { if c.CWIdle { ids = append(ids, c.TGUserID64) } } muxClients.RUnlock() if len(ids) == 0 { return nil, errors.New("No idle client.") } RndMux.Lock() id := RndSrc.Intn(len(ids)) RndMux.Unlock() clients[ids[id]].Mux.Lock() return clients[ids[id]], nil } func getLockedAllIdleClientID64() ([]int64, error) { muxClients.RLock() ids := make([]int64, 0) for _, c := range clients { if c.CWIdle { ids = append(ids, c.TGUserID64) clients[c.TGUserID64].Mux.Lock() } } muxClients.RUnlock() return ids, nil } func getAllIdleClientID64() ([]int64, error) { muxClients.RLock() ids := make([]int64, 0) for _, c := range clients { if c.CWIdle { ids = append(ids, c.TGUserID64) } } muxClients.RUnlock() return ids, nil } func getLockedClient(id int64, createMissing bool) (*ChirpClient, bool) { muxClients.RLock() if c, ok := clients[id]; ok { c.Mux.Lock() muxClients.RUnlock() return c, true } else if createMissing { c := ChirpClient{ TGUserID64: id, Active: false, Config: &ChirpConfig{ InterceptPillage: true, Wartime: `🛡Defend`, }, } c.Mux.Lock() muxClients.RUnlock() muxClients.Lock() clients[id] = &c muxClients.Unlock() return &c, true } else { muxClients.RUnlock() //c := new(ChirpClient) //return c, false return nil, false } } func clientDelTGMsg(userID64 int64, fromMsgID64 int64, fromChatID64 int64) { c := TGCommand{ Type: commandDeleteMsg, FromUserID64: userID64, FromMsgID64: fromMsgID64, FromChatID64: fromChatID64, } MQTGCmdQueue <- c } func clientFwdCWMsg(userID64 int64, fromMsgID64 int64, fromChatID64 int64, toChatID64 int64) { c := TGCommand{ Type: commandForwardMsg, FromUserID64: userID64, FromMsgID64: fromMsgID64, FromChatID64: fromChatID64, ToChatID64: toChatID64, } MQTGCmdQueue <- c } func clientSendTGMsgDelay(userID64 int64, chatID64 int64, s string, d time.Duration) { c := TGCommand{ Type: commandSendMsg, Text: s, FromUserID64: userID64, ToChatID64: chatID64, Delay: d, } MQTGCmdQueue <- c } func clientSendTGMsg(userID64 int64, chatID64 int64, s string) { clientSendTGMsgDelay(userID64, chatID64, s, 0) } func clientSendCWMsg(userID64 int64, s string) { clientSendCWMsgDelay(userID64, s, 0) } func clientSendCWMsgDelay(userID64 int64, s string, d time.Duration) { clientSendTGMsgDelay(userID64, userID64ChtWrsBot, s, d) } func clientRefreshCWMsg(userID64 int64, chatID64 int64, msgID64 int64) { log.Printf("clientRefreshCWMsg(%d, %d, %d)\n", userID64, chatID64, msgID64) c := TGCommand{ Type: commandRefreshMsg, FromUserID64: userID64, FromChatID64: chatID64, FromMsgID64: msgID64, Delay: 0, } MQTGCmdQueue <- c } func clientCallbackDelay(userID64 int64, msgID64 int64, chatID64 int64, name string, data []byte, d time.Duration) { c := TGCommand{ Type: commandCallback, FromUserID64: userID64, FromChatID64: chatID64, FromMsgID64: msgID64, Delay: d, CallbackName: name, CallbackData: data, } MQTGCmdQueue <- c } func clientCallback(userID64 int64, msgID64 int64, chatID64 int64, name string, data []byte) { clientCallbackDelay(userID64, msgID64, chatID64, name, data, 0) } func clientMsgMeAck(m *ChatWarsMessageMeAck) { if clt, ok := getLockedClient(m.Msg.TGUserID64, false); ok { if clt.Active { if clt.CWLastUpdate.Before(m.Msg.Date) { clt.CWGuildID64 = m.CWGuildID64 clt.CWUserID64 = m.CWUserID64 clt.CWState = m.State clt.CWClass = m.Class clt.CWLastUpdate = m.Msg.Date if getObjGuildID(``) != m.CWGuildID64 && strings.Compare(clt.CWRole, ``) == 0 { clientSendCWMsg(m.Msg.TGUserID64, "/g_roles") } if m.State == `🛌Rest` { clt.CWIdle = true } } } clt.Mux.Unlock() } } func clientMsgGListAck(msg *ChatWarsMessageGListAck) { muxClients.Lock() for _, clt := range clients { for _, m := range msg.Members { clt.Mux.Lock() if m.Name == clt.Nickname { if m.Class2 == `⚔️` { clt.CWClass2 = `Knight` } } clt.Mux.Unlock() } } muxClients.Unlock() } func clientMsgGoQuestAck(m *ChatWarsMessageGoQuestAck) { if clt, ok := getLockedClient(m.Msg.TGUserID64, false); ok { if clt.Active { if clt.CWLastUpdate.Before(m.Msg.Date) { clt.CWLastUpdate = m.Msg.Date clt.CWBusyUntil = m.Msg.Date.Add(m.Duration) } } clt.Mux.Unlock() } } func clientMsgGRolesAck(m *ChatWarsMessageGRolesAck) { if clt, ok := getLockedClient(m.Msg.TGUserID64, false); ok { if clt.Active { if clt.CWLastUpdate.Before(m.Msg.Date) { if m.CommanderID64 == clt.CWUserID64 { clt.CWRole = `commander` } else if m.BartenderID64 == clt.CWUserID64 { clt.CWRole = `bartender` } else if m.SquireID64 == clt.CWUserID64 { clt.CWRole = `squire` } else if m.TreasurerID64 == clt.CWUserID64 { clt.CWRole = `treasurer` } else { clt.CWRole = `none` } clt.CWLastUpdate = m.Msg.Date } } clt.Mux.Unlock() } } func clientGetCWUserID64(tgUserID64 int64) (int64, error) { if clt, ok := getLockedClient(tgUserID64, false); ok { i := clt.CWUserID64 clt.Mux.Unlock() return i, nil } return 0, errors.New("Unknown user_id.") } func clientSpreadQuestResultAmbush(cwm *ChatWarsMessageQuestResultAmbush) error { /* muxClients.RLock() var ret string for id, c := range clients { if c.Active { ret = fmt.Sprintf("%s%s | UserID : %d | TelegramID : %d (online)\n", ret, c.Login, c.CWUserID64, id) } else { ret = fmt.Sprintf("%s%s | UserID : %d | TelegramID : %d (offline)\n", ret, c.Login, c.CWUserID64, id) } } muxClients.RUnlock() */ log.Printf("clientSpreadQuestResultAmbush : spreading.") return nil }