comparison sat/plugins/plugin_misc_room_game.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 26edcf3a30eb
children 378188abe941
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from sat.core.i18n import _ 20 from sat.core.i18n import _
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core.log import getLogger 22 from sat.core.log import getLogger
23
23 log = getLogger(__name__) 24 log = getLogger(__name__)
24 from twisted.words.protocols.jabber import jid 25 from twisted.words.protocols.jabber import jid
25 from twisted.words.xish import domish 26 from twisted.words.xish import domish
26 from twisted.internet import defer 27 from twisted.internet import defer
27 from time import time 28 from time import time
28 from wokkel import disco, iwokkel 29 from wokkel import disco, iwokkel
29 from zope.interface import implements 30 from zope.interface import implements
30 import copy 31 import copy
32
31 try: 33 try:
32 from twisted.words.protocols.xmlstream import XMPPHandler 34 from twisted.words.protocols.xmlstream import XMPPHandler
33 except ImportError: 35 except ImportError:
34 from wokkel.subprotocols import XMPPHandler 36 from wokkel.subprotocols import XMPPHandler
35 37
42 C.PI_TYPE: "MISC", 44 C.PI_TYPE: "MISC",
43 C.PI_PROTOCOLS: [], 45 C.PI_PROTOCOLS: [],
44 C.PI_DEPENDENCIES: ["XEP-0045", "XEP-0249"], 46 C.PI_DEPENDENCIES: ["XEP-0045", "XEP-0249"],
45 C.PI_MAIN: "RoomGame", 47 C.PI_MAIN: "RoomGame",
46 C.PI_HANDLER: "no", # handler MUST be "no" (dynamic inheritance) 48 C.PI_HANDLER: "no", # handler MUST be "no" (dynamic inheritance)
47 C.PI_DESCRIPTION: _("""Base class for MUC games""") 49 C.PI_DESCRIPTION: _("""Base class for MUC games"""),
48 } 50 }
49 51
50 52
51 # FIXME: this plugin is broken, need to be fixed 53 # FIXME: this plugin is broken, need to be fixed
54
52 55
53 class RoomGame(object): 56 class RoomGame(object):
54 """This class is used to help launching a MUC game. 57 """This class is used to help launching a MUC game.
55 58
56 Bridge methods callbacks: _prepareRoom, _playerReady, _createGame 59 Bridge methods callbacks: _prepareRoom, _playerReady, _createGame
67 # Values for self.join_mode (who can join the game - NONE means solo game) 70 # Values for self.join_mode (who can join the game - NONE means solo game)
68 ALL, INVITED, NONE = xrange(0, 3) 71 ALL, INVITED, NONE = xrange(0, 3)
69 # Values for ready_mode (how to turn a MUC user into a player) 72 # Values for ready_mode (how to turn a MUC user into a player)
70 ASK, FORCE = xrange(0, 2) 73 ASK, FORCE = xrange(0, 2)
71 74
72 MESSAGE = '/message' 75 MESSAGE = "/message"
73 REQUEST = '%s/%s[@xmlns="%s"]' 76 REQUEST = '%s/%s[@xmlns="%s"]'
74 77
75 def __init__(self, host): 78 def __init__(self, host):
76 """For other plugin to dynamically inherit this class, it is necessary to not use __init__ but _init_. 79 """For other plugin to dynamically inherit this class, it is necessary to not use __init__ but _init_.
77 The subclass itself must be initialized this way: 80 The subclass itself must be initialized this way:
163 @param referee_nick (unicode): nickname of the referee 166 @param referee_nick (unicode): nickname of the referee
164 """ 167 """
165 # Important: do not add the referee to 'players' yet. For a 168 # Important: do not add the referee to 'players' yet. For a
166 # <players /> message to be emitted whenever a new player is joining, 169 # <players /> message to be emitted whenever a new player is joining,
167 # it is necessary to not modify 'players' outside of _updatePlayers. 170 # it is necessary to not modify 'players' outside of _updatePlayers.
168 referee_jid = jid.JID(room_jid.userhost() + '/' + referee_nick) 171 referee_jid = jid.JID(room_jid.userhost() + "/" + referee_nick)
169 self.games[room_jid] = {'referee': referee_jid, 'players': [], 'started': False, 'status': {}} 172 self.games[room_jid] = {
173 "referee": referee_jid,
174 "players": [],
175 "started": False,
176 "status": {},
177 }
170 self.games[room_jid].update(copy.deepcopy(self.game_init)) 178 self.games[room_jid].update(copy.deepcopy(self.game_init))
171 self.invitations.setdefault(room_jid, []) 179 self.invitations.setdefault(room_jid, [])
172 180
173 def _gameExists(self, room_jid, started=False): 181 def _gameExists(self, room_jid, started=False):
174 """Return True if a game has been initialized/started. 182 """Return True if a game has been initialized/started.
175 @param started: if False, the game must be initialized to return True, 183 @param started: if False, the game must be initialized to return True,
176 otherwise it must be initialized and started with createGame. 184 otherwise it must be initialized and started with createGame.
177 @return: True if a game is initialized/started in that room""" 185 @return: True if a game is initialized/started in that room"""
178 return room_jid in self.games and (not started or self.games[room_jid]['started']) 186 return room_jid in self.games and (not started or self.games[room_jid]["started"])
179 187
180 def _checkJoinAuth(self, room_jid, user_jid=None, nick="", verbose=False): 188 def _checkJoinAuth(self, room_jid, user_jid=None, nick="", verbose=False):
181 """Checks if this profile is allowed to join the game. 189 """Checks if this profile is allowed to join the game.
182 190
183 The parameter nick is used to check if the user is already 191 The parameter nick is used to check if the user is already
207 if nick in [invited.user for invited in invitations[1]]: 215 if nick in [invited.user for invited in invitations[1]]:
208 auth = True 216 auth = True
209 break 217 break
210 218
211 if not auth and (verbose or _DEBUG): 219 if not auth and (verbose or _DEBUG):
212 log.debug(_(u"%(user)s not allowed to join the game %(game)s in %(room)s") % {'user': user_jid.userhost() or nick, 'game': self.name, 'room': room_jid.userhost()}) 220 log.debug(
221 _(u"%(user)s not allowed to join the game %(game)s in %(room)s")
222 % {
223 "user": user_jid.userhost() or nick,
224 "game": self.name,
225 "room": room_jid.userhost(),
226 }
227 )
213 return auth 228 return auth
214 229
215 def _updatePlayers(self, room_jid, nicks, sync, profile): 230 def _updatePlayers(self, room_jid, nicks, sync, profile):
216 """Update the list of players and signal to the room that some players joined the game. 231 """Update the list of players and signal to the room that some players joined the game.
217 If sync is True, the news players are synchronized with the game data they have missed. 232 If sync is True, the news players are synchronized with the game data they have missed.
222 @param profile (unicode): %(doc_profile)s 237 @param profile (unicode): %(doc_profile)s
223 """ 238 """
224 if nicks == []: 239 if nicks == []:
225 return 240 return
226 # this is better than set(nicks).difference(...) as it keeps the order 241 # this is better than set(nicks).difference(...) as it keeps the order
227 new_nicks = [nick for nick in nicks if nick not in self.games[room_jid]['players']] 242 new_nicks = [
243 nick for nick in nicks if nick not in self.games[room_jid]["players"]
244 ]
228 if len(new_nicks) == 0: 245 if len(new_nicks) == 0:
229 return 246 return
230 247
231 def setStatus(status): 248 def setStatus(status):
232 for nick in new_nicks: 249 for nick in new_nicks:
233 self.games[room_jid]['status'][nick] = status 250 self.games[room_jid]["status"][nick] = status
234 251
235 sync = sync and self._gameExists(room_jid, True) and len(self.games[room_jid]['players']) > 0 252 sync = (
236 setStatus('desync' if sync else 'init') 253 sync
237 self.games[room_jid]['players'].extend(new_nicks) 254 and self._gameExists(room_jid, True)
255 and len(self.games[room_jid]["players"]) > 0
256 )
257 setStatus("desync" if sync else "init")
258 self.games[room_jid]["players"].extend(new_nicks)
238 self._synchronizeRoom(room_jid, [room_jid], profile) 259 self._synchronizeRoom(room_jid, [room_jid], profile)
239 if sync: 260 if sync:
240 setStatus('init') 261 setStatus("init")
241 262
242 def _synchronizeRoom(self, room_jid, recipients, profile): 263 def _synchronizeRoom(self, room_jid, recipients, profile):
243 """Communicate the list of players to the whole room or only to some users, 264 """Communicate the list of players to the whole room or only to some users,
244 also send the synchronization data to the players who recently joined the game. 265 also send the synchronization data to the players who recently joined the game.
245 @param room_jid (jid.JID): JID of the room 266 @param room_jid (jid.JID): JID of the room
247 - room JID 268 - room JID
248 - room JID + "/" + user nick 269 - room JID + "/" + user nick
249 @param profile (unicode): %(doc_profile)s 270 @param profile (unicode): %(doc_profile)s
250 """ 271 """
251 if self._gameExists(room_jid, started=True): 272 if self._gameExists(room_jid, started=True):
252 element = self._createStartElement(self.games[room_jid]['players']) 273 element = self._createStartElement(self.games[room_jid]["players"])
253 else: 274 else:
254 element = self._createStartElement(self.games[room_jid]['players'], name="players") 275 element = self._createStartElement(
276 self.games[room_jid]["players"], name="players"
277 )
255 elements = [(element, None, None)] 278 elements = [(element, None, None)]
256 279
257 sync_args = [] 280 sync_args = []
258 sync_data = self._getSyncData(room_jid) 281 sync_data = self._getSyncData(room_jid)
259 for nick in sync_data: 282 for nick in sync_data:
260 user_jid = jid.JID(room_jid.userhost() + '/' + nick) 283 user_jid = jid.JID(room_jid.userhost() + "/" + nick)
261 if user_jid in recipients: 284 if user_jid in recipients:
262 user_elements = copy.deepcopy(elements) 285 user_elements = copy.deepcopy(elements)
263 for child in sync_data[nick]: 286 for child in sync_data[nick]:
264 user_elements.append((child, None, None)) 287 user_elements.append((child, None, None))
265 recipients.remove(user_jid) 288 recipients.remove(user_jid)
266 else: 289 else:
267 user_elements = [(child, None, None) for child in sync_data[nick]] 290 user_elements = [(child, None, None) for child in sync_data[nick]]
268 sync_args.append(([user_jid, user_elements], {'profile': profile})) 291 sync_args.append(([user_jid, user_elements], {"profile": profile}))
269 292
270 for recipient in recipients: 293 for recipient in recipients:
271 self._sendElements(recipient, elements, profile=profile) 294 self._sendElements(recipient, elements, profile=profile)
272 for args, kwargs in sync_args: 295 for args, kwargs in sync_args:
273 self._sendElements(*args, **kwargs) 296 self._sendElements(*args, **kwargs)
281 be sent by self._synchronizeRoom for the game to be synchronized. 304 be sent by self._synchronizeRoom for the game to be synchronized.
282 """ 305 """
283 if not self._gameExists(room_jid): 306 if not self._gameExists(room_jid):
284 return {} 307 return {}
285 data = {} 308 data = {}
286 status = self.games[room_jid]['status'] 309 status = self.games[room_jid]["status"]
287 nicks = [nick for nick in status if status[nick] == 'desync'] 310 nicks = [nick for nick in status if status[nick] == "desync"]
288 if force_nicks is None: 311 if force_nicks is None:
289 force_nicks = [] 312 force_nicks = []
290 for nick in force_nicks: 313 for nick in force_nicks:
291 if nick not in nicks: 314 if nick not in nicks:
292 nicks.append(nick) 315 nicks.append(nick)
314 raise NotImplementedError("Need to be fixed !") 337 raise NotImplementedError("Need to be fixed !")
315 # FIXME: this is broken and unsecure ! 338 # FIXME: this is broken and unsecure !
316 if not self._checkInviteAuth(room_jid, nick): 339 if not self._checkInviteAuth(room_jid, nick):
317 return [] 340 return []
318 # TODO: remove invitation waiting for too long, using the time data 341 # TODO: remove invitation waiting for too long, using the time data
319 self.invitations[room_jid].append((time(), [player.userhostJID() for player in other_players])) 342 self.invitations[room_jid].append(
343 (time(), [player.userhostJID() for player in other_players])
344 )
320 nicks = [] 345 nicks = []
321 for player_jid in [player.userhostJID() for player in other_players]: 346 for player_jid in [player.userhostJID() for player in other_players]:
322 # TODO: find a way to make it secure 347 # TODO: find a way to make it secure
323 other_nick = self.host.plugins["XEP-0045"].getRoomEntityNick(room_jid, player_jid, secure=self.testing) 348 other_nick = self.host.plugins["XEP-0045"].getRoomEntityNick(
349 room_jid, player_jid, secure=self.testing
350 )
324 if other_nick is None: 351 if other_nick is None:
325 self.host.plugins["XEP-0249"].invite(player_jid, room_jid, {"game": self.name}, profile) 352 self.host.plugins["XEP-0249"].invite(
353 player_jid, room_jid, {"game": self.name}, profile
354 )
326 else: 355 else:
327 nicks.append(other_nick) 356 nicks.append(other_nick)
328 return nicks 357 return nicks
329 358
330 def _checkInviteAuth(self, room_jid, nick, verbose=False): 359 def _checkInviteAuth(self, room_jid, nick, verbose=False):
337 """ 366 """
338 auth = False 367 auth = False
339 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid): 368 if self.invite_mode == self.FROM_ALL or not self._gameExists(room_jid):
340 auth = True 369 auth = True
341 elif self.invite_mode == self.FROM_NONE: 370 elif self.invite_mode == self.FROM_NONE:
342 auth = not self._gameExists(room_jid, started=True) and self.isReferee(room_jid, nick) 371 auth = not self._gameExists(room_jid, started=True) and self.isReferee(
372 room_jid, nick
373 )
343 elif self.invite_mode == self.FROM_REFEREE: 374 elif self.invite_mode == self.FROM_REFEREE:
344 auth = self.isReferee(room_jid, nick) 375 auth = self.isReferee(room_jid, nick)
345 elif self.invite_mode == self.FROM_PLAYERS: 376 elif self.invite_mode == self.FROM_PLAYERS:
346 auth = self.isPlayer(room_jid, nick) 377 auth = self.isPlayer(room_jid, nick)
347 if not auth and (verbose or _DEBUG): 378 if not auth and (verbose or _DEBUG):
348 log.debug(_(u"%(user)s not allowed to invite for the game %(game)s in %(room)s") % {'user': nick, 'game': self.name, 'room': room_jid.userhost()}) 379 log.debug(
380 _(u"%(user)s not allowed to invite for the game %(game)s in %(room)s")
381 % {"user": nick, "game": self.name, "room": room_jid.userhost()}
382 )
349 return auth 383 return auth
350 384
351 def isReferee(self, room_jid, nick): 385 def isReferee(self, room_jid, nick):
352 """Checks if the player with this nick is the referee for the game in this room" 386 """Checks if the player with this nick is the referee for the game in this room"
353 @param room_jid (jid.JID): room JID 387 @param room_jid (jid.JID): room JID
354 @param nick: user nick in the room 388 @param nick: user nick in the room
355 @return: True if the user is the referee of the game in this room 389 @return: True if the user is the referee of the game in this room
356 """ 390 """
357 if not self._gameExists(room_jid): 391 if not self._gameExists(room_jid):
358 return False 392 return False
359 return jid.JID(room_jid.userhost() + '/' + nick) == self.games[room_jid]['referee'] 393 return (
394 jid.JID(room_jid.userhost() + "/" + nick) == self.games[room_jid]["referee"]
395 )
360 396
361 def isPlayer(self, room_jid, nick): 397 def isPlayer(self, room_jid, nick):
362 """Checks if the user with this nick is a player for the game in this room. 398 """Checks if the user with this nick is a player for the game in this room.
363 @param room_jid (jid.JID): JID of the room 399 @param room_jid (jid.JID): JID of the room
364 @param nick: user nick in the room 400 @param nick: user nick in the room
366 """ 402 """
367 if not self._gameExists(room_jid): 403 if not self._gameExists(room_jid):
368 return False 404 return False
369 # Important: the referee is not in the 'players' list right after 405 # Important: the referee is not in the 'players' list right after
370 # the game initialization, that's why we do also check with isReferee 406 # the game initialization, that's why we do also check with isReferee
371 return nick in self.games[room_jid]['players'] or self.isReferee(room_jid, nick) 407 return nick in self.games[room_jid]["players"] or self.isReferee(room_jid, nick)
372 408
373 def _checkWaitAuth(self, room, other_players, verbose=False): 409 def _checkWaitAuth(self, room, other_players, verbose=False):
374 """Check if we must wait for other players before starting the game. 410 """Check if we must wait for other players before starting the game.
375 411
376 @param room (wokkel.muc.Room): the room 412 @param room (wokkel.muc.Room): the room
386 elif len(room.roster) < len(other_players): 422 elif len(room.roster) < len(other_players):
387 # do not check the players until we may actually have them all 423 # do not check the players until we may actually have them all
388 result = (False, [], other_players) 424 result = (False, [], other_players)
389 else: 425 else:
390 # TODO: find a way to make it secure 426 # TODO: find a way to make it secure
391 (nicks, missing) = self.host.plugins["XEP-0045"].getRoomNicksOfUsers(room, other_players, secure=False) 427 (nicks, missing) = self.host.plugins["XEP-0045"].getRoomNicksOfUsers(
428 room, other_players, secure=False
429 )
392 result = (len(nicks) == len(other_players), nicks, missing) 430 result = (len(nicks) == len(other_players), nicks, missing)
393 if not result[0] and (verbose or _DEBUG): 431 if not result[0] and (verbose or _DEBUG):
394 log.debug(_(u"Still waiting for %(users)s before starting the game %(game)s in %(room)s") % {'users': result[2], 'game': self.name, 'room': room.occupantJID.userhost()}) 432 log.debug(
433 _(
434 u"Still waiting for %(users)s before starting the game %(game)s in %(room)s"
435 )
436 % {
437 "users": result[2],
438 "game": self.name,
439 "room": room.occupantJID.userhost(),
440 }
441 )
395 return result 442 return result
396 443
397 def getUniqueName(self, muc_service=None, profile_key=C.PROF_KEY_NONE): 444 def getUniqueName(self, muc_service=None, profile_key=C.PROF_KEY_NONE):
398 """Generate unique room name 445 """Generate unique room name
399 446
404 client = self.host.getClient(profile_key) 451 client = self.host.getClient(profile_key)
405 # FIXME: jid.JID must be used instead of strings 452 # FIXME: jid.JID must be used instead of strings
406 room = self.host.plugins["XEP-0045"].getUniqueName(client, muc_service) 453 room = self.host.plugins["XEP-0045"].getUniqueName(client, muc_service)
407 return jid.JID("sat_%s_%s" % (self.name.lower(), room.userhost())) 454 return jid.JID("sat_%s_%s" % (self.name.lower(), room.userhost()))
408 455
409 def _prepareRoom(self, other_players=None, room_jid_s='', profile_key=C.PROF_KEY_NONE): 456 def _prepareRoom(
457 self, other_players=None, room_jid_s="", profile_key=C.PROF_KEY_NONE
458 ):
410 room_jid = jid.JID(room_jid_s) if room_jid_s else None 459 room_jid = jid.JID(room_jid_s) if room_jid_s else None
411 other_players = [jid.JID(player).userhostJID() for player in other_players] 460 other_players = [jid.JID(player).userhostJID() for player in other_players]
412 return self.prepareRoom(other_players, room_jid, profile_key) 461 return self.prepareRoom(other_players, room_jid, profile_key)
413 462
414 def prepareRoom(self, other_players=None, room_jid=None, profile_key=C.PROF_KEY_NONE): 463 def prepareRoom(self, other_players=None, room_jid=None, profile_key=C.PROF_KEY_NONE):
418 @param room_jid (jid.JID): JID of the room, or None to generate a unique name 467 @param room_jid (jid.JID): JID of the room, or None to generate a unique name
419 @param profile_key (unicode): %(doc_profile_key)s 468 @param profile_key (unicode): %(doc_profile_key)s
420 """ 469 """
421 # FIXME: need to be refactored 470 # FIXME: need to be refactored
422 client = self.host.getClient(profile_key) 471 client = self.host.getClient(profile_key)
423 log.debug(_(u'Preparing room for %s game') % self.name) 472 log.debug(_(u"Preparing room for %s game") % self.name)
424 profile = self.host.memory.getProfileName(profile_key) 473 profile = self.host.memory.getProfileName(profile_key)
425 if not profile: 474 if not profile:
426 log.error(_("Unknown profile")) 475 log.error(_("Unknown profile"))
427 return defer.succeed(None) 476 return defer.succeed(None)
428 if other_players is None: 477 if other_players is None:
436 self._createOrInvite(client, room_jid, other_players) 485 self._createOrInvite(client, room_jid, other_players)
437 return defer.succeed(None) 486 return defer.succeed(None)
438 487
439 user_jid = self.host.getJidNStream(profile)[0] 488 user_jid = self.host.getJidNStream(profile)[0]
440 d = self.host.plugins["XEP-0045"].join(room_jid, user_jid.user, {}, profile) 489 d = self.host.plugins["XEP-0045"].join(room_jid, user_jid.user, {}, profile)
441 return d.addCallback(lambda dummy: self._createOrInvite(client, room_jid, other_players)) 490 return d.addCallback(
491 lambda dummy: self._createOrInvite(client, room_jid, other_players)
492 )
442 493
443 def userJoinedTrigger(self, room, user, profile): 494 def userJoinedTrigger(self, room, user, profile):
444 """This trigger is used to check if the new user can take part of a game, create the game if we were waiting for him or just update the players list. 495 """This trigger is used to check if the new user can take part of a game, create the game if we were waiting for him or just update the players list.
445 496
446 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User} 497 @room: wokkel.muc.Room object. room.roster is a dict{wokkel.muc.User.nick: wokkel.muc.User}
449 """ 500 """
450 room_jid = room.occupantJID.userhostJID() 501 room_jid = room.occupantJID.userhostJID()
451 profile_nick = room.occupantJID.resource 502 profile_nick = room.occupantJID.resource
452 if not self.isReferee(room_jid, profile_nick): 503 if not self.isReferee(room_jid, profile_nick):
453 return True # profile is not the referee 504 return True # profile is not the referee
454 if not self._checkJoinAuth(room_jid, user.entity if user.entity else None, user.nick): 505 if not self._checkJoinAuth(
506 room_jid, user.entity if user.entity else None, user.nick
507 ):
455 # user not allowed but let him know that we are playing :p 508 # user not allowed but let him know that we are playing :p
456 self._synchronizeRoom(room_jid, [jid.JID(room_jid.userhost() + '/' + user.nick)], profile) 509 self._synchronizeRoom(
510 room_jid, [jid.JID(room_jid.userhost() + "/" + user.nick)], profile
511 )
457 return True 512 return True
458 if self.wait_mode == self.FOR_ALL: 513 if self.wait_mode == self.FOR_ALL:
459 # considering the last batch of invitations 514 # considering the last batch of invitations
460 batch = len(self.invitations[room_jid]) - 1 515 batch = len(self.invitations[room_jid]) - 1
461 if batch < 0: 516 if batch < 0:
462 log.error(u"Invitations from %s to play %s in %s have been lost!" % (profile_nick, self.name, room_jid.userhost())) 517 log.error(
518 u"Invitations from %s to play %s in %s have been lost!"
519 % (profile_nick, self.name, room_jid.userhost())
520 )
463 return True 521 return True
464 other_players = self.invitations[room_jid][batch][1] 522 other_players = self.invitations[room_jid][batch][1]
465 (auth, nicks, dummy) = self._checkWaitAuth(room, other_players) 523 (auth, nicks, dummy) = self._checkWaitAuth(room, other_players)
466 if auth: 524 if auth:
467 del self.invitations[room_jid][batch] 525 del self.invitations[room_jid][batch]
483 profile_nick = room.occupantJID.resource 541 profile_nick = room.occupantJID.resource
484 if not self.isReferee(room_jid, profile_nick): 542 if not self.isReferee(room_jid, profile_nick):
485 return True # profile is not the referee 543 return True # profile is not the referee
486 if self.isPlayer(room_jid, user.nick): 544 if self.isPlayer(room_jid, user.nick):
487 try: 545 try:
488 self.games[room_jid]['players'].remove(user.nick) 546 self.games[room_jid]["players"].remove(user.nick)
489 except ValueError: 547 except ValueError:
490 pass 548 pass
491 if len(self.games[room_jid]['players']) == 0: 549 if len(self.games[room_jid]["players"]) == 0:
492 return True 550 return True
493 if self.wait_mode == self.FOR_ALL: 551 if self.wait_mode == self.FOR_ALL:
494 # allow this user to join the game again 552 # allow this user to join the game again
495 user_jid = user.entity.userhostJID() 553 user_jid = user.entity.userhostJID()
496 if len(self.invitations[room_jid]) == 0: 554 if len(self.invitations[room_jid]) == 0:
511 - create: set to True to allow the game creation 569 - create: set to True to allow the game creation
512 - sync: set to True to advice a game synchronization 570 - sync: set to True to advice a game synchronization
513 """ 571 """
514 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid, profile) 572 user_nick = self.host.plugins["XEP-0045"].getRoomNick(room_jid, profile)
515 if not user_nick: 573 if not user_nick:
516 log.error(u'Internal error: profile %s has not joined the room %s' % (profile, room_jid.userhost())) 574 log.error(
575 u"Internal error: profile %s has not joined the room %s"
576 % (profile, room_jid.userhost())
577 )
517 return False, False 578 return False, False
518 if self._gameExists(room_jid): 579 if self._gameExists(room_jid):
519 is_referee = self.isReferee(room_jid, user_nick) 580 is_referee = self.isReferee(room_jid, user_nick)
520 if self._gameExists(room_jid, started=True): 581 if self._gameExists(room_jid, started=True):
521 log.info(_(u"%(game)s game already created in room %(room)s") % {'game': self.name, 'room': room_jid.userhost()}) 582 log.info(
583 _(u"%(game)s game already created in room %(room)s")
584 % {"game": self.name, "room": room_jid.userhost()}
585 )
522 return False, is_referee 586 return False, is_referee
523 elif not is_referee: 587 elif not is_referee:
524 log.info(_(u"%(game)s game in room %(room)s can only be created by %(user)s") % {'game': self.name, 'room': room_jid.userhost(), 'user': user_nick}) 588 log.info(
589 _(u"%(game)s game in room %(room)s can only be created by %(user)s")
590 % {"game": self.name, "room": room_jid.userhost(), "user": user_nick}
591 )
525 return False, False 592 return False, False
526 else: 593 else:
527 self._initGame(room_jid, user_nick) 594 self._initGame(room_jid, user_nick)
528 return True, False 595 return True, False
529 596
537 but the game must not exist and all the players must be in the room already. 604 but the game must not exist and all the players must be in the room already.
538 @param room_jid (jid.JID): JID of the room 605 @param room_jid (jid.JID): JID of the room
539 @param nicks (list[unicode]): list of players nicks in the room (referee included, in first position) 606 @param nicks (list[unicode]): list of players nicks in the room (referee included, in first position)
540 @param profile_key (unicode): %(doc_profile_key)s 607 @param profile_key (unicode): %(doc_profile_key)s
541 """ 608 """
542 log.debug(_(u"Creating %(game)s game in room %(room)s") % {'game': self.name, 'room': room_jid}) 609 log.debug(
610 _(u"Creating %(game)s game in room %(room)s")
611 % {"game": self.name, "room": room_jid}
612 )
543 profile = self.host.memory.getProfileName(profile_key) 613 profile = self.host.memory.getProfileName(profile_key)
544 if not profile: 614 if not profile:
545 log.error(_(u"profile %s is unknown") % profile_key) 615 log.error(_(u"profile %s is unknown") % profile_key)
546 return 616 return
547 (create, sync) = self._checkCreateGameAndInit(room_jid, profile) 617 (create, sync) = self._checkCreateGameAndInit(room_jid, profile)
549 nicks = [] 619 nicks = []
550 if not create: 620 if not create:
551 if sync: 621 if sync:
552 self._updatePlayers(room_jid, nicks, True, profile) 622 self._updatePlayers(room_jid, nicks, True, profile)
553 return 623 return
554 self.games[room_jid]['started'] = True 624 self.games[room_jid]["started"] = True
555 self._updatePlayers(room_jid, nicks, False, profile) 625 self._updatePlayers(room_jid, nicks, False, profile)
556 if self.player_init: 626 if self.player_init:
557 # specific data to each player (score, private data) 627 # specific data to each player (score, private data)
558 self.games[room_jid].setdefault('players_data', {}) 628 self.games[room_jid].setdefault("players_data", {})
559 for nick in nicks: 629 for nick in nicks:
560 # The dict must be COPIED otherwise it is shared between all users 630 # The dict must be COPIED otherwise it is shared between all users
561 self.games[room_jid]['players_data'][nick] = copy.deepcopy(self.player_init) 631 self.games[room_jid]["players_data"][nick] = copy.deepcopy(
632 self.player_init
633 )
562 634
563 def _playerReady(self, player_nick, referee_jid_s, profile_key=C.PROF_KEY_NONE): 635 def _playerReady(self, player_nick, referee_jid_s, profile_key=C.PROF_KEY_NONE):
564 self.playerReady(player_nick, jid.JID(referee_jid_s), profile_key) 636 self.playerReady(player_nick, jid.JID(referee_jid_s), profile_key)
565 637
566 def playerReady(self, player_nick, referee_jid, profile_key=C.PROF_KEY_NONE): 638 def playerReady(self, player_nick, referee_jid, profile_key=C.PROF_KEY_NONE):
571 """ 643 """
572 profile = self.host.memory.getProfileName(profile_key) 644 profile = self.host.memory.getProfileName(profile_key)
573 if not profile: 645 if not profile:
574 log.error(_(u"profile %s is unknown") % profile_key) 646 log.error(_(u"profile %s is unknown") % profile_key)
575 return 647 return
576 log.debug(u'new player ready: %s' % profile) 648 log.debug(u"new player ready: %s" % profile)
577 # TODO: we probably need to add the game and room names in the sent message 649 # TODO: we probably need to add the game and room names in the sent message
578 self.send(referee_jid, 'player_ready', {'player': player_nick}, profile=profile) 650 self.send(referee_jid, "player_ready", {"player": player_nick}, profile=profile)
579 651
580 def newRound(self, room_jid, data, profile): 652 def newRound(self, room_jid, data, profile):
581 """Launch a new round (reinit the user data) 653 """Launch a new round (reinit the user data)
582 654
583 @param room_jid: room userhost 655 @param room_jid: room userhost
584 @param data: a couple (common_data, msg_elts) with: 656 @param data: a couple (common_data, msg_elts) with:
585 - common_data: backend initialization data for the new round 657 - common_data: backend initialization data for the new round
586 - msg_elts: dict to map each user to his specific initialization message 658 - msg_elts: dict to map each user to his specific initialization message
587 @param profile 659 @param profile
588 """ 660 """
589 log.debug(_(u'new round for %s game') % self.name) 661 log.debug(_(u"new round for %s game") % self.name)
590 game_data = self.games[room_jid] 662 game_data = self.games[room_jid]
591 players = game_data['players'] 663 players = game_data["players"]
592 players_data = game_data['players_data'] 664 players_data = game_data["players_data"]
593 game_data['stage'] = "init" 665 game_data["stage"] = "init"
594 666
595 common_data, msg_elts = copy.deepcopy(data) if data is not None else (None, None) 667 common_data, msg_elts = copy.deepcopy(data) if data is not None else (None, None)
596 668
597 if isinstance(msg_elts, dict): 669 if isinstance(msg_elts, dict):
598 for player in players: 670 for player in players:
599 to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof: 671 to_jid = jid.JID(room_jid.userhost() + "/" + player) # FIXME: gof:
600 elem = msg_elts[player] if isinstance(msg_elts[player], domish.Element) else None 672 elem = (
673 msg_elts[player]
674 if isinstance(msg_elts[player], domish.Element)
675 else None
676 )
601 self.send(to_jid, elem, profile=profile) 677 self.send(to_jid, elem, profile=profile)
602 elif isinstance(msg_elts, domish.Element): 678 elif isinstance(msg_elts, domish.Element):
603 self.send(room_jid, msg_elts, profile=profile) 679 self.send(room_jid, msg_elts, profile=profile)
604 if common_data is not None: 680 if common_data is not None:
605 for player in players: 681 for player in players:
610 686
611 @param to_jid: JID of the recipient 687 @param to_jid: JID of the recipient
612 @return: the created element 688 @return: the created element
613 """ 689 """
614 type_ = "normal" if to_jid.resource else "groupchat" 690 type_ = "normal" if to_jid.resource else "groupchat"
615 elt = domish.Element((None, 'message')) 691 elt = domish.Element((None, "message"))
616 elt["to"] = to_jid.full() 692 elt["to"] = to_jid.full()
617 elt["type"] = type_ 693 elt["type"] = type_
618 elt.addElement(self.ns_tag) 694 elt.addElement(self.ns_tag)
619 return elt 695 return elt
620 696
630 started_elt = domish.Element((None, name)) 706 started_elt = domish.Element((None, name))
631 if players is None: 707 if players is None:
632 return started_elt 708 return started_elt
633 idx = 0 709 idx = 0
634 for player in players: 710 for player in players:
635 player_elt = domish.Element((None, 'player')) 711 player_elt = domish.Element((None, "player"))
636 player_elt.addContent(player) 712 player_elt.addContent(player)
637 player_elt['index'] = str(idx) 713 player_elt["index"] = str(idx)
638 idx += 1 714 idx += 1
639 started_elt.addChild(player_elt) 715 started_elt.addChild(player_elt)
640 return started_elt 716 return started_elt
641 717
642 def _sendElements(self, to_jid, data, profile=None): 718 def _sendElements(self, to_jid, data, profile=None):
685 761
686 def getHandler(self, client): 762 def getHandler(self, client):
687 return RoomGameHandler(self) 763 return RoomGameHandler(self)
688 764
689 765
690 class RoomGameHandler (XMPPHandler): 766 class RoomGameHandler(XMPPHandler):
691 implements(iwokkel.IDisco) 767 implements(iwokkel.IDisco)
692 768
693 def __init__(self, plugin_parent): 769 def __init__(self, plugin_parent):
694 self.plugin_parent = plugin_parent 770 self.plugin_parent = plugin_parent
695 self.host = plugin_parent.host 771 self.host = plugin_parent.host
696 772
697 def connectionInitialized(self): 773 def connectionInitialized(self):
698 self.xmlstream.addObserver(self.plugin_parent.request, self.plugin_parent.room_game_cmd, profile=self.parent.profile) 774 self.xmlstream.addObserver(
699 775 self.plugin_parent.request,
700 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): 776 self.plugin_parent.room_game_cmd,
777 profile=self.parent.profile,
778 )
779
780 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
701 return [disco.DiscoFeature(self.plugin_parent.ns_tag[0])] 781 return [disco.DiscoFeature(self.plugin_parent.ns_tag[0])]
702 782
703 def getDiscoItems(self, requestor, target, nodeIdentifier=''): 783 def getDiscoItems(self, requestor, target, nodeIdentifier=""):
704 return [] 784 return []