mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Fixed and refactored OOB system and tested with new websocket client
This commit is contained in:
parent
9ba212c264
commit
c60a5fdea1
10 changed files with 209 additions and 128 deletions
|
|
@ -144,9 +144,9 @@ class ObjectDB(TypedObject):
|
|||
# make sure to sync the contents cache when initializing
|
||||
#_GA(self, "contents_update")()
|
||||
|
||||
def _at_db_player_presave(self):
|
||||
def _at_db_player_postsave(self):
|
||||
"""
|
||||
This hook is called automatically just before the player field is saved.
|
||||
This hook is called automatically after the player field is saved.
|
||||
"""
|
||||
# we need to re-cache this for superusers to bypass.
|
||||
self.locks.cache_lock_bypass(self)
|
||||
|
|
|
|||
|
|
@ -80,28 +80,28 @@ def hashid(obj, suffix=""):
|
|||
#------------------------------------------------------------
|
||||
|
||||
# callback to field pre_save signal (connected in src.server.server)
|
||||
def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwargs):
|
||||
"""
|
||||
Called at the beginning of the field save operation. The save method
|
||||
must be called with the update_fields keyword in order to be most efficient.
|
||||
This method should NOT save; rather it is the save() that triggers this
|
||||
function. Its main purpose is to allow to plug-in a save handler and oob
|
||||
handlers.
|
||||
"""
|
||||
if raw:
|
||||
return
|
||||
if update_fields:
|
||||
# this is a list of strings at this point. We want field objects
|
||||
update_fields = (_GA(_GA(instance, "_meta"), "get_field_by_name")(field)[0] for field in update_fields)
|
||||
else:
|
||||
# meta.fields are already field objects; get them all
|
||||
update_fields = _GA(_GA(instance, "_meta"), "fields")
|
||||
for field in update_fields:
|
||||
fieldname = field.name
|
||||
handlername = "_at_%s_presave" % fieldname
|
||||
handler = _GA(instance, handlername) if handlername in _GA(sender, '__dict__') else None
|
||||
if callable(handler):
|
||||
handler()
|
||||
#def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwargs):
|
||||
# """
|
||||
# Called at the beginning of the field save operation. The save method
|
||||
# must be called with the update_fields keyword in order to be most efficient.
|
||||
# This method should NOT save; rather it is the save() that triggers this
|
||||
# function. Its main purpose is to allow to plug-in a save handler and oob
|
||||
# handlers.
|
||||
# """
|
||||
# if raw:
|
||||
# return
|
||||
# if update_fields:
|
||||
# # this is a list of strings at this point. We want field objects
|
||||
# update_fields = (_GA(_GA(instance, "_meta"), "get_field_by_name")(field)[0] for field in update_fields)
|
||||
# else:
|
||||
# # meta.fields are already field objects; get them all
|
||||
# update_fields = _GA(_GA(instance, "_meta"), "fields")
|
||||
# for field in update_fields:
|
||||
# fieldname = field.name
|
||||
# handlername = "_at_%s_presave" % fieldname
|
||||
# handler = _GA(instance, handlername) if handlername in _GA(sender, '__dict__') else None
|
||||
# if callable(handler):
|
||||
# handler()
|
||||
|
||||
|
||||
def field_post_save(sender, instance=None, update_fields=None, raw=False, **kwargs):
|
||||
|
|
|
|||
|
|
@ -18,14 +18,19 @@ 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
|
||||
A function named OOB_ERROR will retrieve error strings if it is
|
||||
defined. It will get the error message as its 3rd argument.
|
||||
|
||||
Data is usually returned via
|
||||
session.msg(oob=(cmdname, (args,), {kwargs}))
|
||||
Note that args, kwargs must be iterable/dict, non-iterables will
|
||||
be interpreted as a new command name.
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_NA_REPORT = lambda o: (None, "N/A")
|
||||
_NA_SEND = lambda o: "N/A"
|
||||
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -33,26 +38,25 @@ _NA_SEND = lambda o: "N/A"
|
|||
# cmdname(oobhandler, session, *args, **kwargs)
|
||||
#------------------------------------------------------------
|
||||
|
||||
def _OOB_ERROR(oobhandler, session, errmsg, *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}))
|
||||
session.msg(oob=("err", ("ERROR " + errmsg,)))
|
||||
|
||||
|
||||
def ECHO(oobhandler, session, *args, **kwargs):
|
||||
"Test/debug function, simply returning the args and kwargs"
|
||||
session.msg(oob=("echo", args, kwargs))
|
||||
|
||||
|
||||
##OOB{"SEND":"CHARACTER_NAME"}
|
||||
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:
|
||||
|
|
@ -62,14 +66,18 @@ def SEND(oobhandler, session, *args, **kwargs):
|
|||
ret[name] = value
|
||||
except Exception, e:
|
||||
ret[name] = str(e)
|
||||
# return result
|
||||
session.msg(oob=("send", ret))
|
||||
|
||||
session.msg(oob=("send", ret))
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
##OOB{"REPORT":"TEST"}
|
||||
def 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.
|
||||
|
||||
|
|
@ -79,27 +87,37 @@ def REPORT(oobhandler, session, *args, **kwargs):
|
|||
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)
|
||||
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.",)))
|
||||
|
||||
|
||||
def UNREPORT(oobhandler, session, vartype="prop", *args, **kwargs):
|
||||
##OOB{"UNREPORT": "TEST"}
|
||||
def 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):
|
||||
typ, val = OOB_REPORTABLE.get(name, _NA_REPORT)
|
||||
if typ == "field":
|
||||
oobhandler.untrack_field(obj, session.sessid, name)
|
||||
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, name)
|
||||
oobhandler.untrack_attribute(obj, session.sessid, trackname)
|
||||
else:
|
||||
session.msg(oob=("err", ("You must log in first.",)))
|
||||
|
||||
|
||||
##OOB{"LIST":"COMMANDS"}
|
||||
def LIST(oobhandler, session, mode, *args, **kwargs):
|
||||
"""
|
||||
List available properties. Mode is the type of information
|
||||
|
|
@ -135,15 +153,42 @@ def LIST(oobhandler, session, mode, *args, **kwargs):
|
|||
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))))
|
||||
# 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":
|
||||
# pass
|
||||
elif mode == "CONFIGURABLE_VARIABLES":
|
||||
# Not implemented (game specific)
|
||||
pass
|
||||
else:
|
||||
session.msg(oob=("list", ("unsupported mode",)))
|
||||
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 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)
|
||||
|
||||
|
||||
##OOB{"UNREPEAT":10}
|
||||
def UNREPEAT(oobhandler, session, interval):
|
||||
"""
|
||||
Disable repeating callback
|
||||
"""
|
||||
oobhandler.unrepeat(None, session.sessid, interval)
|
||||
|
||||
|
||||
# Mapping for how to retrieve each property name.
|
||||
|
|
@ -167,9 +212,10 @@ OOB_SENDABLE = {
|
|||
"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.
|
||||
# mapping for which properties may be tracked. Each value points either to a database field
|
||||
# (starting with db_*) or an Attribute name.
|
||||
OOB_REPORTABLE = {
|
||||
"CHARACTER_NAME": lambda o: ("field", o.key),
|
||||
"ROOM_NAME": lambda o: ("attribute", o.db_location.key)
|
||||
"CHARACTER_NAME": "db_key",
|
||||
"ROOM_NAME": "db_location",
|
||||
"TEST" : "test"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ messages.
|
|||
|
||||
from inspect import isfunction
|
||||
from twisted.internet.defer import inlineCallbacks
|
||||
from twisted.internet.task import LoopingCall
|
||||
from django.conf import settings
|
||||
from src.server.models import ServerConfig
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
|
|
@ -57,12 +56,12 @@ 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)
|
||||
_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"
|
||||
session.msg(oob=("send", {"ERROR": errmsg}))
|
||||
session.msg(oob=("err", ("ERROR ", errmsg)))
|
||||
_OOB_ERROR = oob_error
|
||||
|
||||
|
||||
|
|
@ -105,16 +104,16 @@ class TrackerHandler(object):
|
|||
|
||||
def remove(self, fieldname, trackerclass, *args, **kwargs):
|
||||
"""
|
||||
Remove tracker from handler. Raises KeyError if tracker
|
||||
is not found.
|
||||
Remove identified tracker from TrackerHandler.
|
||||
Raises KeyError if tracker is not found.
|
||||
"""
|
||||
trackerkey = trackerclass.__name__
|
||||
tracker = self.tracktargets[fieldname][trackerkey]
|
||||
try:
|
||||
tracker.at_delete(*args, **kwargs)
|
||||
tracker.at_remove(*args, **kwargs)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
del tracker
|
||||
del self.tracktargets[fieldname][trackerkey]
|
||||
self.ntrackers -= 1
|
||||
if self.ntrackers <= 0:
|
||||
# if there are no more trackers, clean this handler
|
||||
|
|
@ -173,9 +172,9 @@ class ReportFieldTracker(TrackerBase):
|
|||
new_value = new_value.key
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
kwargs[self.fieldname] = new_value
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.fieldname,
|
||||
new_value, *args, **kwargs)
|
||||
self.oobhandler.msg(self.sessid, "report", *args, **kwargs)
|
||||
|
||||
|
||||
class ReportAttributeTracker(TrackerBase):
|
||||
|
|
@ -199,8 +198,9 @@ class ReportAttributeTracker(TrackerBase):
|
|||
new_value = new_value.dbobj
|
||||
except AttributeError:
|
||||
new_value = to_str(new_value, force_string=True)
|
||||
kwargs[self.attrname] = new_value
|
||||
# this is a wrapper call for sending oob data back to session
|
||||
self.oobhandler.msg(self.sessid, "report", self.attrname, new_value, *args, **kwargs)
|
||||
self.oobhandler.msg(self.sessid, "report", *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
|
@ -208,25 +208,21 @@ class ReportAttributeTracker(TrackerBase):
|
|||
|
||||
class OOBTicker(Ticker):
|
||||
"""
|
||||
Version of Ticker that calls OOB_FUNC rather than trying to call
|
||||
Version of Ticker that executes an executable rather than trying to call
|
||||
a hook method.
|
||||
"""
|
||||
@inlineCallbacks
|
||||
def _callback(self, oobhandler, sessions):
|
||||
def _callback(self):
|
||||
"See original for more info"
|
||||
for key, (_, args, kwargs) in self.subscriptions.items():
|
||||
session = sessions.session_from_sessid(kwargs.get("sessid"))
|
||||
# args = (sessid, callback_function)
|
||||
session = SESSIONS.session_from_sessid(args[0])
|
||||
try:
|
||||
oobhandler.execute_cmd(session, kwargs.get("func_key"), *args, **kwargs)
|
||||
# execute the oob callback
|
||||
yield args[1](OOB_HANDLER, session, *args[2:], **kwargs)
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
|
||||
def __init__(self, interval):
|
||||
"Sets up the Ticker"
|
||||
self.interval = interval
|
||||
self.subscriptions = {}
|
||||
self.task = LoopingCall(self._callback, OOB_HANDLER, SESSIONS)
|
||||
|
||||
class OOBTickerPool(TickerPool):
|
||||
ticker_class = OOBTicker
|
||||
|
||||
|
|
@ -270,9 +266,9 @@ class OOBHandler(object):
|
|||
tracker_storage = ServerConfig.objects.conf(key="oob_tracker_storage")
|
||||
if tracker_storage:
|
||||
self.oob_tracker_storage = dbunserialize(tracker_storage)
|
||||
#print "recovered from tracker_storage:", self.oob_tracker_storage
|
||||
for (obj, sessid, fieldname, trackerclass, args, kwargs) in self.oob_tracker_storage.values():
|
||||
self.track(unpack_dbobj(obj), sessid, fieldname, trackerclass, *args, **kwargs)
|
||||
#print "restoring tracking:",obj, sessid, fieldname, trackerclass
|
||||
self._track(unpack_dbobj(obj), sessid, fieldname, trackerclass, *args, **kwargs)
|
||||
# make sure to purge the storage
|
||||
ServerConfig.objects.conf(key="oob_tracker_storage", delete=True)
|
||||
self.tickerhandler.restore()
|
||||
|
|
@ -302,6 +298,7 @@ class OOBHandler(object):
|
|||
storekey = (obj_packed, sessid, propname)
|
||||
stored = (obj_packed, sessid, propname, trackerclass, args, kwargs)
|
||||
self.oob_tracker_storage[storekey] = stored
|
||||
#print "_track:", obj, id(obj), obj.__dict__
|
||||
|
||||
def _untrack(self, obj, sessid, propname, trackerclass, *args, **kwargs):
|
||||
"""
|
||||
|
|
@ -312,9 +309,8 @@ class OOBHandler(object):
|
|||
obj = obj.dbobj
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# call at_delete hook
|
||||
# call at_remove hook on the trackerclass
|
||||
_GA(obj, "_trackerhandler").remove(propname, trackerclass, *args, **kwargs)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
|
@ -327,7 +323,7 @@ class OOBHandler(object):
|
|||
Get the names of all variables this session is tracking.
|
||||
"""
|
||||
sessid = session.sessid
|
||||
return [key[2].lstrip("db_") for key in self.oob_tracker_storage.keys() if key[1] == sessid]
|
||||
return [stored for key, stored in self.oob_tracker_storage.items() if key[1] == sessid]
|
||||
|
||||
def track_field(self, obj, sessid, field_name, trackerclass=ReportFieldTracker):
|
||||
"""
|
||||
|
|
@ -336,14 +332,14 @@ class OOBHandler(object):
|
|||
"""
|
||||
# all database field names starts with db_*
|
||||
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
|
||||
self._track(obj, sessid, field_name, trackerclass)
|
||||
self._track(obj, sessid, field_name, trackerclass, field_name)
|
||||
|
||||
def untrack_field(self, obj, sessid, field_name):
|
||||
def untrack_field(self, obj, sessid, field_name, trackerclass=ReportFieldTracker):
|
||||
"""
|
||||
Shortcut for untracking a database field. Uses OOBTracker by defualt
|
||||
"""
|
||||
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
|
||||
self._untrack(obj, sessid, field_name)
|
||||
self._untrack(obj, sessid, field_name, trackerclass)
|
||||
|
||||
def track_attribute(self, obj, sessid, attr_name, trackerclass=ReportAttributeTracker):
|
||||
"""
|
||||
|
|
@ -353,14 +349,15 @@ class OOBHandler(object):
|
|||
"""
|
||||
# get the attribute object if we can
|
||||
try:
|
||||
obj = obj.dbobj
|
||||
attrobj = obj.dbobj
|
||||
except AttributeError:
|
||||
pass
|
||||
attrobj = _GA(obj, "attributes").get(attr_name, return_obj=True)
|
||||
attrobj = obj.attributes.get(attr_name, return_obj=True)
|
||||
#print "track_attribute attrobj:", attrobj, id(attrobj)
|
||||
if attrobj:
|
||||
self._track(attrobj, sessid, "db_value", trackerclass, attr_name)
|
||||
|
||||
def untrack_attribute(self, obj, sessid, attr_name, trackerclass):
|
||||
def untrack_attribute(self, obj, sessid, attr_name, trackerclass=ReportAttributeTracker):
|
||||
"""
|
||||
Shortcut for deactivating tracking for a given attribute.
|
||||
"""
|
||||
|
|
@ -368,25 +365,24 @@ class OOBHandler(object):
|
|||
obj = obj.dbobj
|
||||
except AttributeError:
|
||||
pass
|
||||
attrobj = _GA(obj, "attributes").get(attr_name, return_obj=True)
|
||||
attrobj = obj.attributes.get(attr_name, return_obj=True)
|
||||
if attrobj:
|
||||
self._untrack(attrobj, sessid, attr_name, trackerclass)
|
||||
self._untrack(attrobj, sessid, "db_value", trackerclass, attr_name)
|
||||
|
||||
def repeat(self, obj, sessid, func_key, interval=20, *args, **kwargs):
|
||||
def repeat(self, obj, sessid, interval=20, callback=None, *args, **kwargs):
|
||||
"""
|
||||
Start a repeating action. Every interval seconds,
|
||||
the oobfunc corresponding to func_key is called with
|
||||
args and kwargs.
|
||||
Start a repeating action. Every interval seconds, trigger
|
||||
callback(*args, **kwargs). The callback is called with
|
||||
args and kwargs; note that *args and **kwargs may not contain
|
||||
anything un-picklable (use dbrefs if wanting to use objects).
|
||||
"""
|
||||
if not func_key in _OOB_FUNCS:
|
||||
raise KeyError("%s is not a valid OOB function name.")
|
||||
self.tickerhandler.add(self, obj, interval, func_key=func_key, sessid=sessid, *args, **kwargs)
|
||||
self.tickerhandler.add(obj, interval, sessid, callback, *args, **kwargs)
|
||||
|
||||
def unrepeat(self, obj, sessid, func_key, interval=20):
|
||||
def unrepeat(self, obj, sessid, interval=20):
|
||||
"""
|
||||
Stop a repeating action
|
||||
"""
|
||||
self.tickerhandler.remove(self, obj, interval)
|
||||
self.tickerhandler.remove(obj, interval)
|
||||
|
||||
|
||||
# access method - called from session.msg()
|
||||
|
|
@ -396,23 +392,26 @@ class OOBHandler(object):
|
|||
Retrieve oobfunc from OOB_FUNCS and execute it immediately
|
||||
using *args and **kwargs
|
||||
"""
|
||||
try:
|
||||
#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:
|
||||
errmsg = "OOB Error: function '%s' not recognized: %s" % (func_key, e)
|
||||
oobfunc = _OOB_FUNCS.get(func_key, None)
|
||||
if not oobfunc:
|
||||
# function not found
|
||||
errmsg = "OOB Error: function '%s' not recognized." % func_key
|
||||
if _OOB_ERROR:
|
||||
_OOB_ERROR(self, session, errmsg, *args, **kwargs)
|
||||
logger.log_trace()
|
||||
else:
|
||||
logger.log_trace(errmsg)
|
||||
raise KeyError(errmsg)
|
||||
return
|
||||
|
||||
# execute the found function
|
||||
try:
|
||||
#print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys()
|
||||
oobfunc(self, session, *args, **kwargs)
|
||||
except Exception, err:
|
||||
errmsg = "OOB Error: Exception in '%s'(%s, %s):\n%s" % (func_key, args, kwargs, err)
|
||||
if _OOB_ERROR:
|
||||
_OOB_ERROR(self, session, errmsg, *args, **kwargs)
|
||||
else:
|
||||
logger.log_trace(errmsg)
|
||||
logger.log_trace(errmsg)
|
||||
raise Exception(errmsg)
|
||||
|
||||
def msg(self, sessid, funcname, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import json
|
|||
from twisted.internet.protocol import Protocol
|
||||
from src.server.session import Session
|
||||
from src.utils.logger import log_trace
|
||||
from src.utils.utils import to_str
|
||||
from src.utils.utils import to_str, make_iter
|
||||
from src.utils.text2html import parse_html
|
||||
|
||||
|
||||
|
|
@ -85,7 +85,8 @@ class WebSocketClient(Protocol, Session):
|
|||
try:
|
||||
oobdata = json.loads(string)
|
||||
for (key, args) in oobdata.items():
|
||||
self.data_in(text=None, oob=(key, args))
|
||||
#print "oob data in:", (key, args)
|
||||
self.data_in(text=None, oob=(key, make_iter(args)))
|
||||
except Exception:
|
||||
log_trace("Websocket malformed OOB request: %s" % string)
|
||||
else:
|
||||
|
|
@ -119,6 +120,7 @@ class WebSocketClient(Protocol, Session):
|
|||
self.sendLine(str(e))
|
||||
if "oob" in kwargs:
|
||||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
|
||||
#print "oob data_out:", "OOB" + json.dumps(oobstruct)
|
||||
self.sendLine("OOB" + json.dumps(oobstruct))
|
||||
raw = kwargs.get("raw", False)
|
||||
nomarkup = kwargs.get("nomarkup", False)
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ from src.server.sessionhandler import SESSIONS
|
|||
# setting up server-side field cache
|
||||
|
||||
from django.db.models.signals import post_save
|
||||
from src.server.caches import field_pre_save
|
||||
from src.server.caches import field_post_save
|
||||
#pre_save.connect(field_pre_save, dispatch_uid="fieldcache")
|
||||
post_save.connect(field_pre_save, dispatch_uid="fieldcache")
|
||||
post_save.connect(field_post_save, dispatch_uid="fieldcache")
|
||||
|
||||
#from src.server.caches import post_attr_update
|
||||
#from django.db.models.signals import m2m_changed
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ class ServerSession(Session):
|
|||
if not _OOB_HANDLER:
|
||||
from src.server.oobhandler import OOB_HANDLER as _OOB_HANDLER
|
||||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob", None))
|
||||
#print "session.data_in: oobstruct:",oobstruct
|
||||
for (funcname, args, kwargs) in oobstruct:
|
||||
if funcname:
|
||||
_OOB_HANDLER.execute_cmd(self, funcname, *args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -136,14 +136,17 @@ class SessionHandler(object):
|
|||
elif isinstance(oobstruct[1], (tuple, list)):
|
||||
# cmdname, (args,)
|
||||
return (oobstruct[0].lower(), list(oobstruct[1]), {})
|
||||
else:
|
||||
# cmdname, cmdname
|
||||
return ((oobstruct[0].lower(), (), {}), (oobstruct[1].lower(), (), {}))
|
||||
else:
|
||||
# cmdname, (args,), {kwargs}
|
||||
return (oobstruct[0].lower(), list(oobstruct[1]), dict(oobstruct[2]))
|
||||
|
||||
if hasattr(oobstruct, "__iter__"):
|
||||
# differentiate between (cmdname, cmdname),
|
||||
# (cmdname, args, kwargs) and ((cmdname,args,kwargs),
|
||||
# (cmdname,args,kwargs), ...)
|
||||
# (cmdname, (args), {kwargs}) and ((cmdname,(args),{kwargs}),
|
||||
# (cmdname,(args),{kwargs}), ...)
|
||||
|
||||
if oobstruct and isinstance(oobstruct[0], basestring):
|
||||
return (list(_parse(oobstruct)),)
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ _DA = object.__delattr__
|
|||
#------------------------------------------------------------
|
||||
|
||||
#class Attribute(SharedMemoryModel):
|
||||
class Attribute(WeakSharedMemoryModel):
|
||||
class Attribute(SharedMemoryModel):
|
||||
"""
|
||||
Abstract django model.
|
||||
|
||||
|
|
@ -173,13 +173,6 @@ class Attribute(WeakSharedMemoryModel):
|
|||
"""
|
||||
self.db_value = to_pickle(new_value)
|
||||
self.save(update_fields=["db_value"])
|
||||
try:
|
||||
# eventual OOB hook
|
||||
#self._track_db_value_change.update(self.cached_value)
|
||||
self._track_db_value_change.update(self.new_value)
|
||||
except AttributeError:
|
||||
pass
|
||||
return
|
||||
|
||||
#@value.deleter
|
||||
def __value_del(self):
|
||||
|
|
|
|||
|
|
@ -20,13 +20,38 @@ var OOB_debug = true
|
|||
|
||||
// Custom OOB functions
|
||||
// functions defined here can be called by name by the server. For
|
||||
// example the OOB{"echo":arguments} will trigger a function named
|
||||
// echo(arguments).
|
||||
// example the OOB{"echo":(args),{kwargs}} will trigger a function named
|
||||
// echo(args, kwargs).
|
||||
|
||||
|
||||
function echo(message) {
|
||||
function echo(args, kwargs) {
|
||||
// example echo function.
|
||||
doShow("out", "ECHO return: " + message) }
|
||||
doShow("out", "ECHO return: " + args) }
|
||||
|
||||
function list (args, kwargs) {
|
||||
// show in main window
|
||||
doShow("out", args) }
|
||||
|
||||
function send (args, kwargs) {
|
||||
// show in main window. SEND returns kwargs {name:value}.
|
||||
for (sendvalue in kwargs) {
|
||||
doShow("out", sendvalue + " = " + kwargs[sendvalue]);}
|
||||
}
|
||||
|
||||
function report (args, kwargs) {
|
||||
// show in main window. REPORT returns kwargs
|
||||
// {attrfieldname:value}
|
||||
for (name in kwargs) {
|
||||
doShow("out", name + " = " + kwargs[name]) }
|
||||
}
|
||||
|
||||
function repeat (args, kwargs) {
|
||||
// called by repeating oob funcs
|
||||
doShow("out", args) }
|
||||
|
||||
function err (args, kwargs) {
|
||||
// display error
|
||||
doShow("err", args) }
|
||||
|
||||
|
||||
// Webclient code
|
||||
|
|
@ -61,15 +86,20 @@ function onMessage(evt) {
|
|||
var inmsg = evt.data
|
||||
if (inmsg.length > 3 && inmsg.substr(0, 3) == "OOB") {
|
||||
// dynamically call oob methods, if available
|
||||
try {var oobarray = JSON.parse(inmsg.slice(3));} // everything after OOB }
|
||||
try {
|
||||
var oobarray = JSON.parse(inmsg.slice(3));} // everything after OOB }
|
||||
catch(err) {
|
||||
// not JSON packed - a normal text
|
||||
doShow('out', err + " " + inmsg);
|
||||
doShow('out', inmsg);
|
||||
return;
|
||||
}
|
||||
for (var ind in oobarray) {
|
||||
try { window[oobarray[ind][0]](oobarray[ind][1]) }
|
||||
catch(err) { doShow("err", "Could not execute OOB function " + oobtuple[0] + "(" + oobtuple[1] + ")!") }
|
||||
if (typeof oobarray != "undefined") {
|
||||
for (var ind in oobarray) {
|
||||
try {
|
||||
window[oobarray[ind][0]](oobarray[ind][1], oobarray[ind][2]) }
|
||||
catch(err) {
|
||||
doShow("err", "Could not execute js OOB function '" + oobarray[ind][0] + "(" + oobarray[ind][1] + oobarray[ind][2] + ")'") }
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -93,8 +123,15 @@ 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))); }
|
||||
try {
|
||||
doShow("out", "OOB input: " + outmsg.slice(5));
|
||||
if (outmsg.length == 5) {
|
||||
doShow("err", "OOB testing syntax: ##OOB{\"cmdname:args, ...}"); }
|
||||
else {
|
||||
doOOB(JSON.parse(outmsg.slice(5))); } }
|
||||
catch(err) {
|
||||
doShow("err", err) }
|
||||
}
|
||||
else {
|
||||
// normal output
|
||||
websocket.send(outmsg); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue