Changeset View
Changeset View
Standalone View
Standalone View
source/tools/XpartaMuPP/XpartaMuPP.py
Show First 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | def __init__(self, sjid, password, room, nick, ratingsbot): | ||||
self.ratingsBotWarned = False | self.ratingsBotWarned = False | ||||
self.ratingsBot = ratingsbot | self.ratingsBot = ratingsbot | ||||
# Game collection | # Game collection | ||||
self.gameList = GameList() | self.gameList = GameList() | ||||
# Store mapping of nicks and XmppIDs, attached via presence stanza | # Store mapping of nicks and XmppIDs, attached via presence stanza | ||||
self.nicks = {} | self.nicks = {} | ||||
self.presences = {} # Obselete when XEP-0060 is implemented. | |||||
self.lastLeft = "" | self.lastLeft = "" | ||||
register_stanza_plugin(Iq, PlayerXmppPlugin) | register_stanza_plugin(Iq, PlayerXmppPlugin) | ||||
register_stanza_plugin(Iq, GameListXmppPlugin) | register_stanza_plugin(Iq, GameListXmppPlugin) | ||||
register_stanza_plugin(Iq, BoardListXmppPlugin) | register_stanza_plugin(Iq, BoardListXmppPlugin) | ||||
register_stanza_plugin(Iq, GameReportXmppPlugin) | register_stanza_plugin(Iq, GameReportXmppPlugin) | ||||
register_stanza_plugin(Iq, ProfileXmppPlugin) | register_stanza_plugin(Iq, ProfileXmppPlugin) | ||||
Show All 18 Lines | self.register_handler(Callback('Iq Profile', | ||||
StanzaPath('iq/profile'), | StanzaPath('iq/profile'), | ||||
self.iqhandler, | self.iqhandler, | ||||
instream=True)) | instream=True)) | ||||
self.add_event_handler("session_start", self.start) | self.add_event_handler("session_start", self.start) | ||||
self.add_event_handler("muc::%s::got_online" % self.room, self.muc_online) | 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("muc::%s::got_offline" % self.room, self.muc_offline) | ||||
self.add_event_handler("groupchat_message", self.muc_message) | self.add_event_handler("groupchat_message", self.muc_message) | ||||
self.add_event_handler("changed_status", self.presence_change) | |||||
def start(self, event): | def start(self, event): | ||||
""" | """ | ||||
Process the session_start event | Process the session_start event | ||||
""" | """ | ||||
self.plugin['xep_0045'].joinMUC(self.room, self.nick) | self.plugin['xep_0045'].joinMUC(self.room, self.nick) | ||||
self.send_presence() | self.send_presence() | ||||
self.get_roster() | self.get_roster() | ||||
logging.info("XpartaMuPP started") | logging.info("XpartaMuPP started") | ||||
def muc_online(self, presence): | def muc_online(self, presence): | ||||
""" | """ | ||||
Process presence stanza from a chat room. | Process presence stanza from a chat room. | ||||
""" | """ | ||||
if self.ratingsBot in self.nicks: | if self.ratingsBot in self.nicks: | ||||
self.relayRatingListRequest(self.ratingsBot) | self.relayRatingListRequest(self.ratingsBot) | ||||
self.relayPlayerOnline(presence['muc']['jid']) | self.relayPlayerOnline(presence['muc']['jid']) | ||||
if presence['muc']['nick'] != self.nick: | if presence['muc']['nick'] != self.nick: | ||||
# If it doesn't already exist, store player JID mapped to their nick. | # If it doesn't already exist, store player JID mapped to their nick. | ||||
if str(presence['muc']['jid']) not in self.nicks: | if str(presence['muc']['jid']) not in self.nicks: | ||||
self.nicks[str(presence['muc']['jid'])] = presence['muc']['nick'] | 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. | # Check the jid isn't already in the lobby. | ||||
# Send Gamelist to new player. | # Send Gamelist to new player. | ||||
self.sendGameList(presence['muc']['jid']) | self.sendGameList(presence['muc']['jid']) | ||||
logging.debug("Client '%s' connected with a nick of '%s'." %(presence['muc']['jid'], presence['muc']['nick'])) | logging.debug("Client '%s' connected with a nick of '%s'." %(presence['muc']['jid'], presence['muc']['nick'])) | ||||
def muc_offline(self, presence): | def muc_offline(self, presence): | ||||
""" | """ | ||||
Process presence stanza from a chat room. | Process presence stanza from a chat room. | ||||
""" | """ | ||||
# Clean up after a player leaves | # Clean up after a player leaves | ||||
if presence['muc']['nick'] != self.nick: | if presence['muc']['nick'] != self.nick: | ||||
# Delete any games they were hosting. | # Delete any games they were hosting. | ||||
for JID in self.gameList.getAllGames(): | for JID in self.gameList.getAllGames(): | ||||
if JID == str(presence['muc']['jid']): | if JID == str(presence['muc']['jid']): | ||||
self.gameList.removeGame(JID) | self.gameList.removeGame(JID) | ||||
self.sendGameList() | self.sendGameList() | ||||
break | break | ||||
# Remove them from the local player list. | # Remove them from the local player list. | ||||
self.lastLeft = str(presence['muc']['jid']) | self.lastLeft = str(presence['muc']['jid']) | ||||
if str(presence['muc']['jid']) in self.nicks: | if str(presence['muc']['jid']) in self.nicks: | ||||
del self.nicks[str(presence['muc']['jid'])] | del self.nicks[str(presence['muc']['jid'])] | ||||
del self.presences[str(presence['muc']['jid'])] | |||||
if presence['muc']['nick'] == self.ratingsBot: | if presence['muc']['nick'] == self.ratingsBot: | ||||
self.ratingsBotWarned = False | self.ratingsBotWarned = False | ||||
def muc_message(self, msg): | def muc_message(self, msg): | ||||
""" | """ | ||||
Process new messages from the chatroom. | Process new messages from the chatroom. | ||||
""" | """ | ||||
if msg['mucnick'] != self.nick and self.nick.lower() in msg['body'].lower(): | if msg['mucnick'] != self.nick and self.nick.lower() in msg['body'].lower(): | ||||
self.send_message(mto=msg['from'].bare, | self.send_message(mto=msg['from'].bare, | ||||
mbody="I am the administrative bot in this lobby and cannot participate in any games.", | mbody="I am the administrative bot in this lobby and cannot participate in any games.", | ||||
mtype='groupchat') | 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"): | |||||
user1: 'busy' needs be 'dnd' here | |||||
self.sendGameList(JID) | |||||
self.relayBoardListRequest(JID) | |||||
self.presences[JID] = str(presence['type']) | |||||
break | |||||
def iqhandler(self, iq): | def iqhandler(self, iq): | ||||
""" | """ | ||||
Handle the custom stanzas | Handle the custom stanzas | ||||
This method should be very robust because we could receive anything | This method should be very robust because we could receive anything | ||||
""" | """ | ||||
if iq['type'] == 'error': | if iq['type'] == 'error': | ||||
logging.error('iqhandler error' + iq['error']['condition']) | logging.error('iqhandler error' + iq['error']['condition']) | ||||
#self.disconnect() | #self.disconnect() | ||||
elif iq['type'] == 'get': | elif iq['type'] == 'get': | ||||
""" | """ | ||||
Request lists. | Request lists. | ||||
""" | """ | ||||
# Send lists/register on leaderboard; depreciated once muc_online | # Send lists/register on leaderboard; depreciated once muc_online | ||||
# can send lists/register automatically on joining the room. | # can send lists/register automatically on joining the room. | ||||
if 'gamelist' in iq.plugins: | if list(iq.plugins.items())[0][0][0] == 'gamelist': | ||||
try: | try: | ||||
self.sendGameList(iq['from']) | self.sendGameList(iq['from']) | ||||
except: | except: | ||||
traceback.print_exc() | traceback.print_exc() | ||||
logging.error("Failed to process gamelist request from %s" % iq['from'].bare) | 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'] | command = iq['boardlist']['command'] | ||||
try: | try: | ||||
self.relayBoardListRequest(iq['from']) | self.relayBoardListRequest(iq['from']) | ||||
except: | except: | ||||
traceback.print_exc() | traceback.print_exc() | ||||
logging.error("Failed to process leaderboardlist request from %s" % iq['from'].bare) | 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'] | command = iq['profile']['command'] | ||||
try: | try: | ||||
self.relayProfileRequest(iq['from'], command) | self.relayProfileRequest(iq['from'], command) | ||||
except: | except: | ||||
pass # TODO needed? | pass | ||||
else: | else: | ||||
logging.error("Unknown 'get' type stanza request from %s" % iq['from'].bare) | logging.error("Unknown 'get' type stanza request from %s" % iq['from'].bare) | ||||
elif iq['type'] == 'result': | elif iq['type'] == 'result': | ||||
""" | """ | ||||
Iq successfully received | Iq successfully received | ||||
""" | """ | ||||
if 'boardlist' in iq.plugins: | if list(iq.plugins.items())[0][0][0] == 'boardlist': | ||||
recipient = iq['boardlist']['recipient'] | recipient = iq['boardlist']['recipient'] | ||||
self.relayBoardList(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'] | recipient = iq['profile']['recipient'] | ||||
player = iq['profile']['command'] | player = iq['profile']['command'] | ||||
self.relayProfile(iq['profile'], player, recipient) | self.relayProfile(iq['profile'], player, recipient) | ||||
else: | else: | ||||
pass # TODO error/warn? | pass | ||||
elif iq['type'] == 'set': | elif iq['type'] == 'set': | ||||
if 'gamelist' in iq.plugins: | if list(iq.plugins.items())[0][0][0] == 'gamelist': | ||||
""" | """ | ||||
Register-update / unregister a game | Register-update / unregister a game | ||||
""" | """ | ||||
command = iq['gamelist']['command'] | command = iq['gamelist']['command'] | ||||
if command == 'register': | if command == 'register': | ||||
# Add game | # Add game | ||||
try: | try: | ||||
if iq['from'] in self.nicks: | |||||
self.gameList.addGame(iq['from'], iq['gamelist']['game']) | self.gameList.addGame(iq['from'], iq['gamelist']['game']) | ||||
self.sendGameList() | self.sendGameList() | ||||
except: | except: | ||||
traceback.print_exc() | traceback.print_exc() | ||||
logging.error("Failed to process game registration data") | logging.error("Failed to process game registration data") | ||||
elif command == 'unregister': | elif command == 'unregister': | ||||
# Remove game | # Remove game | ||||
try: | try: | ||||
self.gameList.removeGame(iq['from']) | self.gameList.removeGame(iq['from']) | ||||
self.sendGameList() | self.sendGameList() | ||||
except: | except: | ||||
traceback.print_exc() | traceback.print_exc() | ||||
logging.error("Failed to process game unregistration data") | logging.error("Failed to process game unregistration data") | ||||
elif command == 'changestate': | elif command == 'changestate': | ||||
# Change game status (waiting/running) | # Change game status (waiting/running) | ||||
try: | try: | ||||
self.gameList.changeGameState(iq['from'], iq['gamelist']['game']) | self.gameList.changeGameState(iq['from'], iq['gamelist']['game']) | ||||
self.sendGameList() | self.sendGameList() | ||||
except: | except: | ||||
traceback.print_exc() | 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: | else: | ||||
logging.error("Failed to process command '%s' received from %s" % command, iq['from'].bare) | 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 | Client is reporting end of game statistics | ||||
""" | """ | ||||
try: | try: | ||||
self.relayGameReport(iq['gamereport'], iq['from']) | self.relayGameReport(iq['gamereport'], iq['from']) | ||||
except: | except: | ||||
traceback.print_exc() | traceback.print_exc() | ||||
logging.error("Failed to update game statistics for %s" % iq['from'].bare) | logging.error("Failed to update game statistics for %s" % iq['from'].bare) | ||||
else: | else: | ||||
logging.error("Failed to process stanza type '%s' received from %s" % iq['type'], iq['from'].bare) | logging.error("Failed to process stanza type '%s' received from %s" % iq['type'], iq['from'].bare) | ||||
def sendGameList(self, to = ""): | def sendGameList(self, to = ""): | ||||
""" | """ | ||||
Send a massive stanza with the whole game list. | Send a massive stanza with the whole game list. | ||||
If no target is passed the gamelist is broadcasted | If no target is passed the gamelist is broadcasted | ||||
to all clients. | to all clients. | ||||
""" | """ | ||||
games = self.gameList.getAllGames() | games = self.gameList.getAllGames() | ||||
if to == "": | |||||
for JID in list(self.nicks): | |||||
stz = GameListXmppPlugin() | stz = GameListXmppPlugin() | ||||
## Pull games and add each to the stanza | ## Pull games and add each to the stanza | ||||
for JIDs in games: | for JIDs in games: | ||||
g = games[JIDs] | g = games[JIDs] | ||||
stz.addGame(g) | stz.addGame(g) | ||||
## Set additional IQ attributes | ## Set additional IQ attributes | ||||
iq = self.Iq() | iq = self.Iq() | ||||
iq['type'] = 'result' | iq['type'] = 'result' | ||||
iq['to'] = JID | |||||
iq.setPayload(stz) | 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 | |||||
## Try sending the stanza | ## Try sending the stanza | ||||
try: | try: | ||||
iq.send(block=False, now=True) | iq.send(block=False, now=True) | ||||
except: | except: | ||||
logging.error("Failed to send game list") | logging.error("Failed to send game list") | ||||
else: | else: | ||||
## Check recipient exists | ## Check recipient exists | ||||
if str(to) not in self.nicks: | if str(to) not in self.nicks: | ||||
logging.error("No player with the XmPP ID '%s' known to send gamelist to." % str(to)) | logging.error("No player with the XmPP ID '%s' known to send gamelist to." % str(to)) | ||||
return | 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['to'] = to | ||||
iq.setPayload(stz) | |||||
## Try sending the stanza | ## Try sending the stanza | ||||
try: | try: | ||||
iq.send(block=False, now=True) | iq.send(block=False, now=True) | ||||
except: | except: | ||||
logging.error("Failed to send game list") | logging.error("Failed to send game list") | ||||
def relayBoardListRequest(self, recipient): | def relayBoardListRequest(self, recipient): | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | class XpartaMuPP(sleekxmpp.ClientXMPP): | ||||
def relayBoardList(self, boardList, to = ""): | def relayBoardList(self, boardList, to = ""): | ||||
""" | """ | ||||
Send the whole leaderboard list. | Send the whole leaderboard list. | ||||
If no target is passed the boardlist is broadcasted | If no target is passed the boardlist is broadcasted | ||||
to all clients. | to all clients. | ||||
""" | """ | ||||
iq = self.Iq() | iq = self.Iq() | ||||
iq['type'] = 'result' | iq['type'] = 'result' | ||||
"""for i in board: | |||||
stz.addItem(board[i]['name'], board[i]['rating']) | |||||
stz.addCommand('boardlist')""" | |||||
iq.setPayload(boardList) | iq.setPayload(boardList) | ||||
## Check recipient exists | ## Check recipient exists | ||||
if to == "": | if to == "": | ||||
# Rating List | # 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 | ## Set additional IQ attributes | ||||
iq['to'] = JID | iq['to'] = JID | ||||
## Try sending the stanza | ## Try sending the stanza | ||||
try: | try: | ||||
iq.send(block=False, now=True) | iq.send(block=False, now=True) | ||||
except: | except: | ||||
logging.error("Failed to send rating list") | logging.error("Failed to send rating list") | ||||
else: | else: | ||||
# Leaderboard | # Leaderboard or targeted rating list | ||||
if str(to) not in self.nicks: | if str(to) not in self.nicks: | ||||
logging.error("No player with the XmPP ID '%s' known to send boardlist to" % str(to)) | logging.error("No player with the XmPP ID '%s' known to send boardlist to" % str(to)) | ||||
return | return | ||||
## Set additional IQ attributes | ## Set additional IQ attributes | ||||
iq['to'] = to | iq['to'] = to | ||||
## Try sending the stanza | ## Try sending the stanza | ||||
try: | try: | ||||
iq.send(block=False, now=True) | iq.send(block=False, now=True) | ||||
▲ Show 20 Lines • Show All 91 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
'busy' needs be 'dnd' here