changeset 828:8f335c03eebb

plugins room_games, radiocol, libervia: small changes like refactorization to ease the maintenance
author souliane <souliane@mailoo.org>
date Fri, 17 Jan 2014 15:02:46 +0100 (2014-01-17)
parents 215a2cb15e2d
children 187d2443c82d
files src/plugins/plugin_misc_radiocol.py src/plugins/plugin_misc_room_game.py src/plugins/plugin_misc_tarot.py src/test/test_plugin_misc_room_game.py
diffstat 4 files changed, 73 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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', {})
--- 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 []
--- 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"]))