def run(self): while not self._stopEvent.is_set(): try: # get new chat newChat = self._messageQueue.get(True, 3600) target = self._getTarget(newChat) # check if thread is alive... threadExists = (target in self._chatThreads and self._chatThreads[target].is_alive()) if threadExists: try: # add new chat to thread self._chatThreads[target].messageQueue.put( (target, newChat)) except ReferenceError: self._log.warning("dispatch failed; thread closed...") threadExists = False if not threadExists: self._log.debug( "Opening new thread for target {}.".format(target)) self._chatThreads[target] = self._startNewThread( target, newChat) except Queue.Empty: pass except Exception: self._log.exception("Error in MessageDispatcher") r = SendChatRequest(self._session, "Error sending chat/PM, see error log") tryRequest(r, nothrow=True) finally: self._messageQueue.task_done() self._removeDeadThreads()
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._skillMaxHealPoints idealNumUses = hint/float(maxPotential) possibleNumUses = status['mp']/float(self._mpCost) n = max(1, int(math.floor(min(idealNumUses, possibleNumUses)))) r1 = UseSkillRequest(self.parent.session, str(self.id), numTimes=n) try: tryRequest(r1, numTries=1) # update "best seen value" if n == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._skillMaxHealPoints = max(self._skillMaxHealPoints, newVal - currentVal) self.parent.log("New estimate for {}: heals {} {}" .format(self, self._skillMaxHealPoints, args['type'])) except kol.Error.Error as e: self.parent.log("Error using {}: {}".format(self, e[0]))
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._restMaxHealPoints n = int(max(1, math.floor(hint / maxPotential))) r1 = CampgroundRestRequest(self.parent.session) try: self.parent.log("Resting {} times...".format(n)) for _ in range(n): tryRequest(r1, numTries=1) # update "best seen value" if n == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._restMaxHealPoints = max(self._restMaxHealPoints, newVal - currentVal) self.parent.log("New estimate for {}: heals {} {}".format( self, self._restMaxHealPoints, args['type'])) except kol.Error.Error: self.parent.log("Failed to rest")
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._skillMaxHealPoints idealNumUses = hint / float(maxPotential) possibleNumUses = status['mp'] / float(self._mpCost) n = max(1, int(math.floor(min(idealNumUses, possibleNumUses)))) r1 = UseSkillRequest(self.parent.session, str(self.id), numTimes=n) try: tryRequest(r1, numTries=1) # update "best seen value" if n == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._skillMaxHealPoints = max(self._skillMaxHealPoints, newVal - currentVal) self.parent.log("New estimate for {}: heals {} {}".format( self, self._skillMaxHealPoints, args['type'])) except kol.Error.Error as e: self.parent.log("Error using {}: {}".format(self, e[0]))
def run(self): running = True while running: target = None replyQueue = None try: # read new chats (target, newChat) = self._getFromQueue() if newChat is not None: self._lastTarget = target if target is not None else "MAIN" try: # check if we need to return the reply replyQueue = newChat.get("replyQueue", None) r = SendChatRequest(self._session, newChat["text"]) data = tryRequest(r, numTries=8, initialDelay=1, scaleFactor=1.25) self._log.debug("({})> {}".format( target, newChat["text"])) chats = [] tmpChats = data["chatMessages"] for chat in tmpChats: chats.append(chat) if replyQueue is not None: replyQueue.put(chats) except: self._log.exception("E({})> {}".format( target, newChat["text"])) if replyQueue is not None: replyQueue.put([]) raise Exception( "Target {} unreachable.".format(target)) finally: if replyQueue is not None: replyQueue.put([]) self.__messageQueue.task_done() else: # newChat is None (meaning this thread needs to stop) with self.__lock: # no longer accept new chats self._open = False except Exception: self._log.exception( "Error in MessageThread to target {}".format(target)) r = SendChatRequest( self._session, "Error sending chat/PM to {}, " "see error log".format(target)) tryRequest(r, nothrow=True, numTries=2, initialDelay=1) self._open = False # give up on enqueued messasges return sleep(self.throttleSeconds) with self.__lock: running = ((self._open or not self.__messageQueue.empty()) and self._session.isConnected) self._log.debug("Closed chat thread for target {}.".format( self._lastTarget))
def run(self): while not self._stopEvent.is_set(): try: # get new chat newChat = self._messageQueue.get(True, 3600) target = self._getTarget(newChat) # check if thread is alive... threadExists = (target in self._chatThreads and self._chatThreads[target].is_alive()) if threadExists: try: # add new chat to thread self._chatThreads[target].messageQueue.put( (target, newChat)) except ReferenceError: self._log.warning("dispatch failed; thread closed...") threadExists = False if not threadExists: self._log.debug("Opening new thread for target {}." .format(target)) self._chatThreads[target] = self._startNewThread(target, newChat) except Queue.Empty: pass except Exception: self._log.exception("Error in MessageDispatcher") r = SendChatRequest(self._session, "Error sending chat/PM, see error log") tryRequest(r, nothrow=True) finally: self._messageQueue.task_done() self._removeDeadThreads()
def run(self): running = True while running: target = None replyQueue = None try: # read new chats (target, newChat) = self._getFromQueue() if newChat is not None: self._lastTarget = target if target is not None else "MAIN" try: # check if we need to return the reply replyQueue = newChat.get("replyQueue", None) r = SendChatRequest(self._session, newChat["text"]) data = tryRequest(r, numTries=8, initialDelay=1, scaleFactor=1.25) self._log.debug("({})> {}" .format(target, newChat["text"])) chats = [] tmpChats = data["chatMessages"] for chat in tmpChats: chats.append(chat) if replyQueue is not None: replyQueue.put(chats) except: self._log.exception("E({})> {}" .format(target, newChat["text"])) if replyQueue is not None: replyQueue.put([]) raise Exception( "Target {} unreachable.".format(target)) finally: if replyQueue is not None: replyQueue.put([]) self.__messageQueue.task_done() else: # newChat is None (meaning this thread needs to stop) with self.__lock: # no longer accept new chats self._open = False except Exception: self._log.exception("Error in MessageThread to target {}" .format(target)) r = SendChatRequest(self._session, "Error sending chat/PM to {}, " "see error log".format(target)) tryRequest(r, nothrow=True, numTries=2, initialDelay=1) self._open = False # give up on enqueued messasges return sleep(self.throttleSeconds) with self.__lock: running = ((self._open or not self.__messageQueue.empty()) and self._session.isConnected) self._log.debug("Closed chat thread for target {}." .format(self._lastTarget))
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._restMaxHealPoints n = int(max(1, math.floor(hint/maxPotential))) r1 = CampgroundRestRequest(self.parent.session) try: self.parent.log("Resting {} times...".format(n)) for _ in range(n): tryRequest(r1, numTries=1) # update "best seen value" if n == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._restMaxHealPoints = max(self._restMaxHealPoints, newVal - currentVal) self.parent.log("New estimate for {}: heals {} {}" .format(self, self._restMaxHealPoints, args['type'])) except kol.Error.Error: self.parent.log("Failed to rest")
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._itemMaxHealPoints n = int(max(1, math.floor(hint/maxPotential))) with InventoryLock.lock: invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() qtyInInventory = inv.get(self.id, 0) if qtyInInventory == 0: if self.buyFrom is None: self.parent.log("Out of item {}".format(self.id)) return if qtyInInventory < n: if self.buyFrom is not None: if self.buyFrom.lower() == "mall": try: buyFromMall(self.parent.session, self.id, n-qtyInInventory, 0, self.parent.log) except kol.Error.Error: pass else: r1 = StoreRequest(self.parent.session, self.buyFrom, self.id, quantity=(n-qtyInInventory)) tryRequest(r1, nothrow=True, numTries=1) invMan.refreshInventory() inv = invMan.inventory() qtyInInventory = inv.get(self.id, 0) if qtyInInventory == 0: self.parent.log("Couldn't buy item {}".format(self.id)) return r2 = UseItemRequest(self.parent.session, self.id) try: toUse = min(n, qtyInInventory) for _ in range(toUse): tryRequest(r2, numTries=1) # update "best seen value" if toUse == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._itemMaxHealPoints = max(self._itemMaxHealPoints, newVal - currentVal) self.parent.log("New estimate for {}: heals {} {}" .format(self, self._itemMaxHealPoints, args['type'])) except kol.Error.Error: self.parent.log("Failed to use item {}".format(self.id))
def setMessagesPerPage(self, messagesPerPage): "Sets how many messages the user wants to receive per request." with self.__lock: if self.__messagesPerPage != messagesPerPage: r = GetMessagesRequest(self.session, messagesPerPage=messagesPerPage) tryRequest(r) self.__messagesPerPage = messagesPerPage
def setOldestFirst(self, oldestFirst): """Sets whether the user wants their messages sorted oldest first or newest first.""" with self.__lock: if self.__oldestFirst != oldestFirst: r = GetMessagesRequest(self.session, oldestFirst=oldestFirst) tryRequest(r) self.__oldestFirst = oldestFirst
def heal(self, hint, args, status): if args.get('__lucifer__', False): self.parent.log("Skipping Lucifer (no recursive Lucifer allowed)") return with InventoryLock.lock: invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() if inv.get(571, 0) == 0: qty = 0 if self.buyFromMall: try: qty = buyFromMall(self.parent.session, 571, logFunc=self.parent.log) except kol.Error.Error: pass if qty == 0: self.parent.log("Out of Lucifers.") return r1 = StatusRequest(self.parent.session) d1 = tryRequest(r1) if self.maxFull is not None and int(d1['full']) >= self.maxFull: self.parent.log("Reached reserve fullness.") return mpToHeal = status['maxmp'] - status['mp'] hpNeeded = min(1 + (mpToHeal / 9 + 1), status['maxhp']) self.parent.log("Lucifer: requires {} hp, have {} hp.".format( hpNeeded, status['hp'])) if hpNeeded > status['hp']: curHp = None self.parent.log("Healing for Lucifer...") if self.extHealer is None: reply = self.parent._heal({ 'type': 'hp', 'points': hpNeeded, '__lucifer__': True }) curHp = reply['hp'] else: replies = self.parent._raiseEvent( "heal", "__" + self.extHealer + "__", { 'type': 'hp', 'points': hpNeeded, '__lucifer__': True }) curHp = replies[-1]['hp'] if curHp < hpNeeded: self.parent.log("Failed to heal for Lucifer.") return self.parent.log("Healed for Lucifer!") r2 = EatFoodRequest(self.parent.session, 571) try: tryRequest(r2, numTries=1) except kol.Error.Error as e: self.parent.log("Lucifer error: {}".format(e[0]))
def heal(self, hint, args, status): currentVal = status[args['type']] n = 1 if self._seen > 10: self.parent.debugLog("Using estimate for multi-use") maxPotential = self._itemMaxHealPoints n = int(max(1, math.floor(hint / maxPotential))) with InventoryLock.lock: invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() qtyInInventory = inv.get(self.id, 0) if qtyInInventory == 0: if self.buyFrom is None: self.parent.log("Out of item {}".format(self.id)) return if qtyInInventory < n: if self.buyFrom is not None: if self.buyFrom.lower() == "mall": try: buyFromMall(self.parent.session, self.id, n - qtyInInventory, 0, self.parent.log) except kol.Error.Error: pass else: r1 = StoreRequest(self.parent.session, self.buyFrom, self.id, quantity=(n - qtyInInventory)) tryRequest(r1, nothrow=True, numTries=1) invMan.refreshInventory() inv = invMan.inventory() qtyInInventory = inv.get(self.id, 0) if qtyInInventory == 0: self.parent.log("Couldn't buy item {}".format(self.id)) return r2 = UseItemRequest(self.parent.session, self.id) try: toUse = min(n, qtyInInventory) for _ in range(toUse): tryRequest(r2, numTries=1) # update "best seen value" if toUse == 1: status = self.parent.hpMpStatus() newVal = status[args['type']] if (newVal != status['max' + args['type']] and newVal > currentVal): self._seen += 1 self._itemMaxHealPoints = max(self._itemMaxHealPoints, newVal - currentVal) self.parent.log( "New estimate for {}: heals {} {}".format( self, self._itemMaxHealPoints, args['type'])) except kol.Error.Error: self.parent.log("Failed to use item {}".format(self.id))
def _checkStock(self): with InventoryLock.lock: self._invMan.refreshInventory() inv = self._invMan.completeInventory() r = StatusRequest(self._s) d = tryRequest(r, numTries=6, initialDelay=3, scaleFactor=1.25) meat = int(d['meat']) itemsOwed = {} meatOwed = 0 con = self._db.getDbConnection() c = con.cursor() c.execute("SELECT * FROM {}".format(self._name)) msg = c.fetchone() while msg is not None: if msg['state'] in [self.OUTBOX_SENDING, self.OUTBOX_DEFERRED]: message = decode(msg['data']) itemsOwed = _itemsToDict(message.get('items', []), itemsOwed) meatOwed += message.get('meat', 0) msg = c.fetchone() difference = dict((iid, inv.get(iid, 0) - qty) for iid,qty in itemsOwed.items()) deficit = dict((iid, -diff) for iid,diff in difference.items() if diff < 0) if deficit: # get items in display case r2 = GetDisplayCaseRequest(self._s) d2 = tryRequest(r2) display = _itemsToDict(d2['items']) difference = dict( (iid, inv.get(iid, 0) + display.get(iid, 0) - qty) for iid,qty in itemsOwed.items()) deficit = dict((iid, -diff) for iid,diff in difference.items() if diff < 0) if deficit or meatOwed > meat: # notify admins of item deficit! warningText = ("Warning: {} has an item deficit of: \n" .format(self._props.userName)) for iid, d in deficit.items(): warningText += ("\n{}: {}" .format( d, getItemFromId(iid).get( 'name', "item ID {}".format(iid)))) if meatOwed > meat: warningText += "\n{} meat".format(meatOwed-meat) with con: c2 = con.cursor() for adminUid in self._props.getAdmins("mail_fail"): # notify admins of deficit newMsg = {'userId': adminUid, 'meat': 0, 'text': warningText, 'items': []} self._insertSplitKmail(c2, self.OUTBOX_SENDING, newMsg, reserveItems=False)
def _sendKmail(self, idCode, message, sendItemWarning=False): # append idCode to bottom: \n\n(mail-id: NUMBER) message['text'] += "\n\n" if sendItemWarning: if message.get('out_of_stock', False): message['text'] += _outOfStockText + "\n" else: message['text'] += _couldNotSendItemsText + "\n" message['text'] += "(mail-id: {})".format(idCode) # remove any unicode characters message['text'] = unidecode(message['text']) with InventoryLock.lock: self._invMan.refreshInventory() inv = self._invMan.completeInventory() items = _itemsToDict(message.get('items', [])) for iid,qty in items.items(): inInventory = inv.get(iid, 0) if inInventory < qty: self._log.info("Short on item {}; taking from DC..." .format(iid)) r = TakeItemsFromDisplayCaseRequest( self._s, [{'id': iid, 'quantity': qty - inInventory}]) tryRequest(r) self._invMan.refreshInventory() inv = self._invMan.completeInventory() # check for items in stock, and if they are sendable filteredItems = {} for iid,qty in items.items(): inInventory = inv.get(iid, 0) if inInventory < qty: message['out_of_stock'] = True if inInventory > 0: if iid not in self._clearedItems: r = ItemInformationRequest(self._s, iid) d = tryRequest(r)['item'] approved = d.get('canTransfer', False) self._clearedItems[iid] = approved self._log.debug("Item {} {} for kmail" .format(iid, "APPROVED" if approved else "REJECTED")) if self._clearedItems[iid]: filteredItems[iid] = qty else: self._log.info("Item {} rejected from kmail." .format(iid)) else: filteredItems[iid] = qty message['items'] = _itemsToList(filteredItems) r = SendMessageRequest(self._s, message) # we can't try this more than once! if there's some sort of # error, it will send multiple times. tryRequest(r, numTries=1)
def equipCustomOutfitByName(session, outfitName): r1 = CustomOutfitListRequest(session) d1 = tryRequest(r1) matches = [item['id'] for item in d1['outfits'] if item['name'].lower() == outfitName.lower()] if not matches: raise Error.Error("Invalid outfit name: {}".format(outfitName), Error.INVALID_ACTION) r2 = OutfitEquipRequest(session, matches[0], True) d2 = tryRequest(r2, numTries=1) return d2
def _online(self): now = time.time() if now - self._lastOnlineCheck <= 2: return True try: tryRequest(StatusRequest(self._s), nothrow=False, numTries=6, initialDelay=10, scaleFactor=1) self._lastOnlineCheck = now return True except (kol.Error.Error, urllib2.HTTPError): pass return False
def heal(self, hint, args, status): if args.get('__lucifer__', False): self.parent.log("Skipping Lucifer (no recursive Lucifer allowed)") return with InventoryLock.lock: invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() if inv.get(571, 0) == 0: qty = 0 if self.buyFromMall: try: qty = buyFromMall(self.parent.session, 571, logFunc=self.parent.log) except kol.Error.Error: pass if qty == 0: self.parent.log("Out of Lucifers.") return r1 = StatusRequest(self.parent.session) d1 = tryRequest(r1) if self.maxFull is not None and int(d1['full']) >= self.maxFull: self.parent.log("Reached reserve fullness.") return mpToHeal = status['maxmp'] - status['mp'] hpNeeded = min(1 + (mpToHeal/9 + 1), status['maxhp']) self.parent.log("Lucifer: requires {} hp, have {} hp." .format(hpNeeded, status['hp'])) if hpNeeded > status['hp']: curHp = None self.parent.log("Healing for Lucifer...") if self.extHealer is None: reply = self.parent._heal({'type': 'hp', 'points': hpNeeded, '__lucifer__': True}) curHp = reply['hp'] else: replies = self.parent._raiseEvent( "heal", "__" + self.extHealer + "__", {'type': 'hp', 'points': hpNeeded, '__lucifer__': True}) curHp = replies[-1]['hp'] if curHp < hpNeeded: self.parent.log("Failed to heal for Lucifer.") return self.parent.log("Healed for Lucifer!") r2 = EatFoodRequest(self.parent.session, 571) try: tryRequest(r2, numTries=1) except kol.Error.Error as e: self.parent.log("Lucifer error: {}".format(e[0]))
def equipCustomOutfitByName(session, outfitName): r1 = CustomOutfitListRequest(session) d1 = tryRequest(r1) matches = [ item['id'] for item in d1['outfits'] if item['name'].lower() == outfitName.lower() ] if not matches: raise Error.Error("Invalid outfit name: {}".format(outfitName), Error.INVALID_ACTION) r2 = OutfitEquipRequest(session, matches[0], True) d2 = tryRequest(r2, numTries=1) return d2
def _refreshClanMembers(self): n = len(self._clanMembers) self._log.debug("Updating clan member list...") r1 = ClanWhitelistRequest(self._s) d1 = tryRequest(r1) r2 = ClanDetailedMemberRequest(self._s) d2 = tryRequest(r2) whitelistLength = len(d1['members']) if whitelistLength == 0: self._log.warning("No members detected on whitelist.") else: self._log.debug("{} members on whitelist".format(whitelistLength)) memberLength = len(d2['members']) if memberLength == 0: self._log.warning("No members detected in clan.") else: self._log.debug("{} members in clan".format(memberLength)) with self._clanMemberLock: for record in d1['members']: uid = int(record['userId']) entry = { 'userId': uid, 'userName': record['userName'], 'rankName': record['rankName'], 'whitelist': True } self._clanMembers[uid] = entry for record in d2['members']: uid = int(record['userId']) entry = { 'userId': uid, 'userName': record['userName'], 'rankName': record['rankName'], 'inClan': True, 'karma': record['karma'] } self._clanMembers[uid].update(entry) for uid, record in self._clanMembers.items(): if 'karma' not in record: record['karma'] = 0 record['inClan'] = False if 'whitelist' not in record: record['whitelist'] = False self._lastClanMemberRefresh = time.time() n2 = len(self._clanMembers) self._log.info( "There are {} clan members (previous count: {})".format(n2, n)) self._raiseEvent("new_member_list", None)
def getNewChatMessages(self): "Gets a list of new chat messages and returns them." r = GetChatMessagesRequest(self.session, self.lastRequestTimestamp) data = tryRequest(r, True, 3, 0.5, 1.5) if data is None: return [] self.lastRequestTimestamp = data["lastSeen"] chats = data["chatMessages"] # Set the channel in each channel-less chat to be the current channel. for chat in chats: # fix a little entity bug in kol if "text" in chat: txt = chat["text"] txt = self._entityRegex.sub(r'&#\1;', txt) # convert to unicode (KoL/pykol has weird encoding) txtUnicode = u''.join(unichr(ord(c)) for c in txt) txtUnicode = self._parser.unescape(txtUnicode) if txtUnicode: if any(c in txtUnicode[0] for c in [u"\xbf", u"\xa1"]): txtUnicode = txtUnicode[1:] chat["text"] = unidecode(txtUnicode) t = chat["type"] if t == "normal" or t == "emote": if "channel" not in chat: chat["channel"] = self.currentChannel return chats
def __init__(self, parent, identity, iData, config): """ Initialize the BaseClanDungeonChannelManager """ self.__eventLock = threading.RLock() # lock for reading events # LOCK THIS BEFORE # LOCKING self._syncLock self.__initialized = False self.__lastEvents = None self._lastEventCheck = 0 self._logEntryDb = [] printDbLoad = False if self._csvFile is not None: self._logEntryDb = database.csvDatabase(self._csvFile) printDbLoad = True with self.__raidlogDownloadLock: if self.__initialRaidlog is None: rl = ClanRaidLogRequest(iData.session) result = tryRequest(rl, numTries=5, initialDelay=0.5, scaleFactor=2) self.__initialRaidlog = result self.__lastEvents = self.__initialRaidlog super(BaseClanDungeonChannelManager, self).__init__(parent, identity, iData, config) if printDbLoad: self._log.info("Loaded {} entries of data from {}." .format(len(self._logEntryDb), self._csvFile)) self.__initialized = True
def __init__(self, parent, identity, iData, config): """ Initialize the BaseClanDungeonChannelManager """ self.__eventLock = threading.RLock() # lock for reading events # LOCK THIS BEFORE # LOCKING self._syncLock self.__initialized = False self.__lastEvents = None self._lastEventCheck = 0 self._logEntryDb = [] printDbLoad = False if self._csvFile is not None: self._logEntryDb = database.csvDatabase(self._csvFile) printDbLoad = True with self.__raidlogDownloadLock: if self.__initialRaidlog is None: rl = ClanRaidLogRequest(iData.session) result = tryRequest(rl, numTries=5, initialDelay=0.5, scaleFactor=2) self.__initialRaidlog = result self.__lastEvents = self.__initialRaidlog super(BaseClanDungeonChannelManager, self).__init__(parent, identity, iData, config) if printDbLoad: self._log.info("Loaded {} entries of data from {}.".format( len(self._logEntryDb), self._csvFile)) self.__initialized = True
def _saveKmail(self, message, **kwargs): r = SaveMessagesRequest(self._s, [message['id']], **kwargs) try: result = tryRequest(r) self._log.info("Saved message {}".format(result)) except Exception: self._log.info("Could not save {}. Gave up.".format(message))
def _deleteKmail(self, message, **kwargs): r = DeleteMessagesRequest(self._s, [message['id']], **kwargs) try: result = tryRequest(r) self._log.info("Deleted message.".format(result)) except MessageError: pass
def refreshInventory(self): """ Refresh the inventory list. """ with self.__lock: self.__items = {} r = InventoryRequest(self.session) data = tryRequest(r) for item in data["items"]: self.__items[item["id"]] = item["quantity"]
def _refreshClanMembers(self): n = len(self._clanMembers) self._log.debug("Updating clan member list...") r1 = ClanWhitelistRequest(self._s) d1 = tryRequest(r1) r2 = ClanDetailedMemberRequest(self._s) d2 = tryRequest(r2) whitelistLength = len(d1['members']) if whitelistLength == 0: self._log.warning("No members detected on whitelist.") else: self._log.debug("{} members on whitelist".format(whitelistLength)) memberLength = len(d2['members']) if memberLength == 0: self._log.warning("No members detected in clan.") else: self._log.debug("{} members in clan".format(memberLength)) with self._clanMemberLock: for record in d1['members']: uid = int(record['userId']) entry = {'userId': uid, 'userName': record['userName'], 'rankName': record['rankName'], 'whitelist': True} self._clanMembers[uid] = entry for record in d2['members']: uid = int(record['userId']) entry = {'userId': uid, 'userName': record['userName'], 'rankName': record['rankName'], 'inClan': True, 'karma': record['karma']} self._clanMembers[uid].update(entry) for uid, record in self._clanMembers.items(): if 'karma' not in record: record['karma'] = 0 record['inClan'] = False if 'whitelist' not in record: record['whitelist'] = False self._lastClanMemberRefresh = time.time() n2 = len(self._clanMembers) self._log.info("There are {} clan members (previous count: {})" .format(n2, n)) self._raiseEvent("new_member_list", None)
def openAllGiftPackages(self): with self.__lock: Report.trace("kmail", "Opening gift package(s).") giftPackages = {} # Get a list of all gift packages in our inventory. r = InventoryRequest(self.session) responseData = tryRequest(r) items = responseData["items"] for item in items: if "type" in item and item["type"] == "gift package": giftPackages[item["id"]] = item["quantity"] # Open all of the gift packages. for itemId, quantity in giftPackages.iteritems(): for _i in range(quantity): r = UseItemRequest(self.session, itemId) tryRequest(r)
def openAllGiftPackages(self): with self.__lock: Report.trace("kmail", "Opening gift package(s).") giftPackages = {} # Get a list of all gift packages in our inventory. r = InventoryRequest(self.session) responseData = tryRequest(r) items = responseData["items"] for item in items: if "type" in item and item["type"] == "gift package": giftPackages[item["id"]] = item["quantity"] # Open all of the gift packages. for itemId,quantity in giftPackages.iteritems(): for _i in range(quantity): r = UseItemRequest(self.session, itemId) tryRequest(r)
def notifyAdmins(s, props, log, etype, value, tb): # kmail the administrators if props.debug: return if s is not None and s.isConnected: for uid in props.getAdmins('crash_notify'): errorText = ''.join(traceback.format_exception( etype, value, tb)) if len(errorText) > 1800: errorText = "..." + errorText[-1800:] alert1 = SendMessageRequest( s, {'userId': uid, 'text': "NOTICE: CWbot encountered an " "unknown error: {}".format(errorText)}) try: log.info("Sending notice to {}".format(uid)) tryRequest(alert1) except Exception: log.exception("Exception sending error notice.")
def __init__(self, session): """Initializes the ChatManager with a particular KoL session and then connects to chat.""" self.session = session session.chatManager = self self.lastRequestTimestamp = 0 r = OpenChatRequest(self.session) data = tryRequest(r) self.currentChannel = data["currentChannel"] self._dispatcher = MessageDispatcher(session) self._dispatcher.daemon = True self._dispatcher.start()
def _checkItems(self, message): items = _itemsToDict(message['items']) with InventoryLock.lock: self._invMan.refreshInventory() inv = self._invMan.inventory() r = GetDisplayCaseRequest(self._s) d = tryRequest(r) inv = _itemsToDict(d['items'], inv) for iid,qty in items.items(): if inv.get(iid, 0) < qty: raise MessageError("Not enough of item {} in inventory." .format(iid))
def notifyAdmins(s, props, log, etype, value, tb): # kmail the administrators if props.debug: return if s is not None and s.isConnected: for uid in props.getAdmins('crash_notify'): errorText = ''.join(traceback.format_exception(etype, value, tb)) if len(errorText) > 1800: errorText = "..." + errorText[-1800:] alert1 = SendMessageRequest( s, { 'userId': uid, 'text': "NOTICE: CWbot encountered an " "unknown error: {}".format(errorText) }) try: log.info("Sending notice to {}".format(uid)) tryRequest(alert1) except Exception: log.exception("Exception sending error notice.")
def canReceiveItems(self): now = time.time() if now - self._lastCanReceiveItemsCheck <= 3600: return self._lastCanReceiveItems self._lastCanReceiveItemsCheck = now r = StatusRequest(self._s) d = tryRequest(r, numTries=6, initialDelay=3, scaleFactor=1.25) canReceive = ((int(d.get('hardcore',"1")) == 0 and int(d.get('roninleft',"1")) == 0) or int(d.get('casual',"0")) == 1 or int(d.get('freedralph',"0")) == 1) self._lastCanReceiveItems = canReceive return canReceive
def getMessages(self, box="Inbox", pageNumber=None, messagesPerPage=None, oldestFirst=None, **kwargs): """ A wrapper to GetMessagesRequest. Ensures that the user never specifies both messagesPerPage and oldestFirst. Doing so can cause the request to be very slow. """ with self.__lock: if messagesPerPage != None: self.setMessagesPerPage(messagesPerPage) if oldestFirst != None: self.setOldestFirst(oldestFirst) r = GetMessagesRequest(self.session, box=box, pageNumber=pageNumber, **kwargs) responseData = tryRequest(r) return responseData["kmails"]
def _getRaidLog(self, noThrow=True, force=False): """ Access the raid log and store it locally """ with self.__raidlogDownloadLock: if not self.__initialized and not force: return self.lastEvents self._log.debug("Reading clan raid logs...") rl = ClanRaidLogRequest(self.session) result = tryRequest(rl, nothrow=noThrow, numTries=5, initialDelay=0.5, scaleFactor=2) if result is None: self._log.warning("Could not read clan raid logs.") return self.lastEvents with self._syncLock: self._raiseEvent("new_raid_log", None, LogDict(result)) return result
def _checkForNewKmails(self, force=False): """ Check if any new kmails have arrived, and notify the MailHandler if so. This check is done using the KoL API to check for new "green message" events. If force is true, the MailHandler is notified of new mail even if no mail is present. This doesn't do any harm, the handler will just find an empty inbox if nothing's there. """ azTime = None if force else self._lastGreenEventAzTime r = GetEventMessageRequest(self._s, azTime) events = tryRequest(r)['events'] if events: self._lastGreenEventAzTime = max( e.get('azunixtime', 0) for e in events) if force or any(True for e in events if "New message received" in e.get('message', "")): self._log.debug("Checking kmail...") self._lastKmailRefresh = time.time() self._mailHandler.notify()
def _checkForNewKmails(self, force=False): """ Check if any new kmails have arrived, and notify the MailHandler if so. This check is done using the KoL API to check for new "green message" events. If force is true, the MailHandler is notified of new mail even if no mail is present. This doesn't do any harm, the handler will just find an empty inbox if nothing's there. """ azTime = None if force else self._lastGreenEventAzTime r = GetEventMessageRequest(self._s, azTime) events = tryRequest(r)['events'] if events: self._lastGreenEventAzTime = max(e.get('azunixtime', 0) for e in events) if force or any(True for e in events if "New message received" in e.get('message', "")): self._log.debug("Checking kmail...") self._lastKmailRefresh = time.time() self._mailHandler.notify()
def __init__(self, parent, name, iData, config): """ Initialize the manager """ self._playerDb = None self._numChanges = 0 self._ready = False self._otherBots = None self._myFreq = None self._numPlayersForFreqChange = None self._freqChangeTimeout = None self._format, self._emoteFormat = None, None super(WalkieTalkieRepeater, self).__init__(parent, name, iData, config) self._invMan.refreshInventory() self._lastOutsiderCheck = 0 self._changeFreqRequests = {} inventory = self._invMan.inventory() numTalkies = inventory.get(6846, 0) if numTalkies == 0: numUnusedTalkies = inventory.get(6845, 0) if numUnusedTalkies > 0: try: r = UseItemRequest(self._s, 6845) d = tryRequest(r) numTalkies = 1 except Error: raise FatalError("Could not use unused walkie talkie.") else: raise FatalError("Cannot use WalkieTalkieRepeater with " "no walkie talkie!") replies = self.sendChatMessage("/kenneth", None, waitForReply=True, raw=True) for reply in replies: txt = reply['text'] freq = re.search(r"The frequency is (\d+.\d), Mr. Rather", txt) if freq: self._myFreq = freq.group(1) self._log.info("My walkie talkie frequency is {}".format( freq.group(1))) if self._myFreq is None: raise RuntimeError("Could not determine walkie talkie frequency.") self._ready = True
def __init__(self, parent, name, iData, config): """ Initialize the manager """ self._playerDb = None self._numChanges = 0 self._ready = False self._otherBots = None self._myFreq = None self._numPlayersForFreqChange = None self._freqChangeTimeout = None self._format, self._emoteFormat = None, None super(WalkieTalkieRepeater, self).__init__(parent, name, iData, config) self._invMan.refreshInventory() self._lastOutsiderCheck = 0 self._changeFreqRequests = {} inventory = self._invMan.inventory() numTalkies = inventory.get(6846, 0) if numTalkies == 0: numUnusedTalkies = inventory.get(6845, 0) if numUnusedTalkies > 0: try: r = UseItemRequest(self._s, 6845) d = tryRequest(r) numTalkies = 1 except Error: raise FatalError("Could not use unused walkie talkie.") else: raise FatalError("Cannot use WalkieTalkieRepeater with " "no walkie talkie!") replies = self.sendChatMessage("/kenneth", None, waitForReply=True, raw=True) for reply in replies: txt = reply['text'] freq = re.search(r"The frequency is (\d+.\d), Mr. Rather", txt) if freq: self._myFreq = freq.group(1) self._log.info("My walkie talkie frequency is {}" .format(freq.group(1))) if self._myFreq is None: raise RuntimeError("Could not determine walkie talkie frequency.") self._ready = True
def heal(self, hint, args, status): if self.type == 'tonic': rMp = GalaktikRequest(self.parent.session, False, hint) tryRequest(rMp) return elif self.type == 'nostrum': rHp = GalaktikRequest(self.parent.session, True, hint) tryRequest(rHp) return with InventoryLock.lock: n = int(max(1, math.floor(hint/10.0))) invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() myQty = inv.get(232, 0) if myQty < n: rBuy = GalaktikBuyRequest(self.parent.session, 232, n - myQty) tryRequest(rBuy, nothrow=True) rUse = UseItemRequest(self.parent.session, 232) try: for _ in range(n): tryRequest(rUse) except kol.Error.Error: pass
def heal(self, hint, args, status): if self.type == 'tonic': rMp = GalaktikRequest(self.parent.session, False, hint) tryRequest(rMp) return elif self.type == 'nostrum': rHp = GalaktikRequest(self.parent.session, True, hint) tryRequest(rHp) return with InventoryLock.lock: n = int(max(1, math.floor(hint / 10.0))) invMan = self.parent.inventoryManager invMan.refreshInventory() inv = invMan.inventory() myQty = inv.get(232, 0) if myQty < n: rBuy = GalaktikBuyRequest(self.parent.session, 232, n - myQty) tryRequest(rBuy, nothrow=True) rUse = UseItemRequest(self.parent.session, 232) try: for _ in range(n): tryRequest(rUse) except kol.Error.Error: pass
def buyFromMall(session, itemId, quantity=1, maxPrice=0, logFunc=None): if logFunc is None: logFunc = _empty s = tryRequest(StatusRequest(session)) canBuy = (( int(s.get('hardcore',"1")) == 0 and int(s.get('roninleft',"1")) == 0) or int(s.get('casual',"0")) == 1 or int(s.get('freedralph',"0")) == 1) if not canBuy: raise kol.Error.Error("Can't buy from mall in Ronin/Hardcore", kol.Error.USER_IN_HARDCORE_RONIN) with InventoryLock.lock: item = getItemFromId(itemId) itemName = item.get('name', str(itemId)) numTries = 0 numBought = 0 numResults = 10 logFunc("Trying to buy {}x {} from mall..." .format(quantity, itemName)) while numTries < 10: r1 = MallItemSearchRequest(session, itemName, maxPrice=maxPrice, numResults=numResults) d1 = tryRequest(r1, numTries=1) itemList = [item for item in d1['results'] if item.get('id', -1) == itemId] listFull = (len(itemList) == numResults) availableList = [item for item in itemList if not item.get('hitLimit', False)] if not itemList: return numBought if not availableList and listFull: numResults *= 2 while availableList and numBought < quantity: item = availableList[0] limitedMode = False qty = min(quantity, item['quantity']) if 'limit' in item: qty = 1 limitedMode = True price = item['price'] storeId = item['storeId'] logFunc("Buying {}x {} @ {} meat from store {}" .format(qty, itemName, price, storeId)) r2 = MallItemPurchaseRequest( session, storeId, itemId, price, qty) try: d2 = tryRequest(r2, numTries=1) numBought += d2['items'][0]['quantity'] logFunc("Spent {} meat and got {}x {}." .format(d2['meatSpent'], d2['items'][0]['quantity'], itemName)) if not limitedMode: availableList.pop(0) except kol.Error.Error as e: if e.code == kol.Error.ITEM_NOT_FOUND: logFunc("Could not buy item. Refreshing...") # refresh search availableList = [] continue else: logFunc("Error buying from this store. Moving on...") availableList.pop(0) continue numTries += 1 if numBought >= quantity: break return numBought
def getUniqueDateString(session): r = StatusRequest(session) d = tryRequest(r) s = str(d['rollover']) return s
def buyFromMall(session, itemId, quantity=1, maxPrice=0, logFunc=None): if logFunc is None: logFunc = _empty s = tryRequest(StatusRequest(session)) canBuy = ((int(s.get('hardcore', "1")) == 0 and int(s.get('roninleft', "1")) == 0) or int(s.get('casual', "0")) == 1 or int(s.get('freedralph', "0")) == 1) if not canBuy: raise kol.Error.Error("Can't buy from mall in Ronin/Hardcore", kol.Error.USER_IN_HARDCORE_RONIN) with InventoryLock.lock: item = getItemFromId(itemId) itemName = item.get('name', str(itemId)) numTries = 0 numBought = 0 numResults = 10 logFunc("Trying to buy {}x {} from mall...".format(quantity, itemName)) while numTries < 10: r1 = MallItemSearchRequest(session, itemName, maxPrice=maxPrice, numResults=numResults) d1 = tryRequest(r1, numTries=1) itemList = [ item for item in d1['results'] if item.get('id', -1) == itemId ] listFull = (len(itemList) == numResults) availableList = [ item for item in itemList if not item.get('hitLimit', False) ] if not itemList: return numBought if not availableList and listFull: numResults *= 2 while availableList and numBought < quantity: item = availableList[0] limitedMode = False qty = min(quantity, item['quantity']) if 'limit' in item: qty = 1 limitedMode = True price = item['price'] storeId = item['storeId'] logFunc("Buying {}x {} @ {} meat from store {}".format( qty, itemName, price, storeId)) r2 = MallItemPurchaseRequest(session, storeId, itemId, price, qty) try: d2 = tryRequest(r2, numTries=1) numBought += d2['items'][0]['quantity'] logFunc("Spent {} meat and got {}x {}.".format( d2['meatSpent'], d2['items'][0]['quantity'], itemName)) if not limitedMode: availableList.pop(0) except kol.Error.Error as e: if e.code == kol.Error.ITEM_NOT_FOUND: logFunc("Could not buy item. Refreshing...") # refresh search availableList = [] continue else: logFunc("Error buying from this store. Moving on...") availableList.pop(0) continue numTries += 1 if numBought >= quantity: break return numBought
def __init__(self, s, c, props, inv, configFile, db, exitEvent): """ Initialize the BotSystem """ self._exitEvent = exitEvent self._initialized = False # trigger to stop heartbeat subsystem self._hbStop = threading.Event() # start subsystems try: oldTxt = None hbSys = HeartbeatSubsystem(numThreads=6, period=5, stopEvent=self._hbStop) evSys = EventSubsystem() # initialize subsystems super(BotSystem, self).__init__(name="sys.system", identity="system", evSys=evSys, hbSys=hbSys) if exitEvent.is_set(): sys.exit() # copy arguments self._s = s self._c = c self._props = props self._inv = inv self._db = db self._log = logging.getLogger() # initialize some RunProperties data now that we are logged on self._log.debug("Getting my userId...") r1 = StatusRequest(self._s) d1 = tryRequest(r1) self._props.userId = int(d1['playerid']) self._log.info("Getting my clan...") r2 = UserProfileRequest(self._s, self._props.userId) d2 = tryRequest(r2) self._props.clan = d2.get('clanId', -1) self._log.info("I am a member of clan #{} [{}]!".format( self._props.clan, d2.get('clanName', "Not in any clan"))) # config file stuff self._config = None self._overWriteConfig = False oldTxt = self._loadConfig(configFile) # listen to channels self._initializeChatChannels(self._config) c.getNewChatMessages() # discard old PM's and whatnot # initialize directors self._dir = None iData = InitData(s, c, props, inv, db) self._log.info("Starting communication system...") self._dir = CommunicationDirector(self, iData, self._config['director']) self._lastCheckedChat = 0 self._initialized = True except: self._hbStop.set() raise finally: # rewrite config file (values may be modified by modules/managers) if oldTxt is not None: self._saveConfig(configFile, oldTxt)
def __init__(self, s, c, props, inv, configFile, db, exitEvent): """ Initialize the BotSystem """ self._exitEvent = exitEvent self._initialized = False # trigger to stop heartbeat subsystem self._hbStop = threading.Event() # start subsystems try: oldTxt = None hbSys = HeartbeatSubsystem(numThreads=6, period=5, stopEvent=self._hbStop) evSys = EventSubsystem() # initialize subsystems super(BotSystem, self).__init__( name="sys.system", identity="system", evSys=evSys, hbSys=hbSys) if exitEvent.is_set(): sys.exit() # copy arguments self._s = s self._c = c self._props = props self._inv = inv self._db = db self._log = logging.getLogger() # initialize some RunProperties data now that we are logged on self._log.debug("Getting my userId...") r1 = StatusRequest(self._s) d1 = tryRequest(r1) self._props.userId = int(d1['playerid']) self._log.info("Getting my clan...") r2 = UserProfileRequest(self._s, self._props.userId) d2 = tryRequest(r2) self._props.clan = d2.get('clanId', -1) self._log.info("I am a member of clan #{} [{}]!" .format(self._props.clan, d2.get('clanName', "Not in any clan"))) # config file stuff self._config = None self._overWriteConfig = False oldTxt = self._loadConfig(configFile) # listen to channels self._initializeChatChannels(self._config) c.getNewChatMessages() # discard old PM's and whatnot # initialize directors self._dir = None iData = InitData(s, c, props, inv, db) self._log.info("Starting communication system...") self._dir = CommunicationDirector(self, iData, self._config['director']) self._lastCheckedChat = 0 self._initialized = True except: self._hbStop.set() raise finally: # rewrite config file (values may be modified by modules/managers) if oldTxt is not None: self._saveConfig(configFile, oldTxt)