| | |
- zymb.jabber.rpc.MethodOpset(zymb.jabber.rpc.Opset)
-
- ParlorAdminOpset
- ParlorVolityOpset
- volity.volent.VolEntity(zymb.sched.Agent)
-
- Parlor
class Parlor(volity.volent.VolEntity) |
| |
Parlor: The implementation of a Volity parlor (i.e., game server).
This is the central class which runs games on a system. When you
run the volityd.py script, it creates a Parlor and starts it running.
Parlor is a Jabber client (although it is not a subclass of the
Zymb Jabber client agent; instead, it creates one as a subsidiary
object). It sits around and waits for the "new table" command,
which tells it to start up a Referee. That's nearly all it does,
actually, although there are some extra debugging and administration
features.
Parlor(config) -- constructor.
The *config* is a ConfigFile object, containing various options needed
to set up the Parlor. The volityd.py script creates this. For the
record, the significant fields are:
jid: Used when connecting to Jabber
jid-resource: Resource string to use (optional, overrides the
one in *jid*; if no resource is provided in either *jid* or
*jid-resource*, then "volity" is used)
password: Used when connecting to Jabber
game: Name of Python class which implements the game
bot: Name of Python class which implements the bot (optional;
if not provided, then the parlor will not create bots)
admin: JID which is permitted to send admin commands (optional)
muchost: JID of Jabber MUC server (optional, defaults to
"conference.volity.net")
bookkeeper: JID of Volity bookkeeper (optional, defaults to
"bookkeeper@volity.net/volity")
contact-email: Contact email address of person hosting this
parlor (optional)
contact-jid: Contact Jabber address of person hosting this
parlor (optional)
keepalive: If present, send periodic messages to exercise the
Jabber connection (optional)
keepalive-interval: If present, send periodic messages every
*keepalive-interval* seconds to exercise the Jabber
connection (optional)
Agent states and events:
state 'start': Initial state. Start up the Jabber connection process.
When Jabber is fully connected, jump to 'ready'.
state 'ready': Send out initial presence. In this state, the Parlor
accepts new_table requests.
state 'end': The connection is closed.
Public methods:
start() -- begin activity. (inherited)
stop() -- stop activity. (inherited)
Significant fields:
jid -- the JID by which this Parlor is connected.
conn -- the Jabber client agent.
adminjid -- the JID which is permitted to send admin commands.
gameclass -- the Game subclass which implements the game.
botclass -- the Bot subclass which implements the bot (or None).
gamename -- the game's human-readable name (taken from gameclass).
referees -- dict mapping resource strings to Referees.
actors -- dict mapping resource strings to Actors.
online -- whether the Parlor is accepting new_table requests.
Internal methods:
handlemessage() -- handle a Jabber message stanza.
handlepresence() -- handle a Jabber presence stanza.
newtable() -- create a new table and Referee.
refereeready() -- callback invoked when a Referee is successfully
(or unsuccessfully) created.
refereedied() -- callback invoked when a Referee shuts down.
actordied() -- callback invoked when an Actor (bot) shuts down.
listopengames() -- create a DiscoItems list of currently-active games.
handlerosterquery() -- accept a request to be added to someone's roster. |
| |
- Method resolution order:
- Parlor
- volity.volent.VolEntity
- zymb.sched.Agent
Methods defined here:
- __init__(self, config)
- actordied(self, act)
- refereedied(ref) -> None
Callback invoked when an Actor shuts down. Remove the Actor from
our internal table.
- handlemessage(self, msg)
- handlemessage(msg) -> <stanza outcome>
Handle a Jabber message stanza. The Parlor does not react to messages,
so this just raises StanzaHandled to end processing for the stanza.
- handlepresence(self, msg)
- handlepresence(msg) -> <stanza outcome>
Handle a Jabber presence stanza. The Parlor does not react to presence,
so this just raises StanzaHandled to end processing for the stanza.
- handlerosterquery(self, msg)
- handlerosterquery(msg) -> <stanza outcome>
Accept a request to be added to someone's roster.
- listopengames(self)
- listopengames() -> DiscoItems
Create a DiscoItems list of currently-active games. This is used
when responding to disco#items queries.
- 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.
- refereedied(self, ref)
- refereedied(ref) -> None
Callback invoked when a Referee shuts down. Remove the Referee
from our internal table.
- 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.
Data and other attributes defined here:
- logprefix = 'volity.parlor'
- volityrole = 'parlor'
Methods inherited from volity.volent.VolEntity:
- authed(self)
- authed() -- handler for Jabber client 'authresource' state.
The Jabber client has finished connecting. Jump to 'ready'.
- cappresencehook(self, msg)
- cappresencehook() -- callback for presence stanza generation.
This hook is called whenever we generate a presence stanza. It adds
a JEP-0115 Entity Capabilities tag to the stanza.
- finalize(self)
- finalize() -- 'end' state handler.
Shut down the Jabber client agent.
- rpcnotfound(self, msg, callname, callargs)
- rpcnotfound() -- callback for RPC method-not-found case.
When an RPC arrives that we do not recognize, we want to respond
with an RPC fault. (As opposed to the default behavior, which is
an <item-not-found> stanza error.)
- startpresence(self)
- startpresence() -- 'ready' state handler.
Send out initial presence.
- startup(self)
- startup() -- 'start' state handler.
Start the Jabber client agent, and then wait for it to finish
connecting.
Static methods inherited from volity.volent.VolEntity:
- uniquestamp()
- uniquestamp() -> int
Generate a number which is unique within this process. It is
approximately a Unix timestamp, but incremented when necessary
to avoid repeats.
Data and other attributes inherited from volity.volent.VolEntity:
- laststamp = 0
Methods inherited from zymb.sched.Agent:
- __str__(self)
- addcleanupaction(self, ac)
- addcleanupaction(action) -> None
Add *action* to the list of actions to be removed when the agent
stops (i.e., jumps to the 'end' state).
This is intended for actions that an agent adds as handlers to
other agents. For example:
ac = otheragent.addhandler('event', self.foreigneventhandler)
# Ensure that ac is removed when *self* shuts down.
addcleanupaction(ac)
You do not need to list pollers or socket-checkers as cleanup
actions. Nor do you need to list handlers that an agent adds
to itself. (All these are automatically removed when the agent
shuts down.) You also don't have to worry about the case of
*otheragent* shutting down; when that happens, all handlers added
to it are removed.
- addhandler(self, state, op, *args)
- addhandler(eventname, op, *args) -> action
Add a state or event handler. The *eventname* is a string naming
the state or event you want to handle. The *op* and *args* are
the operation to perform when that state or event occurs.
(See queueaction() for the use of *op* and *args*.)
Handlers are invoked in last-added-first-run order. If an agent
has a built-in handler, it is added first, so it runs last. Handlers
that you add on later run earlier.
Returns the Action. (You can cancel the handler by calling
ac.remove().)
- addtimer(self, op, *args, **dic)
- addtimer(op, *args, delay=num, when=num, periodic=bool) -> action
Add a timed event. You must supply exactly one of the keyword
arguments *delay* and *when*. A *when* is an absolute time,
expressed as a number of seconds since the epoch (e.g., the kind
of value returned by time.time()). A *delay* is a relative time,
expressed as a number of seconds in the future.
It is legal to give a time in the past (or a negative *delay*).
In that case, this is similar to queueaction() -- the operation
will occur very soon. (Although it's still a "low priority"
action.)
If you supply *periodic*=True, the event will occur repeatedly,
every *delay* seconds. (The interval is inferred if you give
*when*.) In this case, you may NOT give a negative *delay* or
a time in the past -- it is meaningless for a periodic event to
have a period less than or equal to zero.
You can also create a periodic timer by calling addtimer with
a PeriodicAction, which is a subclass of Action. This is slightly
more flexible; the interval between calls is specified when
you create the PeriodicAction, but the delay before the first
call may be specified with *delay* or *when*.
See queueaction() for the use of *op* and *args*.
Returns the Action. (You can cancel the timer by calling
ac.remove().)
- basicerror(self, exc, agent)
- basicerror(exc, agent) -> None
A simple event handler for 'error'. This simply writes the
received data to stdout:
sys.stdout.write('Error: ' + str(agent) + ': ' + str(exc) + '
')
This handler is not installed by default. You can enable it by
calling:
ag.addhandler('error', ag.basicerror)
- jump(self, st, *exargs)
- jump(state, *args) -> None
Jump to a different operating state. (If the agent is already
in the given state, nothing happens.)
This queues up all the state transition handlers registered
for the new state. If you provide *args*, they are passed to the
handlers when they are called.
- perform(self, name, *exargs)
- perform(eventname, *args) -> None
Trigger an event.
This queues up all the event handlers registered for the given
event. If you provide *args*, they are passed to the handlers when
they are called.
- queueaction(self, op, *args)
- queueaction(op, *args) -> action
Invoke an action. The action will be handed to the scheduler, which
will run it very soon.
("Very soon" means "before the next timed event or network message
is handled." However, if you queue several actions, they will be
handled in the order you queued them.)
You can pass any callable as *op*; the (optional) *args* will be
passed to it as arguments. You can also, if you like, create
an Action object and pass it as *op*. You can still pass *args*
in this case; they'll be appended to the arguments bound into
the Action.
Returns the Action.
- registerpoll(self, op, *args, **dic)
- registerpoll(op, *args, interval=num) -> action
Add a repeating activity check. *interval* is a (mandatory) keyword
argument; the scheduler will invoke your operation at least every
*interval* seconds. (And at least once per sched.process() call.)
See queueaction() for the use of *op* and *args*. Your operation
should not do any work except for absorbing input and queueing
actions. Typically, it will collect the input and then call
perform(), triggering an event, so that the agent's event
handlers can do something with the input.
Returns the Action. (You can cancel it by calling ac.remove().)
- registersocket(self, fileno, op, *args)
- registersocket(socket, op, *args) -> action
Add a socket-based activity check. The *socket* may be a socket
object, or a number representing a fileno, or any object which
provides a fileno() method.
See queueaction() for the use of *op* and *args*. Your operation
should not do any work except for absorbing input and queueing
actions. Typically, it will collect the input and then call
perform(), triggering an event, so that the agent's event
handlers can do something with the input.
Returns the Action. (You can cancel it by calling ac.remove().)
- shutdown(self)
- shutdown() -- internal 'end' state handler. Do not call.
This is the final 'end' handler. It removes the agent from the
scheduler, and cancels all its remaining actions, timed events,
etc.
- start(self)
- start() -> None
Begin activity. The agent adds itself to the scheduler and moves
to the 'start' state. It does not actually begin doing work in
this call; that happens the next time the scheduler is invoked
(sched.process).
You should only call this once per agent.
- stop(self)
- stop() -> None
Stop activity. The agent moves to the 'end' state. Its 'end'
state handlers will take care of shutting it down and removing
it from the scheduler.
It is safe to call this on an agent which is already in 'end',
or which is completely shut down. (Nothing further will happen.)
(Remember, state handlers are not called as part of the stop()
method. They are run by the scheduler "soon" after stop() is
called. If you want to be sure the agent is completely stopped,
you can check the agent.live field. However, it is better to
register your own 'end' state handler, and consider the agent
stopped when that it called.)
Data and other attributes inherited from zymb.sched.Agent:
- agentcounter = 1
- hidden = False
|
class ParlorAdminOpset(zymb.jabber.rpc.MethodOpset) |
| |
ParlorAdminOpset: The Opset which responds to admin.* namespace
RPCs.
ParlorAdminOpset(par) -- constructor.
The *par* is the Parlor to which this Opset is attached.
Methods:
precondition() -- checks authorization before an RPC handler.
Handler methods:
rpc_status() -- return assorted status information.
rpc_list_tables() -- return a list of open table IDs.
rpc_list_bots() -- return a list of running bots (on all tables).
rpc_online() -- set the Parlor to accept or reject new table requests.
rpc_announce() -- yell a message on all open tables.
rpc_shutdown() -- immediately shut down this Parlor and all tables. |
| |
- Method resolution order:
- ParlorAdminOpset
- zymb.jabber.rpc.MethodOpset
- zymb.jabber.rpc.Opset
Methods defined here:
- __init__(self, par)
- precondition(self, sender, namehead, nametail, *callargs)
- precondition(sender, namehead, nametail, *callargs)
Checks authorization before an RPC handler. Only the admin JID
is permitted to send admin.* namespace RPCs. If no admin JID was
set, then all admin.* RPCs are rejected.
- 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.
- rpc_list_bots(self, sender, *args)
- rpc_list_bots() -> list
Return a list of running bots (on all tables).
- rpc_list_tables(self, sender, *args)
- rpc_list_tables() -> list
Return a list of open table IDs.
- 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.
- 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. It is preferable to set the
Parlor offline (so no new tables start up), then announce that the
system is being shut down, and then wait for everybody to finish
their games and leave.
- 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.
Methods inherited from zymb.jabber.rpc.MethodOpset:
- __call__(self, sender, callname, *callargs)
- __call__(sender, callname, *callargs) -> value
Accept, parse, and handle a call. The *sender* is a JID object.
The *callname* is the method name (or fraction of a name, if
the opset is nested inside another opset which parsed the
namespace). The *callargs* are the RPC arguments, in the form
of Python objects (ints, strings, etc).
This method looks for an instance method named 'rpc_'+*callname*.
It invokes this (after calling
precondition(sender, callname, '', *callargs). The third argument
is empty because, in a MethodOpset, there is no more of the
callname to be matched after the method lookup.)
|
class ParlorVolityOpset(zymb.jabber.rpc.MethodOpset) |
| |
ParlorVolityOpset: The Opset which responds to volity.* namespace
RPCs.
ParlorVolityOpset(par) -- constructor.
The *par* is the Parlor to which this Opset is attached.
Handler methods:
rpc_new_table() -- create a new table and Referee. |
| |
- Method resolution order:
- ParlorVolityOpset
- zymb.jabber.rpc.MethodOpset
- zymb.jabber.rpc.Opset
Methods defined here:
- __init__(self, par)
- rpc_new_table(self, sender, *args)
- rpc_new_table() -> table JID
Create a new table and Referee.
Implemented by the parlor's newtable() method.
Methods inherited from zymb.jabber.rpc.MethodOpset:
- __call__(self, sender, callname, *callargs)
- __call__(sender, callname, *callargs) -> value
Accept, parse, and handle a call. The *sender* is a JID object.
The *callname* is the method name (or fraction of a name, if
the opset is nested inside another opset which parsed the
namespace). The *callargs* are the RPC arguments, in the form
of Python objects (ints, strings, etc).
This method looks for an instance method named 'rpc_'+*callname*.
It invokes this (after calling
precondition(sender, callname, '', *callargs). The third argument
is empty because, in a MethodOpset, there is no more of the
callname to be matched after the method lookup.)
Methods inherited from zymb.jabber.rpc.Opset:
- precondition(self, sender, namehead, nametail, *callargs)
- precondition(sender, namehead, nametail, *callargs) -> None
This method is invoked inside the __call__ method, after the
opset has decided what to do, but before it does it. The
precondition has the opportunity to raise StanzaErrors, RPCFaults,
or RPCResponses for a whole class of calls, before a specific
function is invoked.
The *sender* is a JID; the *callargs* are the RPC arguments,
in the form of Python objects. The *namehead* and *nametail*
represent the callname. *namehead* is the part that has been
successfully parsed by this Opset, and *nametail* is the part
which will be passed on to the function. For some Opset classes
(NamesOpset and MethodOpset), *nametail* is always empty.
In all the Opset classes in this module, the precondition method
does nothing. It is provided so that you can create Opset
subclasses which do application-specific checks.
| |