diff --git a/src/server/amp.py b/src/server/amp.py index 97adaf375..6d2c21ff4 100644 --- a/src/server/amp.py +++ b/src/server/amp.py @@ -34,10 +34,6 @@ SERVER_RESTART = os.path.join(settings.GAME_DIR, "server.restart") # i18n from django.utils.translation import ugettext as _ -# Signals - - - def get_restart_mode(restart_file): """ @@ -141,6 +137,24 @@ class MsgServer2Portal(amp.Command): errors = [(Exception, 'EXCEPTION')] response = [] +class OOBPortal2Server(amp.Command): + """ + OOB data portal -> server + """ + arguments = [('sessid', amp.Integer()), + ('data', amp.String())] + errors = [(Exception, "EXCEPTION")] + response = [] + +class OOBServer2Portal(amp.Command): + """ + OOB data server -> portal + """ + arguments = [('sessid', amp.Integer()), + ('data', amp.String())] + errors = [(Exception, "EXCEPTION")] + response = [] + class ServerAdmin(amp.Command): """ Portal -> Server @@ -168,6 +182,8 @@ class PortalAdmin(amp.Command): errors = [(Exception, 'EXCEPTION')] response = [] +dumps = lambda data: utils.to_str(pickle.dumps(data, pickle.HIGHEST_PROTOCOL)) +loads = lambda data: pickle.loads(utils.to_str(data)) #------------------------------------------------------------ # Core AMP protocol for communication Server <-> Portal @@ -220,7 +236,7 @@ class AMPProtocol(amp.AMP): Relays message to server. This method is executed on the Server. """ #print "msg portal -> server (server side):", sessid, msg - self.factory.server.sessions.data_in(sessid, msg, pickle.loads(utils.to_str(data))) + self.factory.server.sessions.data_in(sessid, msg, loads(data)) return {} MsgPortal2Server.responder(amp_msg_portal2server) @@ -232,7 +248,7 @@ class AMPProtocol(amp.AMP): self.callRemote(MsgPortal2Server, sessid=sessid, msg=msg, - data=utils.to_str(pickle.dumps(data))).addErrback(self.errback, "MsgPortal2Server") + data=dumps(data)).addErrback(self.errback, "MsgPortal2Server") # Server -> Portal message @@ -241,7 +257,7 @@ class AMPProtocol(amp.AMP): Relays message to Portal. This method is executed on the Portal. """ #print "msg server->portal (portal side):", sessid, msg - self.factory.portal.sessions.data_out(sessid, msg, pickle.loads(utils.to_str(data))) + self.factory.portal.sessions.data_out(sessid, msg, loads(data)) return {} MsgServer2Portal.responder(amp_msg_server2portal) @@ -253,8 +269,50 @@ class AMPProtocol(amp.AMP): self.callRemote(MsgServer2Portal, sessid=sessid, msg=utils.to_str(msg), - data=utils.to_str(pickle.dumps(data))).addErrback(self.errback, "MsgServer2Portal") + data=dumps(data)).addErrback(self.errback, "OOBServer2Portal") + # OOB Portal -> Server + + # Portal -> Server Msg + + def amp_oob_portal2server(self, sessid, data): + """ + Relays out-of-band data to server. This method is executed on the Server. + """ + #print "oob portal -> server (server side):", sessid, loads(data) + self.factory.server.sessions.oob_data_in(sessid, loads(data)) + return {} + OOBPortal2Server.responder(amp_oob_portal2server) + + def call_remote_OOBPortal2Server(self, sessid, data=""): + """ + Access method called by the Portal and executed on the Portal. + """ + #print "oob portal->server (portal side):", sessid, data + self.callRemote(OOBPortal2Server, + sessid=sessid, + data=dumps(data)).addErrback(self.errback, "OOBPortal2Server") + + # Server -> Portal message + + def amp_oob_server2portal(self, sessid, data): + """ + Relays out-of-band data to Portal. This method is executed on the Portal. + """ + #print "oob server->portal (portal side):", sessid, data + self.factory.portal.sessions.oob_data_out(sessid, loads(data)) + return {} + OOBServer2Portal.responder(amp_oob_server2portal) + + def call_remote_OOBServer2Portal(self, sessid, data=""): + """ + Access method called by the Server and executed on the Server. + """ + #print "oob server->portal (server side):", sessid, data + self.callRemote(OOBServer2Portal, + sessid=sessid, + data=dumps(data)).addErrback(self.errback, "OOBServer2Portal") + # Server administration from the Portal side @@ -264,7 +322,7 @@ class AMPProtocol(amp.AMP): operations on the server. This is executed on the Server. """ - data = pickle.loads(utils.to_str(data)) + data = loads(data) #print "serveradmin (server side):", sessid, operation, data @@ -315,7 +373,7 @@ class AMPProtocol(amp.AMP): Access method called by the Portal and Executed on the Portal. """ #print "serveradmin (portal side):", sessid, operation, data - data = utils.to_str(pickle.dumps(data)) + data = dumps(data) self.callRemote(ServerAdmin, sessid=sessid, @@ -329,7 +387,7 @@ class AMPProtocol(amp.AMP): This allows the server to perform admin operations on the portal. This is executed on the Portal. """ - data = pickle.loads(utils.to_str(data)) + data = loads(data) #print "portaladmin (portal side):", sessid, operation, data if operation == 'SLOGIN': # 'server_session_login' @@ -376,7 +434,7 @@ class AMPProtocol(amp.AMP): Access method called by the server side. """ #print "portaladmin (server side):", sessid, operation, data - data = utils.to_str(pickle.dumps(data)) + data = dumps(data) self.callRemote(PortalAdmin, sessid=sessid, diff --git a/src/server/serversession.py b/src/server/serversession.py index 450508e75..f2c2c8c29 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -12,12 +12,16 @@ from datetime import datetime from django.conf import settings from src.scripts.models import ScriptDB from src.comms.models import Channel -from src.utils import logger +from src.utils import logger, utils from src.commands import cmdhandler, cmdsethandler +from src.server.session import Session IDLE_COMMAND = settings.IDLE_COMMAND - -from src.server.session import Session + +# load optional out-of-band function module +OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE +if OOB_FUNC_MODULE: + OOB_FUNC_MODULE = utils.mod_import(settings.OOB_FUNC_MODULE) # i18n from django.utils.translation import ugettext as _ @@ -208,6 +212,44 @@ class ServerSession(Session): """ self.sessionhandler.data_out(self, msg, data) + + def oob_data_in(self, data): + """ + This receives out-of-band data from the Portal. + + This method parses the data input (a dict) and uses + it to launch correct methods from those plugged into + the system. + + data = {funcname: ( [args], {kwargs]), + funcname: ( [args], {kwargs}), ...} + + example: + data = {"get_hp": ([], {}), + "update_counter", (["counter1"], {"now":True}) } + """ + + print "server: " + outdata = {} + + for funcname, argtuple in data.items(): + # loop through the data, calling available functions. + func = OOB_FUNC_MODULE.__dict__.get(funcname, None) + if func: + outdata[funcname] = func(*argtuple[0], **argtuple[1]) + else: + logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % funcname) + if outdata: + self.oob_data_out(outdata) + + + def oob_data_out(self, data): + """ + This sends data from Server to the Portal across the AMP connection. + """ + self.sessionhandler.oob_data_out(self, data) + + def __eq__(self, other): return self.address == other.address diff --git a/src/server/session.py b/src/server/session.py index 519450058..ed954c0bd 100644 --- a/src/server/session.py +++ b/src/server/session.py @@ -123,3 +123,20 @@ class Session(object): """ pass + def oob_data_out(self, data): + """ + for Portal, this receives out-of-band data from Server across the AMP. + for Server, this sends out-of-band data to Portal. + + data is a dictionary + """ + pass + + def oob_data_in(self, data): + """ + for Portal, this sends out-of-band requests to Server over the AMP. + for Server, this receives data from Portal. + + data is a dictionary + """ + pass diff --git a/src/server/sessionhandler.py b/src/server/sessionhandler.py index 37937ffb7..9eb16bb01 100644 --- a/src/server/sessionhandler.py +++ b/src/server/sessionhandler.py @@ -295,6 +295,20 @@ class ServerSessionHandler(SessionHandler): # to put custom effects on the server due to data input, e.g. # from a custom client. + def oob_data_in(self, sessid, data): + """ + OOB (Out-of-band) Data Portal -> Server + """ + session = self.sessions.get(sessid, None) + if session: + session.oob_data_in(data) + + def oob_data_out(self, session, data): + """ + OOB (Out-of-band) Data Server -> Portal + """ + self.server.amp_protocol.call_remote_OOBServer2Portal(session.sessid, + data=data) #------------------------------------------------------------ # Portal-SessionHandler class @@ -392,5 +406,20 @@ class PortalSessionHandler(SessionHandler): if session: session.data_out(string, data=data) + def oob_data_in(self, session, data): + """ + OOB (Out-of-band) data Portal -> Server + """ + self.portal.amp_protocol.call_remote_OOBPortal2Server(session.sessid, + data=data) + + def oob_data_out(self, sessid, data): + """ + OOB (Out-of-band) data Server -> Portal + """ + session = self.sessions.get(sessid, None) + if session: + session.oob_data_out(data) + SESSIONS = ServerSessionHandler() PORTAL_SESSIONS = PortalSessionHandler() diff --git a/src/settings_default.py b/src/settings_default.py index 6fa5abb5f..89967ccc2 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -253,6 +253,8 @@ PERMISSION_PLAYER_DEFAULT = "Players" # Tuple of modules implementing lock functions. All callable functions # inside these modules will be available as lock functions. LOCK_FUNC_MODULES = ("src.locks.lockfuncs",) +# Module holding server-side functions for out-of-band protocols to call. +OOB_FUNC_MODULE = "" ################################################### diff --git a/src/utils/utils.py b/src/utils/utils.py index d294bf9ca..686963a96 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -542,7 +542,7 @@ def has_parent(basepath, obj): def mod_import(mod_path, propname=None): """ - Takes filename of a module, converts it to a python path + Takes filename of a module (a python path or a full pathname) and imports it. If property is given, return the named property from this module instead of the module itself. """