Index: source/tools/XpartaMuPP/EcheLOn.py =================================================================== --- source/tools/XpartaMuPP/EcheLOn.py +++ source/tools/XpartaMuPP/EcheLOn.py @@ -74,7 +74,7 @@ the Player model, or the one that already exists in the database. """ - players = db.query(Player).filter_by(jid=str(JID)) + players = db.query(Player).filter(Player.jid.ilike(str(JID))) if not players.first(): player = Player(jid=str(JID), rating=-1) db.add(player) @@ -88,7 +88,7 @@ Returns the player that was removed, or None if that player didn't exist. """ - players = db.query(Player).filter_by(jid=JID) + players = db.query(Player).filter(Player.jid.ilike(str(JID))) player = players.first() if not player: return None @@ -253,6 +253,7 @@ for rank, player in enumerate(players): board[player.jid] = {'name': '@'.join(player.jid.split('@')[:-1]), 'rating': str(player.rating)} return board + def getRatingList(self, nicks): """ Returns a rating list of players @@ -368,6 +369,7 @@ return len(rawGameReport[key].split(","))-1 # Return -1 in case of failure. return -1 + ## Class for custom player stanza extension ## class PlayerXmppPlugin(ElementBase): name = 'query' @@ -447,6 +449,10 @@ self.sjid = sjid self.room = room self.nick = nick + self.ratingListCache = {} + self.ratingCacheReload = True + self.boardListCache = {} + self.boardCacheReload = True # Init leaderboard object self.leaderboard = LeaderboardList(room) @@ -528,12 +534,12 @@ """ Request lists. """ - if 'boardlist' in iq.plugins: + iq_attribute = list(iq.plugins.items())[0][0][0] + if iq_attribute == 'boardlist': command = iq['boardlist']['command'] recipient = iq['boardlist']['recipient'] if command == 'getleaderboard': try: - self.leaderboard.getOrCreatePlayer(iq['from']) self.sendBoardList(iq['from'], recipient) except: traceback.print_exc() @@ -545,7 +551,7 @@ traceback.print_exc() else: logging.error("Failed to process boardlist request from %s" % iq['from'].bare) - elif 'profile' in iq.plugins: + elif iq_attribute == 'profile': command = iq['profile']['command'] recipient = iq['profile']['recipient'] try: @@ -563,20 +569,25 @@ """ pass elif iq['type'] == 'set': - if 'gamereport' in iq.plugins: + iq_attribute = list(iq.plugins.items())[0][0][0] + + if iq_attribute == 'gamereport': """ Client is reporting end of game statistics """ try: + self.leaderboard.getOrCreatePlayer(iq['gamereport']['sender']) self.reportManager.addReport(iq['gamereport']['sender'], iq['gamereport']['game']) if self.leaderboard.getLastRatedMessage() != "": + self.ratingCacheReload = True + self.boardCacheReload = True self.send_message(mto=self.room, mbody=self.leaderboard.getLastRatedMessage(), mtype="groupchat", mnick=self.nick) self.sendRatingList(iq['from']) except: traceback.print_exc() logging.error("Failed to update game statistics for %s" % iq['from'].bare) - elif 'player' in iq.plugins: + elif iq_attribute == 'player': player = iq['player']['online'] #try: self.leaderboard.getOrCreatePlayer(player) @@ -591,13 +602,17 @@ If no target is passed the boardlist is broadcasted to all clients. """ - ## Pull leaderboard data and add it to the stanza - board = self.leaderboard.getBoard() + ## See if we can squeak by with the cached version. + # Leaderboard cache is reloaded upon a new rated game being rated. + if self.boardCacheReload: + self.boardListCache = self.leaderboard.getBoard() + self.boardCacheReload = False + stz = BoardListXmppPlugin() iq = self.Iq() iq['type'] = 'result' - for i in board: - stz.addItem(board[i]['name'], board[i]['rating']) + for i in self.boardListCache: + stz.addItem(self.boardListCache[i]['name'], self.boardListCache[i]['rating']) stz.addCommand('boardlist') stz.addRecipient(recipient) iq.setPayload(stz) @@ -617,13 +632,24 @@ """ Send the rating list. """ - ## Pull rating list data and add it to the stanza - ratinglist = self.leaderboard.getRatingList(self.nicks) + ## Attempt to use the cache. + # Cache is invalidated when a new game is rated or a uncached player + # comes online. + if self.ratingCacheReload: + self.ratingListCache = self.leaderboard.getRatingList(self.nicks) + self.ratingCacheReload = False + else: + for JID in list(self.nicks): + if JID not in self.ratingListCache: + self.ratingListCache = self.leaderboard.getRatingList(self.nicks) + self.ratingCacheReload = False + break + stz = BoardListXmppPlugin() iq = self.Iq() iq['type'] = 'result' - for i in ratinglist: - stz.addItem(ratinglist[i]['name'], ratinglist[i]['rating']) + for i in self.ratingListCache: + stz.addItem(self.ratingListCache[i]['name'], self.ratingListCache[i]['rating']) stz.addCommand('ratinglist') iq.setPayload(stz) ## Check recipient exists Index: source/tools/XpartaMuPP/XpartaMuPP.py =================================================================== --- source/tools/XpartaMuPP/XpartaMuPP.py +++ source/tools/XpartaMuPP/XpartaMuPP.py @@ -178,6 +178,7 @@ # Store mapping of nicks and XmppIDs, attached via presence stanza self.nicks = {} + self.presences = {} # Obselete when XEP-0060 is implemented. self.lastLeft = "" @@ -212,6 +213,7 @@ self.add_event_handler("muc::%s::got_online" % self.room, self.muc_online) self.add_event_handler("muc::%s::got_offline" % self.room, self.muc_offline) self.add_event_handler("groupchat_message", self.muc_message) + self.add_event_handler("changed_status", self.presence_change) def start(self, event): """ @@ -233,6 +235,7 @@ # If it doesn't already exist, store player JID mapped to their nick. if str(presence['muc']['jid']) not in self.nicks: self.nicks[str(presence['muc']['jid'])] = presence['muc']['nick'] + self.presences[str(presence['muc']['jid'])] = "available" # Check the jid isn't already in the lobby. # Send Gamelist to new player. self.sendGameList(presence['muc']['jid']) @@ -254,6 +257,7 @@ self.lastLeft = str(presence['muc']['jid']) if str(presence['muc']['jid']) in self.nicks: del self.nicks[str(presence['muc']['jid'])] + del self.presences[str(presence['muc']['jid'])] if presence['muc']['nick'] == self.ratingsBot: self.ratingsBotWarned = False @@ -266,6 +270,21 @@ mbody="I am the administrative bot in this lobby and cannot participate in any games.", mtype='groupchat') + def presence_change(self, presence): + """ + Processes presence change + """ + prefix = "%s/" % self.room + nick = str(presence['from']).replace(prefix, "") + for JID in self.nicks: + if self.nicks[JID] == nick: + if self.presences[JID] == 'busy' and (str(presence['type']) == "available" or str(presence['type']) == "away"): + self.sendGameList(JID) + self.relayBoardListRequest(JID) + self.presences[JID] = str(presence['type']) + break + + def iqhandler(self, iq): """ Handle the custom stanzas @@ -280,42 +299,42 @@ """ # Send lists/register on leaderboard; depreciated once muc_online # can send lists/register automatically on joining the room. - if 'gamelist' in iq.plugins: + if list(iq.plugins.items())[0][0][0] == 'gamelist': try: self.sendGameList(iq['from']) except: traceback.print_exc() logging.error("Failed to process gamelist request from %s" % iq['from'].bare) - elif 'boardlist' in iq.plugins: + elif list(iq.plugins.items())[0][0][0] == 'boardlist': command = iq['boardlist']['command'] try: self.relayBoardListRequest(iq['from']) except: traceback.print_exc() logging.error("Failed to process leaderboardlist request from %s" % iq['from'].bare) - elif 'profile' in iq.plugins: + elif list(iq.plugins.items())[0][0][0] == 'profile': command = iq['profile']['command'] try: self.relayProfileRequest(iq['from'], command) except: - pass # TODO needed? + pass else: logging.error("Unknown 'get' type stanza request from %s" % iq['from'].bare) elif iq['type'] == 'result': """ Iq successfully received """ - if 'boardlist' in iq.plugins: + if list(iq.plugins.items())[0][0][0] == 'boardlist': recipient = iq['boardlist']['recipient'] self.relayBoardList(iq['boardlist'], recipient) - elif 'profile' in iq.plugins: + elif list(iq.plugins.items())[0][0][0] == 'profile': recipient = iq['profile']['recipient'] player = iq['profile']['command'] self.relayProfile(iq['profile'], player, recipient) else: - pass # TODO error/warn? + pass elif iq['type'] == 'set': - if 'gamelist' in iq.plugins: + if list(iq.plugins.items())[0][0][0] == 'gamelist': """ Register-update / unregister a game """ @@ -323,8 +342,9 @@ if command == 'register': # Add game try: - self.gameList.addGame(iq['from'], iq['gamelist']['game']) - self.sendGameList() + if iq['from'] in self.nicks: + self.gameList.addGame(iq['from'], iq['gamelist']['game']) + self.sendGameList() except: traceback.print_exc() logging.error("Failed to process game registration data") @@ -344,10 +364,16 @@ self.sendGameList() except: traceback.print_exc() - logging.error("Failed to process changestate data") + logging.error("Failed to process changestate data. Trying to add game") + try: + if iq['from'] in self.nicks: + self.gameList.addGame(iq['from'], iq['gamelist']['game']) + self.sendGameList() + except: + pass else: logging.error("Failed to process command '%s' received from %s" % command, iq['from'].bare) - elif 'gamereport' in iq.plugins: + elif list(iq.plugins.items())[0][0][0] == 'gamereport': """ Client is reporting end of game statistics """ @@ -366,20 +392,23 @@ to all clients. """ games = self.gameList.getAllGames() - if to == "": - for JID in list(self.nicks): - stz = GameListXmppPlugin() + + stz = GameListXmppPlugin() - ## Pull games and add each to the stanza - for JIDs in games: - g = games[JIDs] - stz.addGame(g) + ## Pull games and add each to the stanza + for JIDs in games: + g = games[JIDs] + stz.addGame(g) - ## Set additional IQ attributes - iq = self.Iq() - iq['type'] = 'result' + ## Set additional IQ attributes + iq = self.Iq() + iq['type'] = 'result' + iq.setPayload(stz) + if to == "": + for JID in list(self.presences): + if self.presences[JID] != "available" and self.presences[JID] != "away": + continue iq['to'] = JID - iq.setPayload(stz) ## Try sending the stanza try: @@ -391,18 +420,7 @@ if str(to) not in self.nicks: logging.error("No player with the XmPP ID '%s' known to send gamelist to." % str(to)) return - stz = GameListXmppPlugin() - - ## Pull games and add each to the stanza - for JIDs in games: - g = games[JIDs] - stz.addGame(g) - - ## Set additional IQ attributes - iq = self.Iq() - iq['type'] = 'result' iq['to'] = to - iq.setPayload(stz) ## Try sending the stanza try: @@ -526,14 +544,13 @@ """ iq = self.Iq() iq['type'] = 'result' - """for i in board: - stz.addItem(board[i]['name'], board[i]['rating']) - stz.addCommand('boardlist')""" iq.setPayload(boardList) ## Check recipient exists if to == "": # Rating List - for JID in list(self.nicks): + for JID in list(self.presences): + if self.presences[JID] != "available" and self.presences[JID] != "away": + continue ## Set additional IQ attributes iq['to'] = JID ## Try sending the stanza @@ -542,7 +559,7 @@ except: logging.error("Failed to send rating list") else: - # Leaderboard + # Leaderboard or targeted rating list if str(to) not in self.nicks: logging.error("No player with the XmPP ID '%s' known to send boardlist to" % str(to)) return