package main import ( "regexp" "sync" "time" "github.com/streadway/amqp" tb "gopkg.in/tucnak/telebot.v2" ) const maxUnixTimestamp int64 = 2147483647 const chtwrsbotID64 int64 = 408101137 type DataBackup struct { Messages []ChatWarsMessage `json:"messages"` } type MQClient struct { User string Password string Host string Path string SSL bool Connection *amqp.Connection Channel *amqp.Channel Queue amqp.Queue } type ChirpClient struct { HeartBeat time.Time `json:"heart_beat"` Login string `json:"nickname"` Active bool TGUserID64 int64 `json:"tg_user_id"` MQ MQClient `json:"mq_client"` CWUserID64 int64 `json:"user_id"` CWGuildID64 int64 `json:"guild_id"` CWRole string `json:"role"` CWState string `json:"state"` CWBusyUntil time.Time `json:"busy_until"` CWLastUpdate time.Time `json:"last_update"` Mux sync.Mutex } type MQKeepAlive struct { TGUserID64 int64 `json:"tg_user_id"` Nickname string `json:"nick"` Queue string `json:"queue"` Date time.Time `json:"date"` } type TGCommand struct { Type int64 `json:"type"` FromChatID64 int64 `json:"from_chat_id"` FromUserID64 int64 `json:"from_user_id"` FromMsgID64 int64 `json:"from_msg_id"` ToChatID64 int64 `json:"to_chat_id"` ToUserID64 int64 `json:"to_user_id"` Text string `json:"text"` Document tb.Document `json:"document"` ParseMode int64 `json:"parse_mode"` Delay time.Duration `json:"delay"` } type ChatWarsCastle struct { ObjID64 int64 `json:"obj_id"` Logo string `json:"logo"` Name string `json:"name"` } type ChatWarsGuild struct { ObjID64 int64 `json:"obj_id"` Tag string `json:"tag"` Name string `json:"name"` } type ChatWarsUser struct { ObjID64 int64 `json:"obj_id"` Name string `json:"name"` } type ChatWarsItem struct { ObjID64 int64 `json:"obj_id"` ItemTypeID int64 `json:"item_type_id"` Code string `json:"code"` Name string `json:"name"` Weight int `json:"weight"` Exchange bool `json:"exchange"` Auction bool `json:"auction"` } type ChatWarsItems struct { ItemID64 int64 `json:"item_id"` Quantity int64 `json:"quantity"` } type ChatWarsMessage struct { ObjID64 int64 `json:"obj_id"` TGUserID64 int64 `json:"tg_user_id"` TGSenderUserID64 int64 `json:"tg_sender_user_id"` Date time.Time `json:"date"` ID64 int64 `json:"id"` ChatID64 int64 `json:"chat_id"` Text string `json:"text"` IsForwarded bool `json:"is_forwarded"` } type ChatWarsExchangeDeal struct { ItemID64 int64 `json:"item_id"` Quantity int64 `json:"quantity"` Price int64 `json:"price"` Status string `json:"status"` Link string `json:"link"` } type ChatWarsMessageExchangeAck struct { Msg *ChatWarsMessage `json:"msg"` ActiveDeals int64 `json:"active_deals"` MaxDeals int64 `json:"max_deals"` DealList []ChatWarsExchangeDeal `json:"deals"` } type ChatWarsMessageGStock struct { Msg *ChatWarsMessage `json:"msg"` OwnerID64 int64 `json:"owner_id"` ItemList []ChatWarsItems `json:"item_list"` } type ChatWarsMessageWithdrawRcv struct { Msg *ChatWarsMessage `json:"msg"` ItemList []ChatWarsItems `json:"item_list"` } type ChatWarsMessageGDepositReq struct { Msg *ChatWarsMessage `json:"msg"` ItemID64 int64 `json:"item_id"` Quantity int64 `json:"quantity"` } type ChatWarsMessageGDepositAck struct { Msg *ChatWarsMessage `json:"msg"` ItemID64 int64 `json:"item_id"` Quantity int64 `json:"quantity"` } type ChatWarsMessageReportAck struct { ObjID64 int64 `json:"obj_id"` } type ChatWarsMessageStockAck struct { Msg *ChatWarsMessage `json:"msg"` Used int64 `json:"used"` Available int64 `json:"available"` Stock []ChatWarsItems `json:"stock"` } type ChatWarsMessageStockAnyAck struct { Msg *ChatWarsMessage `json:"msg"` Stock []ChatWarsItems `json:"stock"` } type ChatWarsMessageOrderbookAck struct { Msg *ChatWarsMessage `json:"msg"` Name string `json:"name"` Code string `json:"code"` Qty1 int64 `json:"qty1"` Price1 int64 `json:"price1"` Qty2 int64 `json:"qty2"` Price2 int64 `json:"price2"` Qty3 int64 `json:"qty3"` Price3 int64 `json:"price3"` Qty int64 `json:"qty"` Gold int64 `json:"gold"` } type ChatWarsMessageMeAck struct { Msg *ChatWarsMessage `json:"msg"` CWUserID64 int64 `json:"user_id"` CWGuildID64 int64 `json:"guild_id"` State string `json:"state"` Level int64 `json:"level"` ExpNow int64 `json:"exp_now"` ExpLvl int64 `json:"exp_lvl"` } type ChatWarsMessageGRolesAck struct { Msg *ChatWarsMessage `json:"msg"` BartenderID64 int64 `json:"bartender"` CommanderID64 int64 `json:"commander"` SquireID64 int64 `json:"squire"` TreasurerID64 int64 `json:"treasurer"` } type ChatWarsMessageGoQuestAck struct { Msg *ChatWarsMessage `json:"msg"` QuestTypeID int `json:"quest"` Duration time.Duration `json:"duration"` } type ChatWarsMessageQuestResult struct { Msg *ChatWarsMessage `json:"msg"` Gold int64 `json:"gold"` Exp int64 `json:"exp"` Loot []ChatWarsItems `json:"loot"` RegenStamina bool `json:"regen_stamina"` LostTorch bool `json:"lost_torch"` } type ChatWarsMessageQuestResultAmbush struct { Msg *ChatWarsMessage `json:"msg"` Loot []ChatWarsItems `json:"loot"` Level int64 `json:"level"` Armored bool `json:"armored"` Enraged bool `json:"enraged"` SpearResists bool `json:"spear resists"` Toughness bool `json:"toughness"` PoisonBottles bool `json:"poison_bottles"` } type ChatWarsMessageDuelFight struct { ObjID64 int64 `json:"obj_id"` WinCastle string `json:"win_castle"` WinGuild string `json:"win_guild"` WinUser string `json:"win_user"` WinLife int64 `json:"win_life"` LossCastle string `json:"loss_castle"` LossGuild string `json:"loss_guild"` LossUser string `json:"loss_user"` LossLife int64 `json:"loss_life"` Exp int64 `json:"exp"` Weapon string `json:"weapon"` } type ChatWarsMessageAuctionAnnounce struct { ObjID64 int64 `json:"obj_id"` LotID int32 `json:"lot_id"` ItemID64 int64 `json:"item_id"` Cond string `json:"cond"` Quality string `json:"quality"` SellerUserID64 int64 `json:"seller_id"` SellerGuildID64 int64 `json:"seller_guild_id"` SellerCastleID64 int64 `json:"seller_castle_id"` BuyerUserID64 int64 `json:"buyer_id"` BuyerGuildID64 int64 `json:"buyer_guild_id"` BuyerCastleID64 int64 `json:"buyer_castle_id"` Price int32 `json:"price"` Status string `json:"status"` End time.Time `json:"end"` } type ChatWarsMessagePillageInc struct { ObjID64 int64 `json:"obj_id"` Attacker string `json:"attacker"` Guild string `json:"guild"` Castle string `json:"castle"` } type ChatWarsMessageUnionWar struct { } type MessageParsingRule struct { ID int32 Priority int32 Description string Rule string MsgTypeID int64 ChatID64 int64 SenderUserID64 int64 re *regexp.Regexp } type BotMsg struct { To tb.Recipient Text string } type Job struct { ID64 int64 JobTypeID int32 Trigger int64 Timeout time.Time UserID64 int64 Payload []byte } type JobPayloadMsgRefresh struct { ObjID64 int64 `json:"obj_id"` } type JobPayloadPillage struct { ObjID64 int64 `json:"obj_id"` Date time.Time `json:"date"` } type JobPayloadTribute struct { } type JobPayloadStatus struct { } type JobPayloadGStock struct { MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` } type JobPayloadGWithdraw struct { MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` Request string `json:"request"` Status int `json:"status"` } type JobPayloadGDeposit struct { MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` ResObjID64 []int64 `json:"res_obj_id"` Status int `json:"status"` } type JobPayloadGDepositForward struct { ItemID64 int64 `json:"item_id"` Quantity int64 `json:"quantity"` } type JobPayloadSaveRes struct { MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` ResObjID64 int64 `json:"res_obj_id"` BuyRes bool `json:"buy_res"` } type JobPayloadRescanMsg struct { Query string `json:"query"` MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` } type JobPayloadSetDone struct { JobID64 int64 `json:"job_id"` MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` Text string `json:"test"` } type JobPayloadMsgClient struct { Text string `json:"msg"` MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` } type JobPayloadBackupExport struct { MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` } type JobPayloadBackupImport struct { URL string `json:"url"` MsgID64 int64 `json:"msg_id"` ChatID64 int64 `json:"chat_id"` } type JobPayloadVaultUserStatus struct { UserListID64 []int64 `json:"user_list"` ItemTypeListID64 []int64 `json:"item_type_list"` DepositChatID64 int64 `json:"deposit_chat_id"` UserID64 int64 `json:"user_id"` } type JobPayloadVaultItemStatus struct { ItemListID64 []int64 `json:"item_type_list"` DepositChatID64 int64 `json:"deposit_chat_id"` UserID64 int64 `json:"user_id"` } const ( userID64ChtWrsBot = 408101137 commandForwardMsg = 1 commandReplyMsg = 2 commandSendMsg = 3 commandDeleteMsg = 4 commandRefreshMsg = 5 commandSendDocument = 6 cmdParseModePlain = 1 cmdParseModeMarkDown = 2 cmdParseModeHTML = 3 objTypeUser = 1 objTypeGuild = 2 objTypeMessage = 3 objTypeWar = 4 objTypeWarReport = 5 objTypeJob = 6 objTypeItem = 7 objTypeCastle = 8 objTypeFair = 9 objTypeUnion = 10 objTypeTribute = 11 objTypeExperience = 12 objTypeQuest = 13 castleDeer = 1 castleDragon = 2 castleHighnest = 3 castleMoon = 4 castlePotato = 5 castleShark = 6 castleWolf = 7 objSubTypeUser = 101 objSubTypeGuild = 201 objSubTypeMessageUnknown = 301 objSubTypeMessageWar = 302 // from Chat Wars Reports (not done) objSubTypeMessageMiniWar = 303 // FIXME DELETE objSubTypeMessageGuildWar = 304 // from Chat Wars Reports (not done) objSubTypeMessageReportReq = 305 // /report (done) objSubTypeMessageReportAck = 306 // result from /report (done) objSubTypeMessageGReportReq = 307 // /g_report (done) objSubTypeMessageGReportAck = 308 // result from /g_report (not done) objSubTypeMessageQuestResult = 309 // result from going to quest (not done) objSubTypeMessageDuelFight = 310 // result from going to duel fight (done) objSubTypeMessageHeroReq = 311 // /hero (done) objSubTypeMessageHeroAck = 312 // result from /hero (not done) objSubTypeMessageMeReq = 313 // 🏅Me (done) objSubTypeMessageMeAck = 314 // result from 🏅Me (done) objSubTypeMessageInventoryReq = 315 // /inv (done) objSubTypeMessageInventoryAck = 316 // result from /inv (not done) objSubTypeMessagePillageInc = 317 // random incoming pillage (done) objSubTypeMessagePillageGo = 318 // ack from /go (done) objSubTypeMessagePillageTimeout = 319 // ack from lack of /go (done) objSubTypeMessagePillageWin = 320 // pillage successfully intercepted (done) objSubTypeMessagePillageLoss = 321 // pillage not intercepted (done) objSubTypeMessageTributeInc = 322 // request for a /pledge (not done) objSubTypeMessageTributeAck = 323 // pledge accepted (not done) objSubTypeMessageAuctionAnnounce = 324 // from Boris and Co, Ltd (done) objSubTypeMessageAuctionUpdReq = 325 // /l_123456 msg (not done) objSubTypeMessageAuctionUpdAck = 326 // result from /l_123456 (not done) objSubTypeMessageTimeAck = 327 // result from /time (done) objSubTypeMessageTimeReq = 328 // /time (done) objSubTypeMessageGo = 329 // /go (done) objSubTypeMessagePledge = 330 // /pledge (done) objSubTypeMessageGoQuestReq = 331 // 🌲Forest or 🍄Swamp or ⛰️Valley (not done) objSubTypeMessageGoFastFight = 332 // ▶️Fast fight (not done) objSubTypeMessageGoArena = 333 // 📯Arena (not done) objSubTypeMessageTop = 334 // any /topXX (not done) objSubTypeMessageMenu = 335 // main menu (not done) objSubTypeMessageBuyReq = 336 // /wtb_xx (done) objSubTypeMessageSellReq = 337 // /wts_xx (done) objSubTypeMessageOrderbookReq = 338 // /t_xx (done) objSubTypeMessageOrderbookAck = 339 // orderbook summary (not done) objSubTypeMessageWithdrawReq = 340 // /g_withdraw (done) objSubTypeMessageWithdrawCode = 341 // code to receive (done) objSubTypeMessageWithdrawRcv = 342 // Withdraw "received" msg (done) objSubTypeMessageStockReq = 343 // /stock (done) objSubTypeMessageStockAck = 344 // result from /stock (not done) objSubTypeMessageMiscReq = 345 // /misc (done) objSubTypeMessageMiscAck = 346 // result from /misc (not done) objSubTypeMessageUnionWar = 347 // from Chat Wars Reports (not done) objSubTypeMessageTUReportReq = 348 // /tu_report (not done) objSubTypeMessageTUReportAck = 349 // result from /tu_report (not done) objSubTypeMessageTimeout = 350 // generic timeout for action objSubTypeMessageGoQuestAck = 351 // confirm quest destination/busyness (done) objSubTypeMessageGRolesReq = 352 // /g_roles (done) objSubTypeMessageGRolesAck = 353 // result from /g_roles (done) objSubTypeMessageGStockResReq = 354 // /g_stock_res (done) objSubTypeMessageGStockAlchReq = 355 // /g_stock_alch (done) objSubTypeMessageGStockMiscReq = 356 // /g_stock_misc (done) objSubTypeMessageGStockRecReq = 357 // /g_stock_rec (done) objSubTypeMessageGStockPartReq = 358 // /g_stock_parts (done) objSubTypeMessageGStockOthReq = 359 // /g_stock_other (done) objSubTypeMessageGStockAnyAck = 360 // result from any /g_stock_xxx (done) objSubTypeMessageGStockReq = 361 // /g_stock (done) objSubTypeMessageGStockAck = 362 // result from /g_stock (done) objSubTypeMessageBusy = 363 // too busy now objSubTypeMessageResStockReq = 364 // 📦Resources or /stock (done) objSubTypeMessageAlchStockReq = 365 // ⚗️Alchemy (done) objSubTypeMessageMiscStockReq = 366 // 🗃Misc or /misc (done) objSubTypeMessageEquipStockReq = 367 // 🏷Equipment (done) objSubTypeMessageCraftStockReq = 368 // ⚒Crafting (done) objSubTypeMessageStockEmpty = 369 // [empty] (done) objSubTypeMessageStockAnyAck = 370 // list of stock (done) objSubTypeMessageGDepositReq = 371 // /g_deposit xx y (done) objSubTypeMessageGDepositAck = 372 // Deposited successfully: xx (y) (done) objSubTypeMessageAttackReq = 373 // Attack (done) objSubTypeMessageAttackAck = 374 // Read for attack, select target (done) objSubTypeMessageAttackTargetReq = 375 // Castle selection (done) objSubTypeMessageAttackTargetAck = 376 // Castle confirmation (done) objSubTypeMessageDefendReq = 377 // Defend (done) objSubTypeMessageDefendAck = 378 // Defend confirmation (done) objSubTypeMessageBack = 379 // Back (done) objSubTypeMessageCastleReq = 380 // Castle (done) objSubTypeMessageCastleAck = 381 // Castle msg (not done) objSubTypeMessageExchangeReq = 382 // ⚖Exchange (done) objSubTypeMessageExchangeAck = 383 // List of deals (done) objSubTypeMessageEquipGearReq = 384 // /on_item (done) objSubTypeMessageEquipGearAck = 385 // Item equipped (done) objSubTypeMessageUnequipGearReq = 386 // /off_item (done) objSubTypeMessageUnequipGearAck = 387 // Item unequipped (done) objSubTypeMessageNoStamina = 388 // Not enough stamina. (done) objSubTypeMessageOrderbookSearch = 389 // /t objSubTypeMessageQuestReq = 390 // quest objSubTypeMessageQuestAck = 391 // forest/swamp/valley/arena objSubTypeMessageBattle = 392 // wind is howling objSubTypeMessageOrderCancelReq = 393 // /rm_xxx objSubTypeMessageOrderCancelAck = 394 // Cancelling order objSubTypeMessageStaminaRestored = 395 // Stamina Restored objSubTypeMessageTopReq = 396 objSubTypeMessageQuestResultAmbush = 397 // result from going to quest with ambush (not done) objSubTypeJobPillage = 601 objSubTypeJobTribute = 602 objSubTypeJobStatus = 603 objSubTypeJobGWithdraw = 604 objSubTypeJobGStock = 605 objSubTypeJobRescanMsg = 606 objSubTypeJobSetJobDone = 607 objSubTypeJobMsgClient = 608 objSubTypeJobMsgRefresh = 609 objSubTypeJobBackupExport = 610 objSubTypeJobBackupImport = 611 objSubTypeJobGDeposit = 612 objSubTypeJobGDepositForward = 613 objSubTypeJobSaveRes = 614 objSubTypeJobVaultUserStatus = 615 objSubTypeJobVaultItemStatus = 616 objSubTypeItemResource = 701 objSubTypeItemAlch = 702 objSubTypeItemMisc = 703 objSubTypeItemRecipe = 704 objSubTypeItemPart = 705 objSubTypeItemOther = 706 objSubTypeItemUnique = 707 objSubTypeCastle = 801 objSubTypeFair = 901 objSubTypeUnion = 1001 objSubTypeTribute = 1101 objSubTypeExperience = 1201 objSubTypeQuestForest = 1301 objSubTypeQuestSwamp = 1302 objSubTypeQuestValley = 1303 objJobStatusCallBack = -1 objJobStatusNew = 0 objJobStatusPillageGo = 1 objJonStatusPending = 10 objJobStatusDone = 20 objJobPriority = 1 objJobPriorityRescanMsg = 2 objJobPriorityRescanAllMsg = 3 objJobPriorityBackup = 4 MQGetMsgWorkers = 12 MQCWMsgQueueSize = 100 SQLCWMsgWorkers = 6 SQLIdentifyMsgWorkers = 6 SQLMsgIdentifyQueueSize = 100 SQLMsgRescanJobSize = 25 JobWorkers = 12 JobQueueSize = 100 TGCmdWorkers = 3 TGCmdQueueSize = 100 MQTGCmdWorkers = 3 MQTGCmdQueueSize = 100 SQLJobSliceSize = 25 KeepAliveHeartBeatSeconds = 5 ) var ( chatWarsMonth = map[string]int{ "Wintar": 1, "Hornung": 2, "Lenzin": 3, "Ōstar": 4, "Winni": 5, "Brāh": 6, "Hewi": 7, "Aran": 8, "Witu": 9, "Wīndume": 10, "Herbist": 11, "Hailag": 12} chatWarsDaysSpecial = map[int]map[int]int{ 2: {1060: 29}, 4: {1060: 29}} chatWarsDays = map[int]int{ 1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31} )