mirror of
https://github.com/evennia/evennia.git
synced 2026-04-06 07:57:16 +02:00
Finished refactoring all msdp+evenniacore OOB commands. Still untested
This commit is contained in:
parent
156d80b7bb
commit
d4b5533c20
3 changed files with 312 additions and 165 deletions
|
|
@ -21,9 +21,9 @@ oob functions have the following call signature:
|
|||
|
||||
function(oobhandler, session, *args, **kwargs)
|
||||
|
||||
here, oobhandler always holds a back-reference to the central oob
|
||||
handler, session is the active session and *args, **kwargs are what
|
||||
is sent from the oob call.
|
||||
here, oobhandler is a back-reference to the central oob handler (this
|
||||
allows for deactivating itself in various ways), session is the active
|
||||
session and *args, **kwargs are what is sent from the oob call.
|
||||
|
||||
A function called with OOB_ERROR will retrieve error strings if it is
|
||||
defined. It will get the error message as its 3rd argument.
|
||||
|
|
@ -40,6 +40,13 @@ oobcmdnames (like "MSDP.LISTEN" / "LISTEN" above) are case-sensitive. Note that
|
|||
kwargs must be iterable. Non-iterables will be interpreted as a new
|
||||
command name (you can send multiple oob commands with one msg() call))
|
||||
|
||||
Evennia introduces two internal extensions to MSDP, and that is the
|
||||
MSDP_ARRAY and MSDP_TABLE commands. These are never sent across the
|
||||
wire to the client (so this is fully compliant with the MSDP
|
||||
protocol), but tells the Evennia OOB Protocol that you want to send a
|
||||
"bare" array or table to the client, without prepending any command
|
||||
name.
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
|
@ -53,166 +60,87 @@ _NA_SEND = lambda o: "N/A"
|
|||
# cmdname(oobhandler, session, *args, **kwargs)
|
||||
#------------------------------------------------------------
|
||||
|
||||
#
|
||||
# General OOB commands
|
||||
#
|
||||
|
||||
def oob_error(oobhandler, session, errmsg, *args, **kwargs):
|
||||
"""
|
||||
A function with this name is special and is called by the oobhandler when an error
|
||||
occurs already at the execution stage (such as the oob function
|
||||
not being recognized or having the wrong args etc).
|
||||
Error handling method. Error messages are relayed here.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): The main OOB handler.
|
||||
session (Session): The session to receive the error
|
||||
errmsg (str): The failure message
|
||||
|
||||
A function with this name is special and is also called by the
|
||||
oobhandler when an error occurs already at the execution stage
|
||||
(such as the oob function not being recognized or having the wrong
|
||||
args etc). Call this from other oob functions to centralize error
|
||||
management.
|
||||
|
||||
"""
|
||||
session.msg(oob=("err", ("ERROR " + errmsg,)))
|
||||
|
||||
def oob_echo(oobhandler, session, *args, **kwargs):
|
||||
"Test/debug function, simply returning the args and kwargs"
|
||||
"""
|
||||
Test echo function. Echoes args, kwargs sent to it.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): The main OOB handler.
|
||||
session (Session): The Session to receive the echo.
|
||||
args (list of str): Echo text.
|
||||
kwargs (dict of str, optional): Keyed echo text
|
||||
|
||||
"""
|
||||
session.msg(oob=("echo", args, kwargs))
|
||||
|
||||
# MSDP standard commands
|
||||
|
||||
##OOB{"SEND":"CHARACTER_NAME"} - from webclient
|
||||
def oob_send(oobhandler, session, *args, **kwargs):
|
||||
##OOB{"repeat":10}
|
||||
def oob_repeat(oobhandler, session, oobfuncname, interval, *args, **kwargs):
|
||||
"""
|
||||
This function directly returns the value of the given variable to the
|
||||
session.
|
||||
Called as REPEAT <oobfunc> <interval>
|
||||
Repeats a given OOB command with a certain frequency.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): main OOB handler.
|
||||
session (Session): Session creating the repeat
|
||||
oobfuncname (str): OOB function called every interval seconds
|
||||
interval (int): Interval of repeat, in seconds.
|
||||
|
||||
Notes:
|
||||
The command checks so that it cannot repeat itself.
|
||||
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
ret = {}
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
try:
|
||||
value = OOB_SENDABLE.get(name, _NA_SEND)(obj)
|
||||
ret[name] = value
|
||||
except Exception, e:
|
||||
ret[name] = str(e)
|
||||
session.msg(oob=("send", ret))
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
##OOB{"REPORT":"TEST"}
|
||||
def oob_report(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This creates a tracker instance to track the data given in *args.
|
||||
|
||||
The tracker will return with a oob structure
|
||||
oob={"report":["attrfieldname", (args,), {kwargs}}
|
||||
|
||||
Note that the data name is assumed to be a field is it starts with db_*
|
||||
and an Attribute otherwise.
|
||||
|
||||
"Example of tracking changes to the db_key field and the desc" Attribite:
|
||||
REPORT(oobhandler, session, "CHARACTER_NAME", )
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
trackname = OOB_REPORTABLE.get(name, None)
|
||||
if not trackname:
|
||||
session.msg(oob=("err", ("No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % trackname,)))
|
||||
elif trackname.startswith("db_"):
|
||||
oobhandler.track_field(obj, session.sessid, trackname)
|
||||
else:
|
||||
oobhandler.track_attribute(obj, session.sessid, trackname)
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
##OOB{"UNREPORT": "TEST"}
|
||||
def oob_unreport(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This removes tracking for the given data given in *args.
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
trackname = OOB_REPORTABLE.get(name, None)
|
||||
if not trackname:
|
||||
session.msg(oob=("err", ("No Un-Reportable property '%s'. Use LIST REPORTED_VALUES." % name,)))
|
||||
elif trackname.startswith("db_"):
|
||||
oobhandler.untrack_field(obj, session.sessid, trackname)
|
||||
else: # assume attribute
|
||||
oobhandler.untrack_attribute(obj, session.sessid, trackname)
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
##OOB{"LIST":"COMMANDS"}
|
||||
def oob_list(oobhandler, session, mode, *args, **kwargs):
|
||||
"""
|
||||
List available properties. Mode is the type of information
|
||||
desired:
|
||||
"COMMANDS" Request an array of commands supported
|
||||
by the server.
|
||||
"LISTS" Request an array of lists supported
|
||||
by the server.
|
||||
"CONFIGURABLE_VARIABLES" Request an array of variables the client
|
||||
can configure.
|
||||
"REPORTABLE_VARIABLES" Request an array of variables the server
|
||||
will report.
|
||||
"REPORTED_VARIABLES" Request an array of variables currently
|
||||
being reported.
|
||||
"SENDABLE_VARIABLES" Request an array of variables the server
|
||||
will send.
|
||||
"""
|
||||
mode = mode.upper()
|
||||
if mode == "COMMANDS":
|
||||
session.msg(oob=("list", ("COMMANDS",
|
||||
"LIST",
|
||||
"REPORT",
|
||||
"UNREPORT",
|
||||
# "RESET",
|
||||
"SEND")))
|
||||
elif mode == "LISTS":
|
||||
session.msg(oob=("list", ("LISTS",
|
||||
"REPORTABLE_VARIABLES",
|
||||
"REPORTED_VARIABLES",
|
||||
# "CONFIGURABLE_VARIABLES",
|
||||
"SENDABLE_VARIABLES")))
|
||||
elif mode == "REPORTABLE_VARIABLES":
|
||||
session.msg(oob=("list", ("REPORTABLE_VARIABLES",) +
|
||||
tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
elif mode == "REPORTED_VARIABLES":
|
||||
# we need to check so as to use the right return value depending on if it is
|
||||
# an Attribute (identified by tracking the db_value field) or a normal database field
|
||||
reported = oobhandler.get_all_tracked(session)
|
||||
reported = [stored[2] if stored[2] != "db_value" else stored[4][0] for stored in reported]
|
||||
session.msg(oob=("list", ["REPORTED_VARIABLES"] + reported))
|
||||
elif mode == "SENDABLE_VARIABLES":
|
||||
session.msg(oob=("list", ("SENDABLE_VARIABLES",) +
|
||||
tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
elif mode == "CONFIGURABLE_VARIABLES":
|
||||
# Not implemented (game specific)
|
||||
pass
|
||||
else:
|
||||
session.msg(oob=("err", ("LIST", "Unsupported mode",)))
|
||||
|
||||
def _repeat_callback(oobhandler, session, *args, **kwargs):
|
||||
"Set up by REPEAT"
|
||||
session.msg(oob=("repeat", ("Repeat!",)))
|
||||
|
||||
##OOB{"REPEAT":10}
|
||||
def oob_repeat(oobhandler, session, interval, *args, **kwargs):
|
||||
"""
|
||||
Test command for the repeat functionality. Note that the args/kwargs
|
||||
must not be db objects (or anything else non-picklable), rather use
|
||||
dbrefs if so needed. The callback must be defined globally and
|
||||
will be called as
|
||||
callback(oobhandler, session, *args, **kwargs)
|
||||
"""
|
||||
oobhandler.repeat(None, session.sessid, interval, _repeat_callback, *args, **kwargs)
|
||||
if oobfuncname != "REPEAT":
|
||||
oobhandler.add_repeat(None, session.sessid, oobfuncname, interval, *args, **kwargs)
|
||||
|
||||
|
||||
##OOB{"UNREPEAT":10}
|
||||
def oob_unrepeat(oobhandler, session, interval):
|
||||
def oob_unrepeat(oobhandler, session, oobfuncname, interval):
|
||||
"""
|
||||
Disable repeating callback
|
||||
Called with UNREPEAT <oobfunc> <interval>
|
||||
Disable repeating callback.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): main OOB handler.
|
||||
session (Session): Session controlling the repeat
|
||||
oobfuncname (str): OOB function called every interval seconds
|
||||
interval (int): Interval of repeat, in seconds.
|
||||
|
||||
Notes:
|
||||
The command checks so that it cannot repeat itself.
|
||||
|
||||
|
||||
"""
|
||||
oobhandler.unrepeat(None, session.sessid, interval)
|
||||
oobhandler.remove_repeat(None, session.sessid, oobfuncname, interval)
|
||||
|
||||
|
||||
# Mapping for how to retrieve each property name.
|
||||
# Each entry should point to a callable that gets the interesting object as
|
||||
# input and returns the relevant value.
|
||||
#
|
||||
# MSDP standard commands
|
||||
#
|
||||
|
||||
# MSDP recommends the following standard name conventions for making different properties available to the player
|
||||
|
||||
# MSDP recommends the following standard name mappings for general compliance:
|
||||
# "CHARACTER_NAME", "SERVER_ID", "SERVER_TIME", "AFFECTS", "ALIGNMENT", "EXPERIENCE", "EXPERIENCE_MAX", "EXPERIENCE_TNL",
|
||||
# "HEALTH", "HEALTH_MAX", "LEVEL", "RACE", "CLASS", "MANA", "MANA_MAX", "WIMPY", "PRACTICE", "MONEY", "MOVEMENT",
|
||||
# "MOVEMENT_MAX", "HITROLL", "DAMROLL", "AC", "STR", "INT", "WIS", "DEX", "CON", "OPPONENT_HEALTH", "OPPONENT_HEALTH_MAX",
|
||||
|
|
@ -220,6 +148,8 @@ def oob_unrepeat(oobhandler, session, interval):
|
|||
# "CLIENT_VERSION", "PLUGIN_ID", "ANSI_COLORS", "XTERM_256_COLORS", "UTF_8", "SOUND", "MXP", "BUTTON_1", "BUTTON_2",
|
||||
# "BUTTON_3", "BUTTON_4", "BUTTON_5", "GAUGE_1", "GAUGE_2","GAUGE_3", "GAUGE_4", "GAUGE_5"
|
||||
|
||||
|
||||
# mapping from MSDP standard names to Evennia variables
|
||||
OOB_SENDABLE = {
|
||||
"CHARACTER_NAME": lambda o: o.key,
|
||||
"SERVER_ID": lambda o: settings.SERVERNAME,
|
||||
|
|
@ -229,23 +159,201 @@ OOB_SENDABLE = {
|
|||
"UTF_8": lambda o: True
|
||||
}
|
||||
|
||||
# mapping for which properties may be tracked. Each value points either to a database field
|
||||
# (starting with db_*) or an Attribute name.
|
||||
|
||||
##OOB{"SEND":"CHARACTER_NAME"} - from webclient
|
||||
def oob_send(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
Called with the SEND MSDP command.
|
||||
This function directly returns the value of the given variable to
|
||||
the session. It assumes the object on which the variable sits
|
||||
belongs to the session.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): oobhandler reference
|
||||
session (Session): Session object
|
||||
args (str): any number of properties to return. These
|
||||
must belong to the OOB_SENDABLE dictionary.
|
||||
Examples:
|
||||
oob input: ("SEND", "CHARACTER_NAME", "SERVERNAME")
|
||||
oob output: ("MSDP_TABLE", "CHARACTER_NAME", "Amanda",
|
||||
"SERVERNAME", "Evennia")
|
||||
|
||||
"""
|
||||
# mapping of MSDP name to a property
|
||||
obj = session.get_puppet_or_player()
|
||||
ret = {}
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
try:
|
||||
value = OOB_SENDABLE.get(name, _NA_SEND)(obj)
|
||||
ret[name] = value
|
||||
except Exception, e:
|
||||
ret[name] = str(e)
|
||||
# return, make sure to use the right case
|
||||
session.msg(oob=("MSDP_TABLE", (), ret))
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
# mapping standard MSDP keys to Evennia field names
|
||||
OOB_REPORTABLE = {
|
||||
"CHARACTER_NAME": "db_key",
|
||||
"ROOM_NAME": "db_location",
|
||||
"TEST" : "test"
|
||||
}
|
||||
|
||||
##OOB{"REPORT":"TEST"}
|
||||
def oob_report(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
Called with the `REPORT PROPNAME` MSDP command.
|
||||
Monitors the changes of given property name. Assumes reporting
|
||||
happens on an objcet controlled by the session.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): The main OOB handler
|
||||
session (Session): The Session doing the monitoring. The
|
||||
property is assumed to sit on the entity currently
|
||||
controlled by the Session. If puppeting, this is an
|
||||
Object, otherwise the object will be the Player the
|
||||
Session belongs to.
|
||||
args (str or list): One or more property names to monitor changes in.
|
||||
If a name starts with `db_`, the property is assumed to
|
||||
be a field, otherwise an Attribute of the given name will
|
||||
be monitored (if it exists).
|
||||
|
||||
Notes:
|
||||
When the property updates, the monitor will send a MSDP_ARRAY
|
||||
to the session of the form `(SEND, fieldname, new_value)`
|
||||
Examples:
|
||||
("REPORT", "CHARACTER_NAME")
|
||||
("MSDP_TABLE", "CHARACTER_NAME", "Amanda")
|
||||
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in args:
|
||||
propname = OOB_REPORTABLE.get(name, None)
|
||||
if not propname:
|
||||
session.msg(oob=("err", ("No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname,)))
|
||||
# the field_monitors require an oob function as a callback when they report a change.
|
||||
elif propname.startswith("db_"):
|
||||
oobhandler.add_field_monitor(obj, session.sessid, propname, "return_field_report")
|
||||
else:
|
||||
oobhandler.add_attribute_monitor(obj, session.sessid, propname, "return_attribute_report")
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
def oob_return_field_report(oobhandler, session, fieldname, obj, *args, **kwargs):
|
||||
"""
|
||||
This is a helper command called by the monitor when fieldname
|
||||
changes. It is not part of the official MSDP specification but is
|
||||
a callback used by the monitor to format the result before sending
|
||||
it on.
|
||||
"""
|
||||
session.msg(oob=("MSDP_TABLE", (), {fieldname, getattr(obj, fieldname)}))
|
||||
|
||||
|
||||
def oob_return_attribute_report(oobhandler, session, fieldname, obj, *args, **kwargs):
|
||||
"""
|
||||
This is a helper command called by the monitor when an Attribute
|
||||
changes. We need to handle this a little differently from fields
|
||||
since we are generally not interested in the field name (it's
|
||||
always db_value for Attributes) but the Attribute's name.
|
||||
|
||||
This command is not part of the official MSDP specification but is
|
||||
a callback used by the monitor to format the result before sending
|
||||
it on.
|
||||
"""
|
||||
session.msg(oob=("MSDP_TABLE", (), {obj.db_key, getattr(obj, fieldname)}))
|
||||
|
||||
|
||||
##OOB{"UNREPORT": "TEST"}
|
||||
def oob_unreport(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This removes tracking for the given data.
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
propname = OOB_REPORTABLE.get(name, None)
|
||||
if not propname:
|
||||
session.msg(oob=("err", ("No Un-Reportable property '%s'. Use LIST REPORTED_VALUES." % name,)))
|
||||
elif propname.startswith("db_"):
|
||||
oobhandler.remove_field_monitor(obj, session.sessid, propname, "oob_return_field_report")
|
||||
else: # assume attribute
|
||||
oobhandler.remove_attribute_monitor(obj, session.sessid, propname, "oob_return_attribute_report")
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
##OOB{"LIST":"COMMANDS"}
|
||||
def oob_list(oobhandler, session, mode, *args, **kwargs):
|
||||
"""
|
||||
Called with the `LIST <MODE>` MSDP command.
|
||||
|
||||
Args:
|
||||
oobhandler (OOBHandler): The main OOB handler
|
||||
session (Session): The Session asking for the information
|
||||
mode (str): The available properties. One of
|
||||
"COMMANDS" Request an array of commands supported
|
||||
by the server.
|
||||
"LISTS" Request an array of lists supported
|
||||
by the server.
|
||||
"CONFIGURABLE_VARIABLES" Request an array of variables the client
|
||||
can configure.
|
||||
"REPORTABLE_VARIABLES" Request an array of variables the server
|
||||
will report.
|
||||
"REPORTED_VARIABLES" Request an array of variables currently
|
||||
being reported.
|
||||
"SENDABLE_VARIABLES" Request an array of variables the server
|
||||
will send.
|
||||
Examples:
|
||||
oob in: LIST COMMANDS
|
||||
oob out: (COMMANDS, (SEND, REPORT, LIST, ...)
|
||||
"""
|
||||
mode = mode.upper()
|
||||
if mode == "COMMANDS":
|
||||
session.msg(oob=("COMMANDS", ("LIST",
|
||||
"REPORT",
|
||||
"UNREPORT",
|
||||
# "RESET",
|
||||
"SEND")))
|
||||
elif mode == "LISTS":
|
||||
session.msg(oob=("LISTS",("REPORTABLE_VARIABLES",
|
||||
"REPORTED_VARIABLES",
|
||||
# "CONFIGURABLE_VARIABLES",
|
||||
"SENDABLE_VARIABLES")))
|
||||
elif mode == "REPORTABLE_VARIABLES":
|
||||
session.msg(oob=("REPORTABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
elif mode == "REPORTED_VARIABLES":
|
||||
# we need to check so as to use the right return value depending on if it is
|
||||
# an Attribute (identified by tracking the db_value field) or a normal database field
|
||||
# reported is a list of tuples (obj, propname, args, kwargs)
|
||||
reported = oobhandler.get_all_monitors(session.sessid)
|
||||
reported = [rep[0].key if rep[1] == "db_value" else rep[1] for rep in reported]
|
||||
session.msg(oob=("REPORTED_VARIABLES", reported))
|
||||
elif mode == "SENDABLE_VARIABLES":
|
||||
session.msg(oob=("SENDABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
elif mode == "CONFIGURABLE_VARIABLES":
|
||||
# Not implemented (game specific)
|
||||
session.msg(oob=("err", ("LIST", "Not implemented (game specific).")))
|
||||
else:
|
||||
session.msg(oob=("err", ("LIST", "Unsupported mode",)))
|
||||
|
||||
|
||||
# this maps the commands to the names available to use from
|
||||
# the oob call
|
||||
CMD_MAP = {"OOB_ERROR": oob_error, # will get error messages
|
||||
# the oob call. The standard MSDP commands are capitalized
|
||||
# as per the protocol, Evennia's own commands are not.
|
||||
CMD_MAP = {"oob_error": oob_error, # will get error messages
|
||||
"return_field_report": oob_return_field_report,
|
||||
"return_attribute_report": oob_return_attribute_report,
|
||||
"repeat": oob_repeat,
|
||||
"unrepeat": oob_unrepeat,
|
||||
"SEND": oob_send,
|
||||
"ECHO": oob_echo,
|
||||
"REPORT": oob_report,
|
||||
"UNREPORT": oob_unreport,
|
||||
"LIST": oob_list,
|
||||
"REPEAT": oob_repeat,
|
||||
"UNREPEAT": oob_unrepeat}
|
||||
"LIST": oob_list
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,14 +51,18 @@ _DA = object.__delattr__
|
|||
# load resources from plugin module
|
||||
_OOB_FUNCS = {}
|
||||
for mod in make_iter(settings.OOB_PLUGIN_MODULES):
|
||||
_OOB_FUNCS.update(dict((key.lower(), func) for key, func in all_from_module(mod).items() if isfunction(func)))
|
||||
_OOB_FUNCS.update(mod.CMD_MAP)
|
||||
|
||||
# get custom error method or use the default
|
||||
# get the command to receive eventual error strings
|
||||
_OOB_ERROR = _OOB_FUNCS.get("oob_error", None)
|
||||
if not _OOB_ERROR:
|
||||
# create default oob error message function
|
||||
def oob_error(oobhandler, session, errmsg, *args, **kwargs):
|
||||
"Error wrapper"
|
||||
"""
|
||||
Fallback error handler. This will be used if no custom
|
||||
oob_error is defined and just echoes the error back to the
|
||||
session.
|
||||
"""
|
||||
session.msg(oob=("err", ("ERROR ", errmsg)))
|
||||
_OOB_ERROR = oob_error
|
||||
|
||||
|
|
@ -83,13 +87,13 @@ class OOBFieldMonitor(object):
|
|||
"""
|
||||
self.subscribers = defaultdict(list)
|
||||
|
||||
def __call__(self, new_value, obj):
|
||||
def __call__(self, obj, fieldname):
|
||||
"""
|
||||
Called by the save() mechanism when the given
|
||||
field has updated.
|
||||
"""
|
||||
for sessid, (oobfuncname, args, kwargs) in self.subscribers.items():
|
||||
OOB_HANDLER.execute_cmd(sessid, oobfuncname, new_value, obj=obj, *args, **kwargs)
|
||||
OOB_HANDLER.execute_cmd(sessid, oobfuncname, fieldname, obj, *args, **kwargs)
|
||||
|
||||
def add(self, sessid, oobfuncname, *args, **kwargs):
|
||||
"""
|
||||
|
|
@ -246,9 +250,14 @@ class OOBHandler(TickerHandler):
|
|||
obj (Object) - the object on which to register the repeat
|
||||
sessid (int) - session id of the session registering
|
||||
oobfuncname (str) - oob function name to call every interval seconds
|
||||
interval (int) - interval to call oobfunc, in seconds
|
||||
*args, **kwargs - are used as arguments to the oobfunc
|
||||
interval (int, optional) - interval to call oobfunc, in seconds
|
||||
Notes:
|
||||
*args, **kwargs are used as extra arguments to the oobfunc.
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
|
||||
hook = OOBAtRepeat()
|
||||
hookname = self._get_repeat_hook_name(oobfuncname, interval, sessid)
|
||||
_SA(obj, hookname, hook)
|
||||
|
|
@ -265,9 +274,13 @@ class OOBHandler(TickerHandler):
|
|||
Args:
|
||||
obj (Object): The object on which the repeater sits
|
||||
sessid (int): Session id of the Session that registered the repeat
|
||||
oob
|
||||
oobfuncname (str): Name of oob function to call at repeat
|
||||
interval (int, optional): Number of seconds between repeats
|
||||
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
self.remove(obj, interval, idstring=oobfuncname)
|
||||
hookname = self._get_repeat_hook_name(oobfuncname, interval, sessid)
|
||||
try:
|
||||
|
|
@ -287,9 +300,18 @@ class OOBHandler(TickerHandler):
|
|||
oobfuncname (str): OOB function to call when field changes
|
||||
|
||||
Notes:
|
||||
The optional args, and kwargs will be passed on to the
|
||||
oobfunction.
|
||||
When the field updates the given oobfunction will be called as
|
||||
|
||||
`oobfuncname(oobhandler, session, fieldname, obj, *args, **kwargs)`
|
||||
|
||||
where `fieldname` is the name of the monitored field and
|
||||
`obj` is the object on which the field sits. From this you
|
||||
can also easily get the new field value if you want.
|
||||
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
# all database field names starts with db_*
|
||||
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
|
||||
self._add_monitor(obj, sessid, field_name, field_name, oobfuncname=None)
|
||||
|
|
@ -306,10 +328,13 @@ class OOBHandler(TickerHandler):
|
|||
oobfuncname (str, optional): OOB command to call on that field
|
||||
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
|
||||
self._remove_monitor(obj, sessid, field_name, oobfuncname=oobfuncname)
|
||||
|
||||
def add_attribute_track(self, obj, sessid, attr_name, oobfuncname):
|
||||
def add_attribute_monitor(self, obj, sessid, attr_name, oobfuncname):
|
||||
"""
|
||||
Monitor the changes of an Attribute on an object. Will trigger when
|
||||
the Attribute's `db_value` field updates.
|
||||
|
|
@ -321,6 +346,9 @@ class OOBHandler(TickerHandler):
|
|||
oobfuncname (str): OOB function to call when Attribute updates.
|
||||
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
# get the attribute object if we can
|
||||
attrobj = obj.attributes.get(attr_name, return_obj=True)
|
||||
if attrobj:
|
||||
|
|
@ -337,6 +365,9 @@ class OOBHandler(TickerHandler):
|
|||
oobfuncname (str): OOB function name called when Attribute updates.
|
||||
|
||||
"""
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
attrobj = obj.attributes.get(attr_name, return_obj=True)
|
||||
if attrobj:
|
||||
self._remove_monitor(attrobj, sessid, "db_value", attr_name, oobfuncname)
|
||||
|
|
@ -347,9 +378,17 @@ class OOBHandler(TickerHandler):
|
|||
|
||||
Args:
|
||||
sessid (id): Session id of monitoring Session
|
||||
|
||||
Returns:
|
||||
stored monitors (tuple): A list of tuples
|
||||
`(obj, fieldname, args, kwargs)` representing all
|
||||
the monitoring the Session with the given sessid is doing.
|
||||
"""
|
||||
return [stored for key, stored in self.oob_monitor_storage.items() if key[1] == sessid]
|
||||
# check so we didn't get a session instead of a sessid
|
||||
if not isinstance(sessid, int):
|
||||
sessid = sessid.sessid
|
||||
# [(obj, fieldname, args, kwargs), ...]
|
||||
return [(unpack_dbobj(key[0]), key[2], stored[0], stored[1])
|
||||
for key, stored in self.oob_monitor_storage.items() if key[1] == sessid]
|
||||
|
||||
|
||||
# access method - called from session.msg()
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ class SharedMemoryModel(Model):
|
|||
# fieldname and the new value
|
||||
fieldtracker = "_oob_at_%s_postsave" % fieldname
|
||||
if hasattr(self, fieldtracker):
|
||||
_GA(self, fieldtracker)(_GA(self, fieldname), self)
|
||||
_GA(self, fieldtracker)(self, fieldname)
|
||||
|
||||
|
||||
class WeakSharedMemoryModelBase(SharedMemoryModelBase):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue