mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 09:46:32 +01:00
OOB passing data client->server. A few more default commands are needed.
This commit is contained in:
parent
96c6ad4aff
commit
16bbe009c3
6 changed files with 103 additions and 48 deletions
|
|
@ -26,10 +26,10 @@ from django.conf import settings
|
|||
from src.server.models import ServerConfig
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.scripts.scripts import Script
|
||||
from src.create import create_script
|
||||
from src.utils.create import create_script
|
||||
from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj
|
||||
from src.utils import logger
|
||||
from src.utils.utils import variable_from_module, to_str
|
||||
from src.utils.utils import variable_from_module, to_str, is_iter, make_iter
|
||||
|
||||
_SA = object.__setattr__
|
||||
_GA = object.__getattribute__
|
||||
|
|
@ -307,7 +307,7 @@ class OOBHandler(object):
|
|||
oob_tracker_name = "_track_db_value_change"
|
||||
self.track(attrobj, tracker_key, attr_name, sessid, property_name=oob_tracker_name)
|
||||
|
||||
def run(self, func_key, *args, **kwargs):
|
||||
def execute_cmd(self, func_key, *args, **kwargs):
|
||||
"""
|
||||
Retrieve oobfunc from OOB_FUNCS and execute it immediately
|
||||
using *args and **kwargs
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class Msdp(object):
|
|||
"""
|
||||
self.protocol = protocol
|
||||
self.protocol.protocol_flags['MSDP'] = False
|
||||
self.protocol.negotiationMap[MSDP] = self.msdp_to_func
|
||||
self.protocol.negotiationMap[MSDP] = self.msdp_to_evennia
|
||||
self.protocol.will(MSDP).addCallbacks(self.do_msdp, self.no_msdp)
|
||||
self.msdp_reported = {}
|
||||
|
||||
|
|
@ -148,10 +148,7 @@ class Msdp(object):
|
|||
print "msdp supported"
|
||||
self.protocol.protocol_flags['MSDP'] = True
|
||||
|
||||
def parse_msdp(self, args):
|
||||
"Called with arguments to subnegotiation"
|
||||
|
||||
def func_to_msdp(self, cmdname, data):
|
||||
def evennia_to_msdp(self, cmdname, data):
|
||||
"""
|
||||
handle return data from cmdname by converting it to
|
||||
a proper msdp structure. data can either be a single value (will be
|
||||
|
|
@ -179,6 +176,7 @@ class Msdp(object):
|
|||
|
||||
def make_array(name, datalist, string):
|
||||
"build a simple array. Arrays may not nest tables by definition."
|
||||
print "make_array", datalist, string
|
||||
string += MSDP_VAR + name + MSDP_ARRAY_OPEN
|
||||
for val in datalist:
|
||||
string += MSDP_VAL + val
|
||||
|
|
@ -190,11 +188,11 @@ class Msdp(object):
|
|||
elif hasattr(data, '__iter__'):
|
||||
msdp_string = make_array(cmdname, data, "")
|
||||
else:
|
||||
msdp_string = MSDP_VAR + cmdname + MSDP_VAL + data
|
||||
msdp_string = MSDP_VAR + cmdname + MSDP_VAL + data if data!=None else ""
|
||||
return msdp_string
|
||||
|
||||
|
||||
def msdp_to_func(self, data):
|
||||
def msdp_to_evennia(self, data):
|
||||
"""
|
||||
Handle a client's requested negotiation, converting
|
||||
it into a function mapping - either one of the MSDP
|
||||
|
|
@ -229,57 +227,55 @@ class Msdp(object):
|
|||
|
||||
print "MSDP: table, array, variables:", tables, arrays, variables
|
||||
|
||||
# all variables sent through msdp to Evennia are considered commands with arguments.
|
||||
# there are three forms of commands possible through msdp:
|
||||
#
|
||||
# VARNAME VAR -> varname(var)
|
||||
# ARRAYNAME VAR VAL VAR VAL VAR VAL ENDARRAY -> arrayname(val,val,val)
|
||||
# TABLENAME TABLE VARNAME VAL VARNAME VAL ENDTABLE -> tablename(varname=val, varname=val)
|
||||
#
|
||||
|
||||
|
||||
ret = ""
|
||||
|
||||
# default MSDP functions
|
||||
if "LIST" in variables:
|
||||
ret += self.func_to_msdp("LIST", self.msdp_cmd_list(variables["LIST"]))
|
||||
del variables["LIST"]
|
||||
ret += self.evennia_to_msdp("LIST", self.msdp_cmd_list(*(variables.pop("LIST"),)))
|
||||
if "REPORT" in variables:
|
||||
ret += self.func_to_msdp("REPORT", self.msdp_cmd_report(*(variables["REPORT"],)))
|
||||
del variables["REPORT"]
|
||||
ret += self.evennia_to_msdp("REPORT", self.msdp_cmd_report(*(variables.pop("REPORT"),)))
|
||||
if "REPORT" in arrays:
|
||||
ret += self.func_to_msdp("REPORT", self.msdp_cmd_report(*arrays["REPORT"]))
|
||||
del arrays["REPORT"]
|
||||
ret += self.evennia_to_msdp("REPORT", self.msdp_cmd_report(*arrays.pop("REPORT")))
|
||||
if "RESET" in variables:
|
||||
ret += self.func_to_msdp("RESET", self.msdp_cmd_reset(*(variables["RESET"],)))
|
||||
del variables["RESET"]
|
||||
ret += self.evennia_to_msdp("RESET", self.msdp_cmd_reset(*(variables.pop("RESET"),)))
|
||||
if "RESET" in arrays:
|
||||
ret += self.func_to_msdp("RESET", self.msdp_cmd_reset(*arrays["RESET"]))
|
||||
del arrays["RESET"]
|
||||
ret += self.evennia_to_msdp("RESET", self.msdp_cmd_reset(*arrays.pop("RESET",)))
|
||||
if "SEND" in variables:
|
||||
ret += self.func_to_msdp("SEND", self.msdp_cmd_send(*(variables["SEND"],)))
|
||||
del variables["SEND"]
|
||||
ret += self.evennia_to_msdp("SEND", self.msdp_cmd_send(*(variables.pop("SEND",))))
|
||||
if "SEND" in arrays:
|
||||
ret += self.func_to_msdp("SEND",self.msdp_cmd_send(*arrays["SEND"]))
|
||||
del arrays["SEND"]
|
||||
ret += self.evennia_to_msdp("SEND",self.msdp_cmd_send(*arrays.pop("SEND")))
|
||||
|
||||
# if there are anything left we look for a custom function
|
||||
for varname, var in variables.items():
|
||||
# a simple function + argument
|
||||
ooc_func = MSDP_COMMANDS_CUSTOM.get(varname.upper())
|
||||
if ooc_func:
|
||||
ret += self.func_to_msdp(varname, ooc_func(var))
|
||||
ret += self.evennia_to_msdp(varname, ooc_func(var))
|
||||
for arrayname, array in arrays.items():
|
||||
# we assume the array are multiple arguments to the function
|
||||
ooc_func = MSDP_COMMANDS_CUSTOM.get(arrayname.upper())
|
||||
if ooc_func:
|
||||
ret += self.func_to_msdp(arrayname, ooc_func(*array))
|
||||
ret += self.evennia_to_msdp(arrayname, ooc_func(*array))
|
||||
for tablename, table in tables.items():
|
||||
# we assume tables are keyword arguments to the function
|
||||
ooc_func = MSDP_COMMANDS_CUSTOM.get(arrayname.upper())
|
||||
if ooc_func:
|
||||
ret += self.func_to_msdp(tablename, ooc_func(**table))
|
||||
ret += self.evennia_to_msdp(tablename, ooc_func(**table))
|
||||
|
||||
# return any result
|
||||
if ret:
|
||||
# send return value if it exists
|
||||
self.msdp_send(ret)
|
||||
ret = IAC + SB + MSDP + ret + IAC + SE
|
||||
#ret = IAC + SB + MSDP + MSDP_VAR + "SEND" + MSDP_VAL + "Testsend" + IAC + SE
|
||||
self.protocol._write(ret)
|
||||
logger.log_infomsg("MSDP_RESULT: %s" % ret)
|
||||
self.data_out(ret)
|
||||
|
||||
def msdp_send(self, msdp_string):
|
||||
def data_out(self, msdp_string):
|
||||
"""
|
||||
Return a msdp-valid subnegotiation across the protocol.
|
||||
"""
|
||||
|
|
@ -295,21 +291,21 @@ class Msdp(object):
|
|||
The List command allows for retrieving various info about the server/client
|
||||
"""
|
||||
if arg == 'COMMANDS':
|
||||
return self.func_to_msdp(arg, MSDP_COMMANDS)
|
||||
return self.evennia_to_msdp(arg, MSDP_COMMANDS)
|
||||
elif arg == 'LISTS':
|
||||
return self.func_to_msdp(arg, ("COMMANDS", "LISTS", "CONFIGURABLE_VARIABLES",
|
||||
return self.evennia_to_msdp(arg, ("COMMANDS", "LISTS", "CONFIGURABLE_VARIABLES",
|
||||
"REPORTED_VARIABLES", "SENDABLE_VARIABLES"))
|
||||
elif arg == 'CONFIGURABLE_VARIABLES':
|
||||
return self.func_to_msdp(arg, ("CLIENT_NAME", "CLIENT_VERSION", "PLUGIN_ID"))
|
||||
return self.evennia_to_msdp(arg, ("CLIENT_NAME", "CLIENT_VERSION", "PLUGIN_ID"))
|
||||
elif arg == 'REPORTABLE_VARIABLES':
|
||||
return self.func_to_msdp(arg, MSDP_REPORTABLE.keys())
|
||||
return self.evennia_to_msdp(arg, MSDP_REPORTABLE.keys())
|
||||
elif arg == 'REPORTED_VARIABLES':
|
||||
# the dynamically set items to report
|
||||
return self.func_to_msdp(arg, self.msdp_reported.keys())
|
||||
return self.evennia_to_msdp(arg, self.msdp_reported.keys())
|
||||
elif arg == 'SENDABLE_VARIABLES':
|
||||
return self.func_to_msdp(arg, MSDP_SENDABLE.keys())
|
||||
return self.evennia_to_msdp(arg, MSDP_SENDABLE.keys())
|
||||
else:
|
||||
return self.func_to_msdp("LIST", arg)
|
||||
return self.evennia_to_msdp("LIST", arg)
|
||||
|
||||
# default msdp commands
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
for session in self.sessions.values():
|
||||
session.data_out(message)
|
||||
|
||||
|
||||
def data_out(self, sessid, text=None, **kwargs):
|
||||
"""
|
||||
Called by server for having the portal relay messages and data
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from src.server.session import Session
|
|||
from src.server.portal import ttype, mssp, msdp
|
||||
from src.server.portal.mccp import Mccp, mccp_compress, MCCP
|
||||
from src.utils import utils, ansi, logger
|
||||
from src.utils.utils import make_iter, is_iter
|
||||
|
||||
_RE_N = re.compile(r"\{n$")
|
||||
|
||||
|
|
@ -36,14 +37,13 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
# negotiate ttype (client info)
|
||||
#self.ttype = ttype.Ttype(self)
|
||||
# negotiate mssp (crawler communication)
|
||||
self.mssp = mssp.Mssp(self)
|
||||
#self.mssp = mssp.Mssp(self)
|
||||
# msdp
|
||||
#self.msdp = msdp.Msdp(self)
|
||||
self.msdp = msdp.Msdp(self)
|
||||
# add this new connection to sessionhandler so
|
||||
# the Server becomes aware of it.
|
||||
self.sessionhandler.connect(self)
|
||||
|
||||
|
||||
def enableRemote(self, option):
|
||||
"""
|
||||
This sets up the remote-activated options we allow for this protocol.
|
||||
|
|
@ -69,7 +69,6 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
else:
|
||||
return super(TelnetProtocol, self).disableLocal(option)
|
||||
|
||||
|
||||
def connectionLost(self, reason):
|
||||
"""
|
||||
This is executed when the connection is lost for
|
||||
|
|
@ -163,6 +162,16 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
except Exception, e:
|
||||
self.sendLine(str(e))
|
||||
return
|
||||
if "oob" in kwargs:
|
||||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
|
||||
if "MSDP" in self.protocol_flags:
|
||||
print "oobstruct:", oobstruct
|
||||
for cmdname, args in oobstruct:
|
||||
print "cmdname, args:", cmdname, args
|
||||
msdp_string = self.msdp.func_to_msdp(cmdname, args)
|
||||
print "msdp_string:", msdp_string
|
||||
self.msdp.data_out(msdp_string)
|
||||
|
||||
ttype = self.protocol_flags.get('TTYPE', {})
|
||||
raw = kwargs.get("raw", False)
|
||||
nomarkup = not (ttype or ttype.get('256 COLORS') or ttype.get('ANSI') or not ttype.get("init_done"))
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from src.server.session import Session
|
|||
IDLE_COMMAND = settings.IDLE_COMMAND
|
||||
_GA = object.__getattribute__
|
||||
_ObjectDB = None
|
||||
_OOB_HANDLER = None
|
||||
|
||||
# load optional out-of-band function module
|
||||
OOB_PLUGIN_MODULE = settings.OOB_PLUGIN_MODULE
|
||||
|
|
@ -178,8 +179,13 @@ class ServerSession(Session):
|
|||
cmdhandler.cmdhandler(self, text, callertype="session", sessid=self.sessid)
|
||||
self.update_session_counters()
|
||||
if "oob" in kwargs:
|
||||
# relay to OOB handler
|
||||
pass
|
||||
# handle oob instructions
|
||||
global _OOB_HANDLER
|
||||
if not _OOB_HANDLER:
|
||||
from src.servever.oobhandler import OOB_HANDLER as _OOB_HANDLER
|
||||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob", None))
|
||||
for (funcname, args, kwargs) in oobstruct:
|
||||
_OOBHANDLER.execute_cmd(funcname, *args, **kwargs)
|
||||
|
||||
execute_cmd = data_in # alias
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ _ServerSession = None
|
|||
_ServerConfig = None
|
||||
_ScriptDB = None
|
||||
|
||||
|
||||
# AMP signals
|
||||
PCONN = chr(1) # portal session connect
|
||||
PDISCONN = chr(2) # portal session disconnect
|
||||
|
|
@ -357,6 +358,49 @@ class ServerSessionHandler(SessionHandler):
|
|||
return self.sessions.get(sessid)
|
||||
return None
|
||||
|
||||
def oobstruct_parser(self, oobstruct):
|
||||
"""
|
||||
Helper method for each session to use to parse oob structures
|
||||
(The 'oob' kwarg of the msg() method)
|
||||
allowed oob structures are
|
||||
cmdname
|
||||
(cmdname, cmdname)
|
||||
(cmdname,(arg, ))
|
||||
(cmdname,(arg1,arg2))
|
||||
(cmdname,{key:val,key2:val2})
|
||||
(cmdname, (args,), {kwargs})
|
||||
((cmdname, (arg1,arg2)), cmdname, (cmdname, (arg1,)))
|
||||
outputs an ordered structure on the form
|
||||
((cmdname, (args,), {kwargs}), ...), where the two last parts of each tuple may be empty
|
||||
"""
|
||||
slen = len(oobstruct)
|
||||
if not oobstruct:
|
||||
return tuple(None, (), {})
|
||||
elif not hasattr(oobstruct, "__iter__"):
|
||||
# a singular command name, without arguments or kwargs
|
||||
return (oobstruct.lower(), (), {})
|
||||
# regardless of number of args/kwargs, the first element must be the function name.
|
||||
# we will not catch this error if not, but allow it to propagate.
|
||||
if slen == 1:
|
||||
return (oobstruct[0].lower(), (), {})
|
||||
elif slen == 2:
|
||||
if isinstance(oobstruct[1], dict):
|
||||
# cmdname, {kwargs}
|
||||
return (oobstruct[0].lower(), (), dict((key.lower(), val) for key,val in oobstruct[1].items()))
|
||||
elif isinstance(oobstruct[1], (tuple, list)):
|
||||
# cmdname, (args,)
|
||||
return (oobstruct[0].lower(), tuple(arg.lower() for arg in oobstruct[1]), {})
|
||||
else:
|
||||
# cmdname, (args,), {kwargs}
|
||||
return (oobstruct[0].lower(), tuple(arg.lower for arg in oobstruct[1]),
|
||||
dict((key.lower(), val) for key, val in oobstruct[2].items()))
|
||||
|
||||
# either multiple funcnames or multiple func tuples; descend recursively
|
||||
out = []
|
||||
for oobpart in oobstruct:
|
||||
out.append(self.oobstruct_parser(oobpart)[0])
|
||||
return tuple(out)
|
||||
|
||||
def announce_all(self, message):
|
||||
"""
|
||||
Send message to all connected sessions
|
||||
|
|
@ -379,5 +423,4 @@ class ServerSessionHandler(SessionHandler):
|
|||
if session:
|
||||
session.data_in(text=text, **kwargs)
|
||||
|
||||
|
||||
SESSIONS = ServerSessionHandler()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue