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'
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')
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'
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))
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'
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
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)
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
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
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
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()
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')
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'
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
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'
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)
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'
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'
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
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))
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'
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))
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
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))
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'
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)
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)