Example #1
0
    def rpc_restart(self, sender, *args):
        """rpc_restart() -> str

        Immediately shut down this Factory and all bots.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'restart: no arguments')
        if (not self.factory.canrestart):
            raise rpc.RPCFault(609, 'restart: no restart-script available')
        self.factory.queueaction(self.factory.requeststop, False, True)
        return 'restarting factory immediately'
Example #2
0
    def precondition(self, sender, namehead, nametail, *callargs):
        """precondition(sender, namehead, nametail, *callargs)

        Check the sender before an RPC handler. Only referees can send RPCs
        to a bot.
        """
        
        if (self.actor.state != 'running'):
            raise rpc.RPCFault(609, 'bot not ready for RPCs')

        if (sender != self.actor.refereejid):
            raise rpc.RPCFault(607, 'sender is not referee')
Example #3
0
    def rpc_graceful_restart(self, sender, *args):
        """rpc_graceful_restart() -> str

        Shut down this Parlor, but leave tables operating.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'graceful_restart: no arguments')
        if (not self.parlor.canrestart):
            raise rpc.RPCFault(609, 'restart: no restart-script available')
        self.parlor.queueaction(self.parlor.requeststop, True, True)
        return 'restarting parlor gracefully'
Example #4
0
    def newbot(self, sender, *args):
        """newbot(sender, uri, tablejid) -> <RPC outcome>

        Create a new bot, and have it join the given table. The RPC
        response will be the bot's full JID, but that doesn't happen in this
        function; see the botready() callback.
        """
        
        if (len(args) != 2):
            raise rpc.RPCFault(604, 'new_bot takes two arguments')
        if (not type(args[0]) in (str, unicode)):
            raise rpc.RPCFault(605, 'new_bot: first argument must be string')
        if (not type(args[1]) in (str, unicode)):
            raise rpc.RPCFault(605, 'new_bot: second argument must be string')
        uri = args[0]
        tablejidstr = args[1]
        tablejid = interface.JID(tablejidstr)

        if (self.state != 'ready'):
            raise rpc.RPCFault(609, 'factory is not yet ready')

        if (not self.online):
            raise volent.FailureToken('volity.offline')

        found = False
        for botclass in self.botclasses:
            if (botclass.boturi == uri):
                found = True
                break
        if (not found):
            raise volent.FailureToken('volity.bot_not_available')
        
        self.log.info('new bot requested by %s (%s)...', unicode(sender),
            botclass.boturi)

        botresource = 'bot_' + str(os.getpid()) + '_' + str(self.uniquestamp())
        
        # The player-visible name of the bot shouldn't conflict with existing
        # MUC nicknames. We will do collision detection when we join the MUC,
        # but some MUC servers get crashy when you do that (in cases which
        # we haven't diagnosed yet). So we make a rough attempt to start
        # with a never-before-used name.
        botnick = 'Bot ' + str(self.botcounter)
        self.botcounter += 1

        try:
            act = actor.Actor(self, sender, self.jid, self.password,
                tablejid, botresource, botnick, botclass)
        except Exception, ex:
            self.log.error('Unable to create bot',
                exc_info=True)
            raise rpc.RPCFault(608,
                'unable to create bot: ' + str(ex))
Example #5
0
    def rpc_restart(self, sender, *args):
        """rpc_restart() -> str

        Immediately shut down this Parlor and all tables. This kills all
        open games, so use it considerately.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'restart: no arguments')
        if (not self.parlor.canrestart):
            raise rpc.RPCFault(609, 'restart: no restart-script available')
        self.parlor.queueaction(self.parlor.requeststop, False, True)
        return 'restarting parlor immediately'
Example #6
0
    def rpc_status(self, sender, *args):
        """rpc_status() -> dict

        Return assorted status information. This returns a Jabber-RPC struct
        containing these fields:

            online: Whether the Parlor is online.
            startup_time: When the Parlor was started.
            startup_at: How long ago the Parlor was started.
            last_new_table: How long ago it's been since a table was started.
            tables_running: How many tables are currently open.
            tables_started: How many tables have been started since the
                Parlor began.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'status: no arguments')
        dic = {}
        dic['online'] = self.parlor.online
        dic['startup_time'] = time.ctime(self.parlor.startuptime)
        dic['startup_at'] = volent.descinterval(self.parlor.startuptime,
                                                limit=2)
        dic['last_new_table'] = volent.descinterval(self.parlor.activitytime,
                                                    limit=2)
        dic['tables_running'] = len(self.parlor.referees)
        dic['tables_started'] = self.parlor.refereesstarted

        return dic
Example #7
0
    def __call__(self, sender, callname, *callargs):
        """__call__(sender, callname, *callargs) -> <rpc outcome>

        Invoke an RPC. This is invoked by the Zymb RPC-handling service.
        The CallNotFound exception is trapped and turned into a silent
        success.
        """
        
        try:
            return rpc.MethodOpset.__call__(self, sender, callname, *callargs)
        except rpc.CallNotFound:
            # unimplemented methods are assumed to return quietly.
            return None
        except rpc.RPCResponse:
            raise
        except rpc.RPCFault:
            raise
        except interface.StanzaError:
            raise
        except Exception, ex:
            st = str(ex.__class__) + ': ' + str(ex)
            self.actor.log.error(
                'uncaught exception in volity opset: %s (from %s)',
                unicode(sender), callname,
                exc_info=True)
            raise rpc.RPCFault(608, st)
Example #8
0
    def rpc_status(self, sender, *args):
        """rpc_status() -> dict

        Return assorted status information. This returns a Jabber-RPC struct
        containing these fields:

            referee: The JID of the bot's referee.
            refstate: The bot's view of the referee state.
            seat: The seat ID the bot is sitting in, or ''.
            gameseatlist: The list of seats which are involved in the current
                game, if there is one.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'status: no arguments')
        dic = {}
        dic['referee'] = unicode(self.actor.refereejid)
        dic['refstate'] = self.actor.refstate
        dic['seat'] = ''
        if (self.actor.seat):
            dic['seat'] = self.actor.seat.id
        ls = self.actor.bot.getgameseatlist()
        if (ls != None):
            dic['gameseatlist'] = [ seat.id for seat in ls ]

        return dic
Example #9
0
    def rpc_status(self, sender, *args):
        """rpc_status() -> dict

        Return assorted status information. This returns a Jabber-RPC struct
        containing these fields:

            online: Whether the Factory is online.
            startup_time: When the Factory was started.
            startup_at: How long ago the Factory was started.
            last_new_bot: How long ago it's been since a bot was started.
            bots_running: How many bots are currently open.
            bots_started: How many bots have been started since the
                Factory began.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'status: no arguments')
        dic = {}
        dic['online'] = self.factory.online
        dic['startup_time'] = time.ctime(self.factory.startuptime)
        dic['startup_at'] = volent.descinterval(
            self.factory.startuptime,
            limit=2)
        dic['last_new_bot'] = volent.descinterval(
            self.factory.activitytime,
            limit=2)
        dic['bots_running'] = len(self.factory.actors)
        dic['bots_started'] = self.factory.actorsstarted
        
        return dic
Example #10
0
    def rpc_get_info(self, sender, *args):
        """rpc_get_info() -> dict

        Return the same information as the <x> part of a disco#info
        query.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'get_info takes no arguments')

        if (self.parlor.state != 'ready'):
            raise rpc.RPCFault(609, 'parlor is not yet ready')

        dic = {}
        for tup in self.parlor.dataform.getfields():
            dic[tup[0]] = tup[1]
        return dic
Example #11
0
    def rpc_list_bots(self, sender, *args):
        """rpc_list_bots() -> list

        Return a list of running bots (on all tables).
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'list_bots: no arguments')
        return self.parlor.actors.keys()
Example #12
0
    def precondition(self, sender, namehead, nametail, *callargs):
        """precondition(sender, namehead, nametail, *callargs)

        Check the sender before an RPC handler. Only referees can send RPCs
        to a bot.
        """
        
        if (self.actor.state != 'running'):
            raise rpc.RPCFault(609, 'bot not ready for RPCs')

        # Anyone can send get_info().
        mustberef = (not (namehead in ['get_info']))
        
        # Actually, the bookkeeper can send a few of these.
        if (mustberef and
            sender != self.actor.refereejid and
            sender != self.actor.bookkeeperjid):
            raise rpc.RPCFault(607, 'sender is not referee')
Example #13
0
    def rpc_shutdown(self, sender, *args):
        """rpc_shutdown() -> str

        Immediately shut down this Actor.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'shutdown: no arguments')
        self.actor.queueaction(self.actor.stop)
        return 'stopping actor'
Example #14
0
    def rpc_list_bots(self, sender, *args):
        """rpc_list_bots() -> list

        Return a list of open bot IDs.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'list_bots: no arguments')
        ls = [ act.jid for act in self.factory.actors.values() ]
        return ls
Example #15
0
    def rpc_shutdown(self, sender, *args):
        """rpc_shutdown() -> str

        Immediately shut down this Factory and all bots.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'shutdown: no arguments')
        self.factory.queueaction(self.factory.requeststop, False, False)
        return 'stopping factory immediately'
Example #16
0
    def botready(self, act, res):
        """botready(act, res) -> <RPC outcome>

        Callback invoked when an Actor is successfully (or unsuccessfully)
        created. This is the continuation of newbot(). The *act* is
        the Actor object that was created, and *res* is either 'running',
        'end', or 'timeout'.
        """
        
        if (res == 'timeout'):
            self.log.warning('bot %s failed to start up in time -- killing', act.resource)
            act.stop()
            raise rpc.RPCFault(608, 'unable to start bot')
        if (res == 'end'):
            self.log.warning('bot %s died before responding', act.resource)
            raise rpc.RPCFault(608, 'bot failed to start up')
        self.activitytime = time.time()
        self.actorsstarted += 1
        return unicode(act.jid)
Example #17
0
    def rpc_graceful_shutdown(self, sender, *args):
        """rpc_graceful_shutdown() -> str

        Shut down this Factory, but leave bots operating.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'graceful_shutdown: no arguments')
        self.factory.queueaction(self.factory.requeststop, True, False)
        return 'stopping factory gracefully'
Example #18
0
    def rpc_graceful_shutdown(self, sender, *args):
        """rpc_graceful_shutdown() -> str

        Shut down this Parlor, but leave tables operating.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'graceful_shutdown: no arguments')
        self.parlor.queueaction(self.parlor.requeststop, True, False)
        return 'stopping parlor gracefully'
Example #19
0
    def rpc_list_tables(self, sender, *args):
        """rpc_list_tables() -> list

        Return a list of open table IDs.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'list_tables: no arguments')
        ls = [ref.jid for ref in self.parlor.referees.values()]
        return ls
Example #20
0
    def rpc_announce(self, sender, *args):
        """rpc_announce(msg) -> str

        Yell a message via all open bots. The message is broadcast as
        an ordinary group-chat message, so all clients at a bot's table
        will see it.

        Returns a message saying how many bots yelled.
        """
        
        if (len(args) != 1):
            raise rpc.RPCFault(604, 'announce STRING')
        val = args[0]
        if (not type(val) in [str, unicode]):
            raise rpc.RPCFault(605, 'announce STRING')

        ls = self.factory.actors.values()
        for act in ls:
            act.announce(val)
        return ('sent to %d bots' % len(ls))
Example #21
0
    def rpc_shutdown(self, sender, *args):
        """rpc_shutdown() -> str

        Immediately shut down this Parlor and all tables. This kills all
        open games, so use it considerately.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'shutdown: no arguments')
        self.parlor.queueaction(self.parlor.requeststop, False, False)
        return 'stopping parlor immediately'
Example #22
0
    def rpc_announce(self, sender, *args):
        """rpc_announce(msg) -> str

        Yell a message on all open tables. The message is broadcast as
        an ordinary group-chat message, so all connected clients will see
        it.

        Returns a message saying how many tables were yelled at.
        """

        if (len(args) != 1):
            raise rpc.RPCFault(604, 'announce STRING')
        val = args[0]
        if (not type(val) in [str, unicode]):
            raise rpc.RPCFault(605, 'announce STRING')

        ls = self.parlor.referees.values()
        for ref in ls:
            ref.announce(val)
        return ('sent to %d tables' % len(ls))
Example #23
0
    def rpc_players(self, sender, *args):
        """rpc_players() -> dict

        Return the actor's view of the players in each seat.
        """
        
        if (len(args) != 0):
            raise rpc.RPCFault(604, 'players: no arguments')
        dic = {}
        for seat in self.actor.seatlist:
            dic[seat.id] = seat.players
        return dic
Example #24
0
    def newtable(self, sender, *args):
        """newtable(sender, *args) -> <RPC outcome>

        Create a new table and Referee. The RPC response will be the
        table JID, but that doesn't happen in this function; see the
        refereeready() callback.
        """

        if (len(args) != 0):
            raise rpc.RPCFault(604, 'new_table takes no arguments')

        if (self.state != 'ready'):
            raise rpc.RPCFault(609, 'parlor is not yet ready')

        if (not self.online):
            raise volent.FailureToken('volity.offline')

        self.log.info('new table requested by %s...', unicode(sender))

        # see unique-nick discussion, bug 1308207
        # assumes resource didn't change
        refresource = 'ref_' + str(os.getpid()) + '_' + str(self.uniquestamp())
        muc = interface.JID(self.muchost)
        muc.setnode(refresource)

        # Create the actual Referee object.

        try:
            refclass = self.gameclass.refereeclass
            if (refclass):
                if (not issubclass(refclass, referee.Referee)):
                    raise Exception(
                        'refereeclass must be a subclass of Referee')
            else:
                refclass = referee.Referee
            ref = refclass(self, self.jid, self.password, refresource, muc)
        except Exception, ex:
            self.log.error('Unable to create referee', exc_info=True)
            raise rpc.RPCFault(608, 'unable to create referee: ' + str(ex))
Example #25
0
    def rpc_online(self, sender, *args):
        """rpc_online(val) -> str

        Set the Parlor to accept or reject new table requests. The *val*
        must be a boolean. If it is False, then new_table requests will
        be rejected with a 'volity.offline' failure token.

        Returns a message describing the outcome.
        """

        if (len(args) != 1):
            raise rpc.RPCFault(604, 'online TRUE/FALSE')
        val = args[0]
        if (type(val) != bool):
            raise rpc.RPCFault(605, 'online TRUE/FALSE')
        if (self.parlor.online and (not val)):
            self.parlor.online = False
            return 'parlor now offline for new table requests'
        if ((not self.parlor.online) and val):
            self.parlor.online = True
            return 'parlor now online for new table requests'
        return 'no change to online status'
Example #26
0
    def refereeready(self, ref, res):
        """refereeready(ref, res) -> <RPC outcome>

        Callback invoked when a Referee is successfully (or unsuccessfully)
        created. This is the continuation of newtable(). The *ref* is the
        Referee object that was created, and *res* is either 'running',
        'end', or 'timeout'.

        If the Referee is running, we return the table JID. If not, we
        return an RPC fault.
        """

        if (res == 'timeout'):
            self.log.warning(
                'referee %s failed to start up in time -- killing',
                ref.resource)
            ref.stop()
            raise rpc.RPCFault(608, 'unable to start referee')
        if (res == 'end'):
            self.log.warning('referee %s died before responding', ref.resource)
            raise rpc.RPCFault(608, 'referee failed to start up')
        self.activitytime = time.time()
        self.refereesstarted += 1
        return unicode(ref.muc)
Example #27
0
 def rpc_leave_table(self, sender, *args):
     if (self.actor.seat):
         raise rpc.RPCFault(609, 'actor is seated')
     self.actor.log.warning('leave_table request; shutting down')
     self.actor.queueaction(self.actor.stop)