Пример #1
0
    def testEnoughTurnsPlayed(self):
        txq = asyncio.Queue()
        wordset = SupportedWordSets["test"]

        allConns = Connections(txq)
        team1 = mockPlyrTeam(txq, allConns, 1, {"sb": [101]}, {"sb": 2})
        team2 = mockPlyrTeam(txq, allConns, 2, {"jg": [102]}, {"jg": 2})

        teams = {1: team1, 2: team2}
        hostParameters = HostParameters(numTeams=2,
                                        turnDurationSec=30,
                                        wordSets=["test"],
                                        numTurns=2)

        for team in teams.values():
            for ws in team.conns._wss:
                allConns.addConn(ws)

        turnMgr = TurnManager("taboo:1", txq, wordset, teams, hostParameters, allConns, None)

        self.assertFalse(turnMgr.startNewTurn())
        self.assertGiTxQueueMsgs(txq, [
            ClientTxMsg(['PLAYER-STATUS', 'jg', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(['PLAYER-STATUS', 'sb', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(['PLAYER-STATUS', 'jg', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {102}),
            ClientTxMsg(['PLAYER-STATUS', 'sb', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {102}),
            ClientTxMsg(["SCORE", {1: 0, 2: 0}],
                        {101, 102}),
        ], anyOrder=True)
Пример #2
0
    def testAddConnectionsBeforeMsgSrc(self):
        conns1 = Connections(self.txq)
        conns2 = Connections(self.txq)
        conns2.addConn(clientWs2)

        self.assertGiTxQueueMsgs(self.txq, [])

        self.conns.addConnections(conns1)
        self.assertGiTxQueueMsgs(self.txq, [])

        self.conns.addConnections(conns2)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Add message sources

        # message source with no messages
        msgSrcEmpty = MsgSrc(self.conns)  # pylint: disable=unused-variable
        self.assertGiTxQueueMsgs(self.txq, [])

        msgSrc = MsgSrc(self.conns)
        msgSrc.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3)
        ])
Пример #3
0
class TabooPlayer:
    def __init__(self, txQueue, allConns, name, team, turnsPlayed=0):
        """ Creates a taboo player associated to a team. Self-registers to the team

        txQueue: tx queue
        allConns: Connections with all clients in the room
        name: player name
        team: team that this player should belong to
        """
        self.name = name
        self.team = team
        self.turnsPlayed = turnsPlayed

        self.__ready = False
        self.playerConns = Connections(txQueue)
        team.addPlayer(self)

        self.playerStatusMsgSrc = MsgSrc(allConns)

    def __str__(self):
        return "TabooPlayer({}) teamId={}, turnsPlayed={}".format(
            self.name, self.team.teamNumber, self.turnsPlayed)

    def addConn(self, ws):
        self.playerConns.addConn(ws)
        self.team.conns.addConn(ws)
        self._updateMsgSrc()

    def delConn(self, ws):
        self.playerConns.delConn(ws)
        self.team.conns.delConn(ws)
        self._updateMsgSrc()

    @property
    def ready(self):
        return self.__ready

    @ready.setter
    def ready(self, flag):
        self.__ready = flag
        self._updateMsgSrc()

    def incTurnsPlayed(self):
        self.turnsPlayed += 1

    def numConns(self):
        return self.playerConns.count()

    def _updateMsgSrc(self):
        self.playerStatusMsgSrc.setMsgs([
            Jmai([
                "PLAYER-STATUS", self.name, {
                    "numConns": self.numConns(),
                    "ready": self.ready,
                    "turnsPlayed": self.turnsPlayed,
                }
            ], None),
        ])
Пример #4
0
 def setRxTxQueues(self, rxQueue, txQueue):
     """Setup RX and TX queue for a plugin"""
     assert not self.rxQueue
     assert not self.txQueue
     assert rxQueue
     assert txQueue
     self.rxQueue = rxQueue
     self.txQueue = txQueue
     self.conns = Connections(self.txQueue)
     self.postQueueSetup()
Пример #5
0
    def __init__(self, txQueue, allConns, name, team, turnsPlayed=0):
        """ Creates a taboo player associated to a team. Self-registers to the team

        txQueue: tx queue
        allConns: Connections with all clients in the room
        name: player name
        team: team that this player should belong to
        """
        self.name = name
        self.team = team
        self.turnsPlayed = turnsPlayed

        self.__ready = False
        self.playerConns = Connections(txQueue)
        team.addPlayer(self)

        self.playerStatusMsgSrc = MsgSrc(allConns)
Пример #6
0
    def testBasic(self):
        txq = asyncio.Queue()
        wordset = SupportedWordSets["test"]
        with stub(wordset, "nextWord", self.mockNextWord):
            allConns = Connections(txq)
            team1 = mockPlyrTeam(txq, allConns, 1, {"sb1": [101], "sb2": [102]}, {})
            team2 = mockPlyrTeam(txq, allConns, 2, {"jg1": [201], "jg2": [202]}, {})

            teams = {1: team1, 2: team2}
            hostParameters = HostParameters(numTeams=2,
                                            turnDurationSec=30,
                                            wordSets=["test"],
                                            numTurns=2)

            for team in teams.values():
                for ws in team.conns._wss:
                    allConns.addConn(ws)
            self.drainGiTxQueue(txq)

            turnMgr = TurnManager("taboo:1", txq, wordset, teams, hostParameters, allConns, None)
            def mockFindNextPlayer():
                return team2.members["jg1"]
            stub1 = stub(turnMgr, "_findNextPlayer", mockFindNextPlayer)
            stub1.__enter__() # pylint: disable=no-member

            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(["SCORE", {1: 0, 2: 0}],
                            {101, 102, 201, 202}),
            ], anyOrder=True)

            self.assertTrue(turnMgr.startNewTurn())
            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(["WAIT-FOR-KICKOFF", 1, "jg1"], {101, 102, 201, 202}, None),
            ])

            self.assertTrue(turnMgr.startNextWord())
            secretMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': None,  # We didn't send KICKOFF explicitly
                                        'secret': 'c', 'disallowed': ['c1', 'c2']}]
            publicMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': None}]
            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(publicMsg, {101, 102, 201, 202}),
                ClientTxMsg(secretMsg, {101, 102}),
                ClientTxMsg(secretMsg, {201}),
            ], anyOrder=True)
Пример #7
0
    def __init__(self, txQueue, allConns, teamNumber):
        self.txQueue = txQueue
        self.teamNumber = teamNumber

        self.teamStatusMsgSrc = MsgSrc(allConns)

        self.members = {}
        self.conns = Connections(self.txQueue)
        self._updateMsgSrc()
Пример #8
0
def mockPlyrTeam(txq, allConns, teamId : int,
                 connsByPlayerName,
                 turnsPlayedByPlayerName=None):
    turnsPlayedByPlayerName = turnsPlayedByPlayerName or {}

    team = TabooTeam(txq, Connections(txq), teamId)
    for plyrName, conns in connsByPlayerName.items():
        plyr = TabooPlayer(txq, allConns, name=plyrName, team=team)
        for ws in conns:
            plyr.addConn(ws)
        plyr.turnsPlayed = turnsPlayedByPlayerName.get(plyrName, 0)
    return team
Пример #9
0
    def setUpWord(self, turnId=1, wordId=1,
                  secret=None, disallowed=None,
                  player=None, otherTeams=None,
                  allConns=None,
                  state=WordState.IN_PLAY,
                  utcTimeout=30,
                  score=None,
                  playerName="sb", playerTeamNum=1, playerWss=None,
                  otherTeamNum=2, otherTeamWss=None):
        # pylint: disable=too-many-locals
        secret = secret or "a"
        disallowed = disallowed or ["a1", "a2"]

        playerWss = playerWss or {101} # 1 player
        otherTeamWss = otherTeamWss or {102} # 1 other team member

        allConns = Connections(self.txq)
        for ws in playerWss | otherTeamWss | {103}: # 1 spectator added
            allConns.addConn(ws)

        playerTeam = TabooTeam(self.txq, allConns, playerTeamNum)
        player = TabooPlayer(self.txq, allConns, name=playerName, team=playerTeam)
        for ws in playerWss:
            player.addConn(ws)

        otherTeam = TabooTeam(self.txq, allConns, otherTeamNum)
        for ws in otherTeamWss:
            otherTeam.conns.addConn(ws)

        otherTeams = [otherTeam]
        score = score or []

        return Word(turnId=turnId, wordId=wordId,
                    secret=secret, disallowed=disallowed,
                    player=player, otherTeams=otherTeams,
                    allConns=allConns,
                    utcTimeout=utcTimeout,
                    state=state,
                    score=score)
Пример #10
0
    def testNoClients(self):
        txq = asyncio.Queue()
        wordset = SupportedWordSets["test"]
        allConns = Connections(txq)

        team1 = mockPlyrTeam(txq, allConns, 1, {"sb": []})
        team2 = mockPlyrTeam(txq, allConns, 2, {"jg": []})

        teams = {1: team1, 2: team2}
        hostParameters = HostParameters(numTeams=2,
                                        turnDurationSec=30,
                                        wordSets=["test"],
                                        numTurns=1)

        for team in teams.values():
            for ws in team.conns._wss:
                allConns.addConn(ws)

        turnMgr = TurnManager("taboo:1", txq, wordset, teams, hostParameters, allConns, None)

        self.assertFalse(turnMgr.startNewTurn())
        self.assertGiTxQueueMsgs(txq, [])
Пример #11
0
class Plugin:
    """
    Base game instance that is registered with the main loop by the name "path".
    """
    def __init__(self, path, name, storage=None):
        """
        Arguments
        ---------
        path : str
            Path to reach this instance. For example,
                "lobby"
                "chat"  --  chat room's lobby
                "chat:1"  --  chat room id 1
                "chat:2"  --  chat room id 2
        storage : Storage (optional)
        """
        self.path = path
        self.name = name
        self.storage = storage

        self.rxQueue = None
        self.txQueue = None
        self.conns = None

    # ---------------------------------
    # Startup related

    def postQueueSetup(self):
        """Additional logic to run after RX and TX queues are
        setup for a plugin"""

    def setRxTxQueues(self, rxQueue, txQueue):
        """Setup RX and TX queue for a plugin"""
        assert not self.rxQueue
        assert not self.txQueue
        assert rxQueue
        assert txQueue
        self.rxQueue = rxQueue
        self.txQueue = txQueue
        self.conns = Connections(self.txQueue)
        self.postQueueSetup()

    # ---------------------------------
    # Message sending helpers

    def broadcast(self, jmsg, initiatorWs=None):
        """Send a message to all clients of a Plugin"""
        self.conns.send([Jmai(jmsg, initiatorWs)])

    # ---------------------------------
    # Message handling

    def postProcessConnect(self, ws):
        """Additional logic to run after a ws connects"""

    def processConnect(self, ws):
        """Add client websocket as a member in this game instance"""
        self.conns.addConn(ws)
        self.postProcessConnect(ws)

    def postProcessDisconnect(self, ws):
        """Additional logic to run after a ws disconnects"""

    def processDisconnect(self, ws):
        """Remove client websocket as a member in this game instance"""
        self.conns.delConn(ws)
        self.postProcessDisconnect(ws)

    def processMsg(self, qmsg):
        """Act to on the received msg.

        Return value : bool
            True => msg was handled
            False => msg was handled
        """
        if isinstance(qmsg, InternalConnectWsToGi):
            self.processConnect(qmsg.ws)
            return True

        if isinstance(qmsg, InternalDisconnectWsToGi):
            self.processDisconnect(qmsg.ws)
            return True

        return False

    async def worker(self):
        """The worker task for a plugin. All messages should be processed.
        Any unhandled message returns a bad message to the sender"""
        trace(Level.game, "{}.worker() ready".format(self.path))
        while True:
            qmsg = await self.rxQueue.get()
            self.rxQueue.task_done()
            trace(Level.msg, self.path, "received", str(qmsg))

            processed = self.processMsg(qmsg)
            if not processed:
                if not isinstance(qmsg, ClientRxMsg):
                    trace(Level.error, "Unexpected message not handled:",
                          str(qmsg))
                    continue
                self.txQueue.put_nowait(
                    ClientTxMsg("Bad message", {qmsg.initiatorWs},
                                initiatorWs=qmsg.initiatorWs))
Пример #12
0
 def setUp(self):
     self.txq = asyncio.Queue()
     self.conns = Connections(self.txq)
Пример #13
0
class MsgSrcConnectionsTest(unittest.TestCase, MsgTestLib):
    """Test MsgSrc and Connections

    MsgSrc1 --> +-------------+
                |             | --> Websocket1
    MsgSrc2 --> | Connections |
                |             | --> Websocket2
    MsgSrc3 --> +-------------+
    """
    def setUp(self):
        self.txq = asyncio.Queue()
        self.conns = Connections(self.txq)

    def test1MsgSrc1Websocket(self):
        """
        Try various triggers of adding/removing MsgSrcs and Websockets
        """
        self.assertGiTxQueueMsgs(self.txq, [])

        # Adding connections doesn't create a message
        self.conns.addConn(clientWs1)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Adding msgSrc with no messages
        msgSrc1 = MsgSrc(self.conns)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Set messages in msgSrc
        msgSrc1.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs1}, initiatorWs=clientWs3)
        ])

        # Adding msgSrc with previous messages
        msgSrc2 = MsgSrc(self.conns)
        msgSrc2.setMsgs(
            [Jmai([True], initiatorWs=None),
             Jmai([False], initiatorWs=None)])
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([True], {clientWs1}),
            ClientTxMsg([False], {clientWs1})
        ])

        # Adding a second connection
        self.conns.addConn(clientWs2)
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([True], {clientWs2}, initiatorWs=None),
            ClientTxMsg([False], {clientWs2}, initiatorWs=None)
        ],
                                 anyOrder=True)

        # Adding msgSrc with state preset
        msgSrc2.setMsgs([Jmai(["yes"], initiatorWs=None)])
        self.assertGiTxQueueMsgs(
            self.txq, [ClientTxMsg(["yes"], {clientWs1, clientWs2})])

        # Delete msgSrc
        self.conns.delMsgSrc(msgSrc2)

        # Add another client
        self.conns.addConn(clientWs3)
        self.assertSetEqual(self.conns.msgSrcs, {msgSrc1})
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs3}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs3}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)

        # Remove a client
        self.conns.delConn(clientWs2)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Add msgSrc2 again
        self.conns.addMsgSrc(msgSrc2)
        self.assertGiTxQueueMsgs(
            self.txq,
            [ClientTxMsg(["yes"], {clientWs1, clientWs3}, initiatorWs=None)],
            anyOrder=True)
Пример #14
0
    def testAddDelConnections(self):
        conns1 = Connections(self.txq)
        conns1.addConn(clientWs1)
        conns2 = Connections(self.txq)
        conns2.addConn(clientWs2)

        self.conns.addConnections(conns1)
        self.conns.addConnections(conns2)

        msgSrc = MsgSrc(self.conns)
        msgSrc.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])

        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)

        self.conns.delConnections(conns1)

        clientWs4 = 104
        conns3 = Connections(self.txq)
        conns3.addConn(clientWs3)
        conns3.addConn(clientWs4)

        self.conns.addConnections(conns3)

        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs3, clientWs4}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs3, clientWs4}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)
Пример #15
0
 def __init__(self, txQueue, name, passwd):
     self.name = name
     self.passwd = passwd
     self.playerConns = Connections(txQueue)