# HG changeset patch # User souliane # Date 1389967366 -3600 # Node ID 8f335c03eebb4d9388223bd234221b5ccbf6f815 # Parent 215a2cb15e2d47b95cd74bfbc2c1cb0988609eeb plugins room_games, radiocol, libervia: small changes like refactorization to ease the maintenance diff -r 215a2cb15e2d -r 8f335c03eebb src/plugins/plugin_misc_radiocol.py --- a/src/plugins/plugin_misc_radiocol.py Thu Jan 16 11:44:14 2014 +0100 +++ b/src/plugins/plugin_misc_radiocol.py Fri Jan 17 15:02:46 2014 +0100 @@ -235,27 +235,19 @@ else: error(_('Unmanaged game element: %s') % elt.name) - def getSyncData(self, room_jid_s, force_nicks=[]): - data = {} + def getSyncDataForPlayer(self, room_jid_s, nick): game_data = self.games[room_jid_s] - status = game_data['status'] - nicks = [nick for nick in status if status[nick] == 'desync'] - for nick in force_nicks: - if nick not in nicks: - nicks.append(nick) - for nick in nicks: - elements = [] - if game_data['playing']: - preload = copy.deepcopy(game_data['playing']) - preload['filename'] += '#t=%.2f' % (time.time() - game_data['playing_time']) - elements.append(preload) - play = domish.Element(('', 'play')) - play['filename'] = preload['filename'] - elements.append(play) - if len(game_data['queue']) > 0: - elements.extend(copy.deepcopy(game_data['queue'])) - if len(game_data['queue']) == QUEUE_LIMIT: - elements.append(domish.Element(('', 'no_upload'))) - if data: - data[nick] = elements - return data + elements = [] + if game_data['playing']: + preload = copy.deepcopy(game_data['playing']) + current_time = game_data['playing_time'] + 1 if self.testing else time.time() + preload['filename'] += '#t=%.2f' % (current_time - game_data['playing_time']) + elements.append(preload) + play = domish.Element(('', 'play')) + play['filename'] = preload['filename'] + elements.append(play) + if len(game_data['queue']) > 0: + elements.extend(copy.deepcopy(game_data['queue'])) + if len(game_data['queue']) == QUEUE_LIMIT: + elements.append(domish.Element(('', 'no_upload'))) + return elements diff -r 215a2cb15e2d -r 8f335c03eebb src/plugins/plugin_misc_room_game.py --- a/src/plugins/plugin_misc_room_game.py Thu Jan 16 11:44:14 2014 +0100 +++ b/src/plugins/plugin_misc_room_game.py Fri Jan 17 15:02:46 2014 +0100 @@ -108,14 +108,19 @@ self.join_mode = self.INVITED self.ready_mode = self.FORCE # TODO: asking for confirmation is not implemented + # this has been added for testing purpose. It is sometimes needed to remove a dependence + # while building the synchronization data, for example to replace a call to time.time() + # by an arbitrary value. If needed, this attribute would be set to True from the testcase. + self.testing = False + host.trigger.add("MUC user joined", self.userJoinedTrigger) host.trigger.add("MUC user left", self.userLeftTrigger) def _createOrInvite(self, room, other_players, profile): """ This is called only when someone explicitly wants to play. - The game must not be created if one already exists in the room, - and its creation could be postponed until all the expected players + The game will not be created if one already exists in the room, + also its creation could be postponed until all the expected players join the room (in that case it will be created from userJoinedTrigger). @param room: instance of wokkel.muc.Room @param other_players: list for other players JID userhosts @@ -128,7 +133,7 @@ if not self._checkJoinAuth(room_jid_s, user_jid.userhost(), nick): return nicks.extend(self._invitePlayers(room, other_players, nick, profile)) - self._updatePlayers(room_jid_s, nicks, profile) + self._updatePlayers(room_jid_s, nicks, True, profile) else: self._initGame(room_jid_s, nick) (auth, waiting, missing) = self._checkWaitAuth(room, other_players) @@ -137,7 +142,7 @@ if auth: self.createGame(room_jid_s, nicks, profile) else: - self._updatePlayers(room_jid_s, nicks, profile) + self._updatePlayers(room_jid_s, nicks, False, profile) def _initGame(self, room_jid_s, referee_nick): """Important: do not add the referee to 'players' yet. For a @@ -191,11 +196,14 @@ debug(_("%s not allowed to join the game %s in %s") % (user_jid_s or nick, self.name, room_jid_s)) return auth - def _updatePlayers(self, room_jid_s, nicks, profile): + def _updatePlayers(self, room_jid_s, nicks, sync, profile): """Update the list of players and signal to the room that some players joined the game. + If sync is True, the news players are synchronized with the game data they have missed. Remark: self.games[room_jid_s]['players'] should not be modified outside this method. @param room_jid_s: room userhost @param nicks: list of players nicks in the room (referee included, in first position) + @param sync: set to True to send synchronization data to the new players + @param profile """ if nicks == []: return @@ -203,12 +211,12 @@ new_nicks = [nick for nick in nicks if nick not in self.games[room_jid_s]['players']] if len(new_nicks) == 0: return - sync = self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0 def setStatus(status): for nick in new_nicks: self.games[room_jid_s]['status'][nick] = status + sync = sync and self._gameExists(room_jid_s, True) and len(self.games[room_jid_s]['players']) > 0 setStatus('desync' if sync else 'init') self.games[room_jid_s]['players'].extend(new_nicks) self._synchronizeRoom(room_jid_s, [JID(room_jid_s)], profile) @@ -231,7 +239,7 @@ elements = [(element, None, None)] sync_args = [] - sync_data = self.getSyncData(room_jid_s) + sync_data = self._getSyncData(room_jid_s) for nick in sync_data: user_jid = JID(room_jid_s + '/' + nick) if user_jid in recipients: @@ -248,16 +256,35 @@ for args, kwargs in sync_args: self._sendElements(*args, **kwargs) - def getSyncData(self, room_jid_s, force_nicks=[]): - """This method may (and should probably) be overwritten by a child class. - The synchronization data are returned for each player who has the state - 'desync' or if he's been contained by force_nicks. + def _getSyncData(self, room_jid_s, force_nicks=[]): + """The synchronization data are returned for each player who + has the state 'desync' or if he's been contained by force_nicks. @param room_jid_s: room userhost @param force_nicks: force the synchronization for this list of the nicks - @return: a mapping between player nicks and a list of child elements - to be sent by self._synchronizeRoom for the game to be synchronized. + @return: a mapping between player nicks and a list of elements to + be sent by self._synchronizeRoom for the game to be synchronized. """ - return {} + if not self._gameExists(room_jid_s): + return {} + data = {} + status = self.games[room_jid_s]['status'] + nicks = [nick for nick in status if status[nick] == 'desync'] + for nick in force_nicks: + if nick not in nicks: + nicks.append(nick) + for nick in nicks: + elements = self.getSyncDataForPlayer(room_jid_s, nick) + if elements: + data[nick] = elements + return data + + def getSyncDataForPlayer(self, room_jid_s, nick): + """This method may (and should probably) be overwritten by a child class. + @param room_jid_s: room userhost + @param nick: the nick of the player to be synchronized + @return: a list of elements to synchronize this player with the game. + """ + return [] def _invitePlayers(self, room, other_players, nick, profile): """Invite players to a room, associated game may exist or not. @@ -424,7 +451,7 @@ self.createGame(room_jid_s, nicks, profile_key=profile) return True # let the room know that a new player joined - self._updatePlayers(room_jid_s, [user.nick], profile) + self._updatePlayers(room_jid_s, [user.nick], True, profile) return True def userLeftTrigger(self, room, user, profile): @@ -442,6 +469,9 @@ self.games[room_jid_s]['players'].remove(user.nick) except ValueError: pass + if len(self.games[room_jid_s]['players']) == 0: + del self.games[room_jid_s] # finish the game + return True if self.wait_mode == self.FOR_ALL: # allow this user to join the game again user_jid_s = user.entity.userhost() @@ -493,11 +523,10 @@ (create, sync) = self._checkCreateGameAndInit(room_jid_s, profile) if not create: if sync: - debug(_('Synchronize game %s in %s for %s') % (self.name, room_jid_s, ', '.join(nicks))) - self._updatePlayers(room_jid_s, nicks, profile) + self._updatePlayers(room_jid_s, nicks, True, profile) return self.games[room_jid_s]['started'] = True - self._updatePlayers(room_jid_s, nicks, profile) + self._updatePlayers(room_jid_s, nicks, False, profile) if self.player_init: # specific data to each player (score, private data) self.games[room_jid_s].setdefault('players_data', {}) diff -r 215a2cb15e2d -r 8f335c03eebb src/plugins/plugin_misc_tarot.py --- a/src/plugins/plugin_misc_tarot.py Thu Jan 16 11:44:14 2014 +0100 +++ b/src/plugins/plugin_misc_tarot.py Fri Jan 17 15:02:46 2014 +0100 @@ -631,5 +631,5 @@ else: error(_('Unmanaged card game element: %s') % elt.name) - def getSyncData(self, room_jid_s): - return {} + def getSyncDataForPlayer(self, room_jid_s, nick): + return [] diff -r 215a2cb15e2d -r 8f335c03eebb src/test/test_plugin_misc_room_game.py --- a/src/test/test_plugin_misc_room_game.py Thu Jan 16 11:44:14 2014 +0100 +++ b/src/test/test_plugin_misc_room_game.py Fri Jan 17 15:02:46 2014 +0100 @@ -129,32 +129,32 @@ self.init() self.initGame(0, 0) self.assertEqual(self.plugin.games[ROOM_JID_S]['players'], []) - self.plugin._updatePlayers(ROOM_JID_S, [], Const.PROFILE[0]) + self.plugin._updatePlayers(ROOM_JID_S, [], True, Const.PROFILE[0]) self.assertEqual(self.plugin.games[ROOM_JID_S]['players'], []) - self.plugin._updatePlayers(ROOM_JID_S, ["user1"], Const.PROFILE[0]) + self.plugin._updatePlayers(ROOM_JID_S, ["user1"], True, Const.PROFILE[0]) self.assertEqual(self.plugin.games[ROOM_JID_S]['players'], ["user1"]) - self.plugin._updatePlayers(ROOM_JID_S, ["user2", "user3"], Const.PROFILE[0]) + self.plugin._updatePlayers(ROOM_JID_S, ["user2", "user3"], True, Const.PROFILE[0]) self.assertEqual(self.plugin.games[ROOM_JID_S]['players'], ["user1", "user2", "user3"]) - self.plugin._updatePlayers(ROOM_JID_S, ["user2", "user3"], Const.PROFILE[0]) # should not be stored twice + self.plugin._updatePlayers(ROOM_JID_S, ["user2", "user3"], True, Const.PROFILE[0]) # should not be stored twice self.assertEqual(self.plugin.games[ROOM_JID_S]['players'], ["user1", "user2", "user3"]) - def test_signalPlayers(self): + def test_synchronizeRoom(self): self.init() self.initGame(0, 0) - self.plugin._signalPlayers(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) + self.plugin._synchronizeRoom(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) self.assertEqual(self.host.getSentMessage(0, 0), self.expectedMessage(ROOM_JID_S, "groupchat", "players", [])) self.plugin.games[ROOM_JID_S]['players'].append("test1") - self.plugin._signalPlayers(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) + self.plugin._synchronizeRoom(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) self.assertEqual(self.host.getSentMessage(1, 0), self.expectedMessage(ROOM_JID_S, "groupchat", "players", ["test1"])) self.plugin.games[ROOM_JID_S]['started'] = True self.plugin.games[ROOM_JID_S]['players'].append("test2") - self.plugin._signalPlayers(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) + self.plugin._synchronizeRoom(ROOM_JID_S, [Const.MUC[0]], Const.PROFILE[0]) self.assertEqual(self.host.getSentMessage(2, 0), self.expectedMessage(ROOM_JID_S, "groupchat", "started", ["test1", "test2"])) self.plugin.games[ROOM_JID_S]['players'].append("test3") self.plugin.games[ROOM_JID_S]['players'].append("test4") user1 = JID(ROOM_JID_S + "/" + Const.JID[0].user) user2 = JID(ROOM_JID_S + "/" + Const.JID[1].user) - self.plugin._signalPlayers(ROOM_JID_S, [user1, user2], Const.PROFILE[0]) + self.plugin._synchronizeRoom(ROOM_JID_S, [user1, user2], Const.PROFILE[0]) self.assertEqualXML(self.host.getSentMessage(3, 0), self.expectedMessage(user1.full(), "normal", "started", ["test1", "test2", "test3", "test4"])) self.assertEqualXML(self.host.getSentMessage(4, 0), self.expectedMessage(user2.full(), "normal", "started", ["test1", "test2", "test3", "test4"]))