mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Working on the OOB system, somewhat unstable at the moment.
This commit is contained in:
parent
d59500f574
commit
9ba212c264
6 changed files with 252 additions and 342 deletions
175
src/server/oob_cmds.py
Normal file
175
src/server/oob_cmds.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
"""
|
||||
Out-of-band default plugin commands available for OOB handler.
|
||||
|
||||
This module implements commands as defined by the MSDP standard
|
||||
(http://tintin.sourceforge.net/msdp/), but is independent of the
|
||||
actual transfer protocol (webclient, MSDP, GMCP etc).
|
||||
|
||||
This module is pointed to by settings.OOB_PLUGIN_MODULES. All functions
|
||||
(not classes) defined globally in this module will be made available
|
||||
to the oob mechanism.
|
||||
|
||||
oob functions have the following call signature:
|
||||
function(oobhandler, session, *args, **kwargs)
|
||||
|
||||
where oobhandler is a back-reference to the central OOB_HANDLER
|
||||
instance and session is the active session to get return data.
|
||||
|
||||
The function names are not case-sensitive (this allows for names
|
||||
like "LIST" which would otherwise collide with Python builtins).
|
||||
|
||||
A function named _OOB_ERROR will retrieve error strings if it is
|
||||
defined. It will get the error message as its 3rd argument.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_NA_REPORT = lambda o: (None, "N/A")
|
||||
_NA_SEND = lambda o: "N/A"
|
||||
|
||||
#------------------------------------------------------------
|
||||
# All OOB commands must be on the form
|
||||
# cmdname(oobhandler, session, *args, **kwargs)
|
||||
#------------------------------------------------------------
|
||||
|
||||
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).
|
||||
"""
|
||||
session.msg(oob=("send", {"ERROR": errmsg}))
|
||||
|
||||
|
||||
def ECHO(oobhandler, session, *args, **kwargs):
|
||||
"Test/debug function, simply returning the args and kwargs"
|
||||
session.msg(oob=("echo", args, kwargs))
|
||||
|
||||
|
||||
def SEND(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This function directly returns the value of the given variable to the
|
||||
session.
|
||||
"""
|
||||
print "In SEND:", oobhandler, session, args
|
||||
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 result
|
||||
session.msg(oob=("send", ret))
|
||||
|
||||
|
||||
def REPORT(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This creates a tracker instance to track the data given in *args.
|
||||
|
||||
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):
|
||||
typ, val = OOB_REPORTABLE.get(name, _NA_REPORT)(obj)
|
||||
if typ == "field":
|
||||
oobhandler.track_field(obj, session.sessid, name)
|
||||
elif typ == "attribute":
|
||||
oobhandler.track_attribute(obj, session.sessid, name)
|
||||
|
||||
|
||||
def UNREPORT(oobhandler, session, vartype="prop", *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):
|
||||
typ, val = OOB_REPORTABLE.get(name, _NA_REPORT)
|
||||
if typ == "field":
|
||||
oobhandler.untrack_field(obj, session.sessid, name)
|
||||
else: # assume attribute
|
||||
oobhandler.untrack_attribute(obj, session.sessid, name)
|
||||
|
||||
|
||||
def 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":
|
||||
session.msg(oob=("list", ("REPORTED_VARIABLES",) +
|
||||
tuple(oobhandler.get_all_tracked(session))))
|
||||
elif mode == "SENDABLE_VARIABLES":
|
||||
session.msg(oob=("list", ("SENDABLE_VARIABLES",) +
|
||||
tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
#elif mode == "CONFIGURABLE_VARIABLES":
|
||||
# pass
|
||||
else:
|
||||
session.msg(oob=("list", ("unsupported mode",)))
|
||||
|
||||
|
||||
# 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 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",
|
||||
# "OPPONENT_LEVEL", "OPPONENT_NAME", "AREA_NAME", "ROOM_EXITS", "ROOM_VNUM", "ROOM_NAME", "WORLD_TIME", "CLIENT_ID",
|
||||
# "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"
|
||||
|
||||
OOB_SENDABLE = {
|
||||
"CHARACTER_NAME": lambda o: o.key,
|
||||
"SERVER_ID": lambda o: settings.SERVERNAME,
|
||||
"ROOM_NAME": lambda o: o.db_location.key,
|
||||
"ANSI_COLORS": lambda o: True,
|
||||
"XTERM_256_COLORS": lambda o: True,
|
||||
"UTF_8": lambda o: True
|
||||
}
|
||||
|
||||
# mapping for which properties may be tracked. Each callable should return a tuple (type, value) where
|
||||
# the type is one of "field" or "attribute" depending on what is being tracked.
|
||||
OOB_REPORTABLE = {
|
||||
"CHARACTER_NAME": lambda o: ("field", o.key),
|
||||
"ROOM_NAME": lambda o: ("attribute", o.db_location.key)
|
||||
}
|
||||
|
|
@ -1,317 +0,0 @@
|
|||
"""
|
||||
Out-of-band default plugin commands available for OOB handler. This
|
||||
follows the standards defined by the MSDP out-of-band protocol
|
||||
(http://tintin.sourceforge.net/msdp/)
|
||||
|
||||
This module is pointed to by settings.OOB_PLUGIN_MODULES. All functions
|
||||
(not classes) defined globally in this module will be made available
|
||||
to the oob mechanism.
|
||||
|
||||
function execution - the oob protocol can execute a function directly on
|
||||
the server. The available functions must be defined
|
||||
as global functions via settings.OOB_PLUGIN_MODULES.
|
||||
repeat func execution - the oob protocol can request a given function be
|
||||
executed repeatedly at a regular interval. This
|
||||
uses an internal script pool.
|
||||
tracking - the oob protocol can request Evennia to track changes to
|
||||
fields on objects, as well as changes in Attributes. This is
|
||||
done by dynamically adding tracker-objects on entities. The
|
||||
behaviour of those objects can be customized via
|
||||
settings.OOB_PLUGIN_MODULES.
|
||||
|
||||
What goes into the OOB_PLUGIN_MODULES is a list of modules with input
|
||||
for the OOB system.
|
||||
|
||||
oob functions have the following call signature:
|
||||
function(caller, session, *args, **kwargs)
|
||||
|
||||
oob trackers should build upon the OOBTracker class in this module
|
||||
module and implement a minimum of the same functionality.
|
||||
|
||||
a global function oob_error will be used as optional error management.
|
||||
"""
|
||||
from django.conf import settings
|
||||
from src.utils.utils import to_str
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_NA = lambda o: (None, "N/A") # not implemented
|
||||
|
||||
# default properties defined by the MSDP protocol. These are
|
||||
# used by the SEND oob function below. Each entry should point
|
||||
# to a function that takes the relevant object as input and
|
||||
# returns the data it is responsible for. Most of these
|
||||
# are commented out, but kept for reference for each
|
||||
# game to implement.
|
||||
|
||||
OOB_SENDABLE = {
|
||||
## General
|
||||
"CHARACTER_NAME": lambda o: ("db_key", o.key),
|
||||
"SERVER_ID": lambda o: ("settings.SERVERNAME", settings.SERVERNAME),
|
||||
#"SERVER_TIME": _NA,
|
||||
## Character
|
||||
#"AFFECTS": _NA,
|
||||
#"ALIGNMENT": _NA,
|
||||
#"EXPERIENCE": _NA,
|
||||
#"EXPERIENCE_MAX": _NA,
|
||||
#"EXPERIENCE_TNL": _NA,
|
||||
#"HEALTH": _NA,
|
||||
#"HEALTH_MAX": _NA,
|
||||
#"LEVEL": _NA,
|
||||
#"RACE": _NA,
|
||||
#"CLASS": _NA,
|
||||
#"MANA": _NA,
|
||||
#"MANA_MAX": _NA,
|
||||
#"WIMPY": _NA,
|
||||
#"PRACTICE": _NA,
|
||||
#"MONEY": _NA,
|
||||
#"MOVEMENT": _NA,
|
||||
#"MOVEMENT_MAX": _NA,
|
||||
#"HITROLL": _NA,
|
||||
#"DAMROLL": _NA,
|
||||
#"AC": _NA,
|
||||
#"STR": _NA,
|
||||
#"INT": _NA,
|
||||
#"WIS": _NA,
|
||||
#"DEX": _NA,
|
||||
#"CON": _NA,
|
||||
## Combat
|
||||
#"OPPONENT_HEALTH": _NA,
|
||||
#"OPPONENT_HEALTH_MAX": _NA,
|
||||
#"OPPONENT_LEVEL": _NA,
|
||||
#"OPPONENT_NAME": _NA,
|
||||
## World
|
||||
#"AREA_NAME": _NA,
|
||||
#"ROOM_EXITS": _NA,
|
||||
#"ROOM_VNUM": _NA,
|
||||
"ROOM_NAME": lambda o: ("db_location", o.db_location.key),
|
||||
#"WORLD_TIME": _NA,
|
||||
## Configurable variables
|
||||
#"CLIENT_ID": _NA,
|
||||
#"CLIENT_VERSION": _NA,
|
||||
#"PLUGIN_ID": _NA,
|
||||
#"ANSI_COLORS": _NA,
|
||||
#"XTERM_256_COLORS": _NA,
|
||||
#"UTF_8": _NA,
|
||||
#"SOUND": _NA,
|
||||
#"MXP": _NA,
|
||||
## GUI variables
|
||||
#"BUTTON_1": _NA,
|
||||
#"BUTTON_2": _NA,
|
||||
#"BUTTON_3": _NA,
|
||||
#"BUTTON_4": _NA,
|
||||
#"BUTTON_5": _NA,
|
||||
#"GAUGE_1": _NA,
|
||||
#"GAUGE_2": _NA,
|
||||
#"GAUGE_3": _NA,
|
||||
#"GAUGE_4": _NA,
|
||||
#"GAUGE_5": _NA
|
||||
}
|
||||
# mapping for which properties may be tracked
|
||||
OOB_REPORTABLE = OOB_SENDABLE
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Tracker classes
|
||||
#
|
||||
# Trackers are added to a given object's trackerhandler and
|
||||
# reports back changes when they happen. They are managed using
|
||||
# the oobhandler's track/untrack mechanism
|
||||
#------------------------------------------------------------
|
||||
|
||||
class TrackerBase(object):
|
||||
"""
|
||||
Base class for OOB Tracker objects.
|
||||
"""
|
||||
def __init__(self, oobhandler, *args, **kwargs):
|
||||
self.oobhandler = oobhandler
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
"Called by tracked objects"
|
||||
pass
|
||||
|
||||
def at_remove(self, *args, **kwargs):
|
||||
"Called when tracker is removed"
|
||||
pass
|
||||
|
||||
|
||||
# Tracker objects stored on objects when using the MSDP report command
|
||||
|
||||
class ReportFieldTracker(TrackerBase):
|
||||
"""
|
||||
Tracker that passively sends data to a stored sessid whenever
|
||||
a named database field changes. The TrackerHandler calls this with
|
||||
the correct arguments.
|
||||
"""
|
||||
def __init__(self, oobhandler, fieldname, sessid, *args, **kwargs):
|
||||
"""
|
||||
name - name of entity to track, such as "db_key"
|
||||
sessid - sessid of session to report to
|
||||
"""
|
||||
self.oobhandler = oobhandler
|
||||
self.fieldname = fieldname
|
||||
self.sessid = sessid
|
||||
|
||||
def update(self, new_value, *args, **kwargs):
|
||||
"Called by cache when updating the tracked entitiy"
|
||||
# use oobhandler to relay data
|
||||
try:
|
||||
# we must never relay objects across the amp, only text data.
|
||||
new_value = new_value.key
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.fieldname,
|
||||
new_value, *args, **kwargs)
|
||||
|
||||
|
||||
class ReportAttributeTracker(TrackerBase):
|
||||
"""
|
||||
Tracker that passively sends data to a stored sessid whenever
|
||||
the Attribute updates. Since the field here is always "db_key",
|
||||
we instead store the name of the attribute to return.
|
||||
"""
|
||||
def __init__(self, oobhandler, fieldname, sessid, attrname, *args, **kwargs):
|
||||
"""
|
||||
attrname - name of attribute to track
|
||||
sessid - sessid of session to report to
|
||||
"""
|
||||
self.oobhandler = oobhandler
|
||||
self.attrname = attrname
|
||||
self.sessid = sessid
|
||||
|
||||
def update(self, new_value, *args, **kwargs):
|
||||
"Called by cache when attribute's db_value field updates"
|
||||
try:
|
||||
new_value = new_value.dbobj
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.attrname, new_value, *args, **kwargs)
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# OOB commands
|
||||
# This defines which internal server commands the OOB handler
|
||||
# makes available to the client. These commands are called
|
||||
# automatically by the OOB mechanism by triggering the
|
||||
# oobhandlers's execute_cmd method with the cmdname and
|
||||
# eventual args/kwargs. All functions defined globally in this
|
||||
# module will be made available to call by the oobhandler. Use
|
||||
# _funcname if you want to exclude one. To allow for python-names
|
||||
# like "list" here, these properties are case-insensitive.
|
||||
#
|
||||
# All OOB commands must be on the form
|
||||
# cmdname(oobhandler, session, *args, **kwargs)
|
||||
#------------------------------------------------------------
|
||||
|
||||
def oob_error(oobhandler, session, errmsg, *args, **kwargs):
|
||||
"""
|
||||
This is a special function 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).
|
||||
"""
|
||||
session.msg(oob=("send", {"ERROR": errmsg}))
|
||||
|
||||
def 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()
|
||||
# the first return argument is treated by the msdp protocol as the
|
||||
# name of the msdp array to return
|
||||
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":
|
||||
session.msg(oob=("list", ("REPORTED_VARIABLES",) +
|
||||
tuple(oobhandler.get_all_tracked(session))))
|
||||
elif mode == "SENDABLE_VARIABLES":
|
||||
session.msg(oob=("list", ("SENDABLE_VARIABLES",) +
|
||||
tuple(key for key in OOB_REPORTABLE.keys())))
|
||||
#elif mode == "CONFIGURABLE_VARIABLES":
|
||||
# pass
|
||||
else:
|
||||
session.msg(oob=("list", ("unsupported mode",)))
|
||||
|
||||
|
||||
def SEND(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This function directly returns the value of the given variable to the
|
||||
session. vartype can be one of
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
ret = {}
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
try:
|
||||
key, value = OOB_SENDABLE.get(name, _NA)(obj)
|
||||
ret[name] = value
|
||||
except Exception, e:
|
||||
ret[name] = str(e)
|
||||
# return result
|
||||
session.msg(oob=("send", ret))
|
||||
|
||||
|
||||
def REPORT(oobhandler, session, *args, **kwargs):
|
||||
"""
|
||||
This creates a tracker instance to track the data given in *args.
|
||||
vartype is one of "prop" (database fields) or "attr" (attributes)
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
key, val = OOB_REPORTABLE.get(name, _NA)(obj)
|
||||
if key:
|
||||
if key.startswith("db_"):
|
||||
oobhandler.track_field(obj, session.sessid,
|
||||
key, ReportFieldTracker)
|
||||
else: # assume attribute
|
||||
oobhandler.track_attribute(obj, session.sessid,
|
||||
key, ReportAttributeTracker)
|
||||
|
||||
|
||||
def UNREPORT(oobhandler, session, vartype="prop", *args, **kwargs):
|
||||
"""
|
||||
This removes tracking for the given data given in *args.
|
||||
vartype is one of of "prop" or "attr".
|
||||
"""
|
||||
obj = session.get_puppet_or_player()
|
||||
if obj:
|
||||
for name in (a.upper() for a in args if a):
|
||||
key, val = OOB_REPORTABLE.get(name, _NA)
|
||||
if key:
|
||||
if key.startswith("db_"):
|
||||
oobhandler.untrack_field(obj, session.sessid, key)
|
||||
else: # assume attribute
|
||||
oobhandler.untrack_attribute(obj, session.sessid, key)
|
||||
|
||||
def ECHO(oobhandler, session, *args, **kwargs):
|
||||
"Test function, returning the args, kwargs"
|
||||
args = ["Return echo:"] + list(args)
|
||||
session.msg(oob=("echo", args, kwargs))
|
||||
|
|
@ -45,7 +45,7 @@ from src.server.sessionhandler import SESSIONS
|
|||
from src.scripts.tickerhandler import Ticker, TickerPool, TickerHandler
|
||||
from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj
|
||||
from src.utils import logger
|
||||
from src.utils.utils import all_from_module, make_iter
|
||||
from src.utils.utils import all_from_module, make_iter, to_str
|
||||
|
||||
_SA = object.__setattr__
|
||||
_GA = object.__getattribute__
|
||||
|
|
@ -55,9 +55,9 @@ _DA = object.__delattr__
|
|||
_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)))
|
||||
# get custom error method or use the default
|
||||
_OOB_ERROR = _OOB_FUNCS.get("oob_error", None)
|
||||
|
||||
# get custom error method or use the default
|
||||
_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):
|
||||
|
|
@ -131,11 +131,12 @@ class TrackerHandler(object):
|
|||
logger.log_trace()
|
||||
|
||||
|
||||
# Tracker loaded by the TrackerHandler
|
||||
# On-object Trackers to load with TrackerHandler
|
||||
|
||||
class TrackerBase(object):
|
||||
"""
|
||||
Base class for OOB Tracker objects.
|
||||
Base class for OOB Tracker objects. Inherit from this
|
||||
to define custom trackers.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
|
@ -148,6 +149,61 @@ class TrackerBase(object):
|
|||
"Called when tracker is removed"
|
||||
pass
|
||||
|
||||
|
||||
class ReportFieldTracker(TrackerBase):
|
||||
"""
|
||||
Tracker that passively sends data to a stored sessid whenever
|
||||
a named database field changes. The TrackerHandler calls this with
|
||||
the correct arguments.
|
||||
"""
|
||||
def __init__(self, oobhandler, fieldname, sessid, *args, **kwargs):
|
||||
"""
|
||||
name - name of entity to track, such as "db_key"
|
||||
sessid - sessid of session to report to
|
||||
"""
|
||||
self.oobhandler = oobhandler
|
||||
self.fieldname = fieldname
|
||||
self.sessid = sessid
|
||||
|
||||
def update(self, new_value, *args, **kwargs):
|
||||
"Called by cache when updating the tracked entitiy"
|
||||
# use oobhandler to relay data
|
||||
try:
|
||||
# we must never relay objects across the amp, only text data.
|
||||
new_value = new_value.key
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.fieldname,
|
||||
new_value, *args, **kwargs)
|
||||
|
||||
|
||||
class ReportAttributeTracker(TrackerBase):
|
||||
"""
|
||||
Tracker that passively sends data to a stored sessid whenever
|
||||
the Attribute updates. Since the field here is always "db_key",
|
||||
we instead store the name of the attribute to return.
|
||||
"""
|
||||
def __init__(self, oobhandler, fieldname, sessid, attrname, *args, **kwargs):
|
||||
"""
|
||||
attrname - name of attribute to track
|
||||
sessid - sessid of session to report to
|
||||
"""
|
||||
self.oobhandler = oobhandler
|
||||
self.attrname = attrname
|
||||
self.sessid = sessid
|
||||
|
||||
def update(self, new_value, *args, **kwargs):
|
||||
"Called by cache when attribute's db_value field updates"
|
||||
try:
|
||||
new_value = new_value.dbobj
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.attrname, new_value, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
# Ticker of auto-updating objects
|
||||
|
||||
class OOBTicker(Ticker):
|
||||
|
|
@ -273,7 +329,7 @@ class OOBHandler(object):
|
|||
sessid = session.sessid
|
||||
return [key[2].lstrip("db_") for key in self.oob_tracker_storage.keys() if key[1] == sessid]
|
||||
|
||||
def track_field(self, obj, sessid, field_name, trackerclass):
|
||||
def track_field(self, obj, sessid, field_name, trackerclass=ReportFieldTracker):
|
||||
"""
|
||||
Shortcut wrapper method for specifically tracking a database field.
|
||||
Takes the tracker class as argument.
|
||||
|
|
@ -289,7 +345,7 @@ class OOBHandler(object):
|
|||
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
|
||||
self._untrack(obj, sessid, field_name)
|
||||
|
||||
def track_attribute(self, obj, sessid, attr_name, trackerclass):
|
||||
def track_attribute(self, obj, sessid, attr_name, trackerclass=ReportAttributeTracker):
|
||||
"""
|
||||
Shortcut wrapper method for specifically tracking the changes of an
|
||||
Attribute on an object. Will create a tracker on the Attribute
|
||||
|
|
@ -332,12 +388,6 @@ class OOBHandler(object):
|
|||
"""
|
||||
self.tickerhandler.remove(self, obj, interval)
|
||||
|
||||
def msg(self, sessid, funcname, *args, **kwargs):
|
||||
"Shortcut to relay oob data back to portal. Used by oob functions."
|
||||
session = self.sessionhandler.session_from_sessid(sessid)
|
||||
#print "oobhandler msg:", sessid, session, funcname, args, kwargs
|
||||
if session:
|
||||
session.msg(oob=(funcname, args, kwargs))
|
||||
|
||||
# access method - called from session.msg()
|
||||
|
||||
|
|
@ -347,7 +397,7 @@ class OOBHandler(object):
|
|||
using *args and **kwargs
|
||||
"""
|
||||
try:
|
||||
print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys()
|
||||
#print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys()
|
||||
oobfunc = _OOB_FUNCS[func_key] # raise traceback if not found
|
||||
oobfunc(self, session, *args, **kwargs)
|
||||
except KeyError,e:
|
||||
|
|
@ -364,5 +414,14 @@ class OOBHandler(object):
|
|||
else:
|
||||
logger.log_trace(errmsg)
|
||||
raise Exception(errmsg)
|
||||
|
||||
def msg(self, sessid, funcname, *args, **kwargs):
|
||||
"Shortcut to force-send an OOB message through the oobhandler to a session"
|
||||
session = self.sessionhandler.session_from_sessid(sessid)
|
||||
#print "oobhandler msg:", sessid, session, funcname, args, kwargs
|
||||
if session:
|
||||
session.msg(oob=(funcname, args, kwargs))
|
||||
|
||||
|
||||
# access object
|
||||
OOB_HANDLER = OOBHandler()
|
||||
|
|
|
|||
|
|
@ -103,15 +103,9 @@ class SessionHandler(object):
|
|||
def oobstruct_parser(self, oobstruct):
|
||||
"""
|
||||
Helper method for each session to use to parse oob structures
|
||||
(The 'oob' kwarg of the msg() method)
|
||||
((cmdname, (args), {}), ...)
|
||||
|
||||
|
||||
Allowed oob structures are:
|
||||
allowed oob structures are
|
||||
|
||||
|
||||
(The 'oob' kwarg of the msg() method).
|
||||
|
||||
Allowed input oob structures are:
|
||||
cmdname
|
||||
((cmdname,), (cmdname,))
|
||||
(cmdname,(arg, ))
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ LOCK_FUNC_MODULES = ("src.locks.lockfuncs",)
|
|||
# Module holding OOB (Out of Band) hook objects. This allows for customization
|
||||
# and expansion of which hooks OOB protocols are allowed to call on the server
|
||||
# protocols for attaching tracker hooks for when various object field change
|
||||
OOB_PLUGIN_MODULES = ["src.server.oob_msdp"]
|
||||
OOB_PLUGIN_MODULES = ["src.server.oob_cmds"]
|
||||
|
||||
######################################################################
|
||||
# Default command sets
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ function echo(message) {
|
|||
doShow("out", "ECHO return: " + message) }
|
||||
|
||||
|
||||
|
||||
|
||||
// Webclient code
|
||||
|
||||
function webclient_init(){
|
||||
|
|
@ -95,6 +93,7 @@ function doSend(){
|
|||
|
||||
if (OOB_debug && outmsg.length > 4 && outmsg.substr(0, 5) == "##OOB") {
|
||||
// test OOB messaging
|
||||
doShow("out", "OOB input: " + outmsg.slice(5))
|
||||
doOOB(JSON.parse(outmsg.slice(5))); }
|
||||
else {
|
||||
// normal output
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue