Changed the OOB message structure to include sending text data as well; still not working fully.

This commit is contained in:
Griatch 2016-01-28 22:19:23 +01:00
parent 529f13c689
commit 4817ec90b3
8 changed files with 249 additions and 240 deletions

View file

@ -461,25 +461,34 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
return cmdhandler.cmdhandler(self, raw_string, callertype="object", session=session, **kwargs)
def msg(self, text=None, from_obj=None, session=None, **kwargs):
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
"""
Emits something to a session attached to the object.
Args:
text (str, optional): The message to send
text (str or tuple, optional): The message to send. This
is treated internally like any send-command, so its
value can be a tuple if sending multiple arguments to
the `text` oob command.
from_obj (obj, optional): object that is sending. If
given, at_msg_send will be called
given, at_msg_send will be called. This value will be
passed on to the protocol.
session (Session or list, optional): Session or list of
Sessions to relay data to, if any. If set, will
force send to these sessions. If unset, who receives the
message depends on the MULTISESSION_MODE.
Sessions to relay data to, if any. If set, will force send
to these sessions. If unset, who receives the message
depends on the MULTISESSION_MODE.
options (dict, optional): Message-specific option-value
pairs. These will be applied at the protocol level.
Kwargs:
any (string or tuples): All kwarg keys not listed above
will be treated as send-command names and their arguments
(which can be a string or a tuple).
Notes:
`at_msg_receive` will be called on this Object.
All extra kwargs will be passed on to the protocol.
"""
text = to_str(text, force_string=True) if text != None else ""
# try send hooks
if from_obj:
try:
@ -493,10 +502,12 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
except Exception:
logger.log_trace()
kwargs["options"] = options
# relay to session(s)
sessions = make_iter(session) if session else self.sessions.all()
for session in sessions:
session.msg(text=text, **kwargs)
session.data_out(text=text, **kwargs)
def for_contents(self, func, exclude=None, **kwargs):
"""

View file

@ -137,7 +137,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
* Helper methods
- msg(outgoing_string, from_obj=None, **kwargs)
- msg(text=None, from_obj=None, session=None, options=None, **kwargs)
- execute_cmd(raw_string)
- search(ostring, global_search=False, attribute_name=None,
use_nicks=False, location=None,
@ -384,7 +384,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
super(PlayerDB, self).delete(*args, **kwargs)
## methods inherited from database model
def msg(self, text=None, from_obj=None, session=None, **kwargs):
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
"""
Evennia -> User
This is the main route for sending data back to the user from the
@ -398,12 +398,11 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
Sessions to receive this send. If given, overrules the
default send behavior for the current
MULTISESSION_MODE.
Notes:
All other keywords are passed on to the protocol.
options (list): Protocol-specific options. Passed on to the protocol.
Kwargs:
any (dict): All other keywords are passed on to the protocol.
"""
text = to_str(text, force_string=True) if text else ""
if from_obj:
# call hook
try:
@ -414,7 +413,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)):
# session relay
sessions = make_iter(session) if session else self.sessions.all()
for session in sessions:
session.msg(text=text, **kwargs)
session.data_out(text=text, **kwargs)
def execute_cmd(self, raw_string, session=None, **kwargs):
"""

View file

@ -424,20 +424,19 @@ class AMPProtocol(amp.AMP):
self.factory.server.sessions.data_in(self.factory.server.sessions[sessid], **kwargs)
return {}
def send_MsgPortal2Server(self, session, text="", **kwargs):
def send_MsgPortal2Server(self, session, **kwargs):
"""
Access method called by the Portal and executed on the Portal.
Args:
sessid (int): Unique Session id.
text (str): Message to send over the wire.
kwargs (any, optional): Optional data.
Returns:
deferred (Deferred): Asynchronous return.
"""
return self.send_data(MsgPortal2Server, session.sessid, text=text, **kwargs)
return self.send_data(MsgPortal2Server, session.sessid, **kwargs)
# Server -> Portal message
@ -455,18 +454,17 @@ class AMPProtocol(amp.AMP):
return {}
def send_MsgServer2Portal(self, session, text="", **kwargs):
def send_MsgServer2Portal(self, session, **kwargs):
"""
Access method - executed on the Server for sending data
to Portal.
Args:
session (Session): Unique Session.
msg (str, optional): Message to send over the wire.
kwargs (any, optiona): Extra data.
"""
return self.send_data(MsgServer2Portal, session.sessid, text=text, **kwargs)
return self.send_data(MsgServer2Portal, session.sessid, **kwargs)
# Server administration from the Portal side
@AdminPortal2Server.responder

View file

@ -9,6 +9,7 @@ from collections import deque
from twisted.internet import reactor
from django.conf import settings
from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC
from evennia.utils.logger import log_trace
# module import
_MOD_IMPORT = None
@ -295,74 +296,9 @@ class PortalSessionHandler(SessionHandler):
"""
for session in self.values():
session.data_out(message)
session.data_out(text=message)
def oobstruct_parser(self, oobstruct):
"""
Helper method for each session to use to parse oob structures
(The 'oob' kwarg of the msg() method).
Args:
oobstruct (str or iterable): A structure representing
an oob command on one of the following forms:
- "cmdname"
- "cmdname", "cmdname"
- ("cmdname", arg)
- ("cmdname",(args))
- ("cmdname",{kwargs}
- ("cmdname", (args), {kwargs})
- (("cmdname", (args,), {kwargs}), ("cmdname", (args,), {kwargs}))
and any combination of argument-less commands or commands with only
args, only kwargs or both.
Returns:
structure (tuple): A generic OOB structure on the form
`((cmdname, (args,), {kwargs}), ...)`, where the two last
args and kwargs may be empty
"""
def _parse(oobstruct):
slen = len(oobstruct)
if not oobstruct:
return tuple(None, (), {})
elif not hasattr(oobstruct, "__iter__"):
# a singular command name, without arguments or kwargs
return (oobstruct, (), {})
# 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], (), {})
elif slen == 2:
if isinstance(oobstruct[1], dict):
# (cmdname, {kwargs})
return (oobstruct[0], (), dict(oobstruct[1]))
elif isinstance(oobstruct[1], (tuple, list)):
# (cmdname, (args,))
return (oobstruct[0], tuple(oobstruct[1]), {})
else:
# (cmdname, arg)
return (oobstruct[0], (oobstruct[1],), {})
else:
# (cmdname, (args,), {kwargs})
return (oobstruct[0], tuple(oobstruct[1]), dict(oobstruct[2]))
if hasattr(oobstruct, "__iter__"):
# differentiate between (cmdname, cmdname),
# (cmdname, (args), {kwargs}) and ((cmdname,(args),{kwargs}),
# (cmdname,(args),{kwargs}), ...)
if oobstruct and isinstance(oobstruct[0], basestring):
return (list(_parse(oobstruct)),)
else:
out = []
for oobpart in oobstruct:
out.append(_parse(oobpart))
return (list(out),)
return (_parse(oobstruct),)
def data_in(self, session, text="", **kwargs):
def data_in(self, session, **kwargs):
"""
Called by portal sessions for relaying data coming
in from the protocol to the server.
@ -371,7 +307,6 @@ class PortalSessionHandler(SessionHandler):
session (PortalSession): Session receiving data.
Kwargs:
text (str): Text from protocol.
kwargs (any): Other data from protocol.
Notes:
@ -394,24 +329,24 @@ class PortalSessionHandler(SessionHandler):
if self.command_overflow:
self.data_out(session, text=_ERROR_COMMAND_OVERFLOW)
return
# scrub data
kwargs = self.clean_senddata(session, kwargs)
# relay data to Server
self.command_counter += 1
session.cmd_last = now
self.portal.amp_protocol.send_MsgPortal2Server(session,
text=text,
**kwargs)
**kwargs)
else:
# called by the callLater callback
if self.command_overflow:
self.command_overflow = False
reactor.callLater(1.0, self.data_in, None)
def data_out(self, session, text=None, **kwargs):
def data_out(self, session, **kwargs):
"""
Called by server for having the portal relay messages and data
to the correct session protocol. We also convert oob input to
a generic form here.
to the correct session protocol.
Args:
session (Session): Session sending data.
@ -424,10 +359,16 @@ class PortalSessionHandler(SessionHandler):
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "portalsessionhandler.data_out")
# distribute outgoing data to the correct session methods.
if session:
# convert oob to the generic format
if "oob" in kwargs:
kwargs["oob"] = self.oobstruct_parser(kwargs["oob"])
session.data_out(text=text, **kwargs)
print ("portalsessionhandler.data_out:", session, kwargs, session.datamap)
for cmdname, args in kwargs.items():
try:
if cmdname in session.datamap:
session.datamap[cmdname](session, *args)
else:
session.datamap["_default"](session, *args)
except Exception:
log_trace()
PORTAL_SESSIONS = PortalSessionHandler()

View file

@ -10,6 +10,7 @@ sessions etc.
import re
from twisted.internet.task import LoopingCall
from twisted.conch.telnet import Telnet, StatefulTelnetProtocol, IAC, LINEMODE, GA, WILL, WONT, ECHO
from django.conf import settings
from evennia.server.session import Session
from evennia.server.portal import ttype, mssp, telnet_oob, naws
from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
@ -21,6 +22,7 @@ NOP = chr(241)
_RE_N = re.compile(r"\{n$")
_RE_LEND = re.compile(r"\n$|\r$", re.MULTILINE)
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
"""
@ -69,6 +71,10 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
self.keep_alive = LoopingCall(self._write, IAC + NOP)
self.keep_alive.start(30, now=False)
self.datamap = {"text": self.send_text,
"prompt": self.send_prompt,
"_default": self.send_oob}
def handshake_done(self, force=False):
"""
@ -242,98 +248,117 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
self.data_out(reason)
self.connectionLost(reason)
def data_in(self, text=None, **kwargs):
def data_in(self, **kwargs):
"""
Data User -> Evennia
Kwargs:
text (str): Incoming text.
kwargs (any): Options from the protocol.
"""
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "telnet.data_in")
self.sessionhandler.data_in(self, text=text, **kwargs)
self.sessionhandler.data_in(self, **kwargs)
def data_out(self, text=None, **kwargs):
def data_out(self, **kwargs):
"""
Data Evennia -> User. A generic hook method for engine to call
in order to send data through the telnet connection.
Data Evennia -> User
Kwargs:
text (str): Text to send.
oob (list): `[(cmdname,args,kwargs), ...]`, supply an
Out-of-Band instruction.
xterm256 (bool): Enforce xterm256 setting. If not given,
ttype result is used. If client does not suport xterm256,
the ansi fallback will be used
mxp (bool): Enforce mxp setting. If not given, enables if
we detected client support for it
ansi (bool): Enforce ansi setting. If not given, ttype
result is used.
nomarkup (bool): If True, strip all ansi markup (this is
the same as `xterm256=False, ansi=False`)
raw (bool):Pass string through without any ansi processing
(i.e. include Evennia ansi markers but do not convert them
into ansi tokens)
prompt (str): Supply a prompt text which gets sent without
a newline added to the end.
echo (str): Turn on/off line echo on the client, if the
client supports it (e.g. for password input). Remember
that you must manually activate it again later.
kwargs (any): Options to the protocol
"""
self.sessionhandler.data_out(self, **kwargs)
Notes:
The telnet TTYPE negotiation flags, if any, are used if no kwargs
are given.
@staticmethod
def send_text(session, *args, **kwargs):
"""
Send text data. This is an in-band telnet operation.
Args:
text (str): The first argument is always the text string to send. No other arguments
are considered.
*options (str): All other arguments are considered option flags.
Available flags are (if not set, TTYPE will be used, turning on if available):
mxp: Enforce MXP link support.
ansi: Enforce no ANSI colors.
xterm256: Enforce xterm256 colors, regardless of TTYPE.
noxterm256: Enforce no xterm256 color support, regardless of TTYPE.
nomarkup: Strip all ANSI markup. This is the same as noxterm256,noansi
raw: Pass string through without any ansi processing
(i.e. include Evennia ansi markers but do not
convert them into ansi tokens)
echo: Turn on/off line echo on the client. Turn
off line echo for client, for example for password.
Note that it must be actively turned back on again!
"""
## profiling, debugging
#if text.startswith("TEST_MESSAGE"): 1/0
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "telnet.data_out", final=True)
if args:
text = args[0]
if text is None:
return
try:
text = utils.to_str(text if text else "", encoding=self.encoding)
except Exception as e:
self.sendLine(str(e))
return
if "oob" in kwargs and "OOB" in self.protocol_flags:
# oob is a list of [(cmdname, arg, kwarg), ...]
for cmdname, args, okwargs in kwargs["oob"]:
self.oob.data_out(cmdname, *args, **okwargs)
# handle arguments
options = kwargs.get("options", {})
ttype = session.protocol_flags.get('TTYPE', {})
xterm256 = options.get("xterm256", ttype.get('256 COLORS', False) if ttype.get("init_done") else True)
useansi = options.get("ansi", ttype and ttype.get('ANSI', False) if ttype.get("init_done") else True)
raw = options.get("raw", False)
nomarkup = options.get("nomarkup", not (xterm256 or useansi))
echo = options.get("echo", None)
mxp = options.get("mxp", session.protocol_flags.get("MXP", False))
screenreader = options.get("screenreader", session.screenreader)
# parse **kwargs, falling back to ttype if nothing is given explicitly
ttype = self.protocol_flags.get('TTYPE', {})
xterm256 = kwargs.get("xterm256", ttype.get('256 COLORS', False) if ttype.get("init_done") else True)
useansi = kwargs.get("ansi", ttype and ttype.get('ANSI', False) if ttype.get("init_done") else True)
raw = kwargs.get("raw", False)
nomarkup = kwargs.get("nomarkup", not (xterm256 or useansi))
prompt = kwargs.get("prompt")
echo = kwargs.get("echo", None)
mxp = kwargs.get("mxp", self.protocol_flags.get("MXP", False))
if screenreader:
# screenreader mode cleans up output
text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False)
text = _RE_SCREENREADER_REGEX.sub("", text)
if raw:
# no processing whatsoever
self.sendLine(text)
elif text:
# we need to make sure to kill the color at the end in order
# to match the webclient output.
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp)
if mxp:
linetosend = mxp_parse(linetosend)
self.sendLine(linetosend)
if prompt:
# Send prompt separately
prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256)
if mxp:
prompt = mxp_parse(prompt)
if options.get("send_prompt"):
# send a prompt instead.
if not raw:
# processing
prompt = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256)
if mxp:
prompt = mxp_parse(prompt)
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
prompt += IAC + GA
self.transport.write(mccp_compress(self, prompt))
if echo:
self.transport.write(mccp_compress(self, IAC+WONT+ECHO))
elif echo == False:
self.transport.write(mccp_compress(self, IAC+WILL+ECHO))
session.transport.write(mccp_compress(session, prompt))
else:
if raw:
# no processing
session.sendLine(text)
return
else:
# we need to make sure to kill the color at the end in order
# to match the webclient output.
linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp)
if mxp:
linetosend = mxp_parse(linetosend)
session.sendLine(linetosend)
if echo is not None:
# turn on/off echo
if echo:
session.transport.write(mccp_compress(session, IAC+WILL+ECHO))
else:
session.transport.write(mccp_compress(session, IAC+WONT+ECHO))
@staticmethod
def send_prompt(session, *args, **kwargs):
"""
Send a prompt - a text without a line end. See send_text for argument options.
"""
kwargs["options"].update({"send_prompt": True})
session.send_text(*args, **kwargs)
@staticmethod
def send_oob(session, *args, **kwargs):
"""
Send oob data
"""
print "telnet.send_oob not implemented yet! ", args

View file

@ -28,7 +28,6 @@ _SA = object.__setattr__
_ObjectDB = None
_ANSI = None
_INLINEFUNC_ENABLED = settings.INLINEFUNC_ENABLED
_RE_SCREENREADER_REGEX = re.compile(r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE)
# i18n
from django.utils.translation import ugettext as _
@ -169,6 +168,8 @@ class ServerSession(Session):
self.player = None
self.cmdset_storage_string = ""
self.cmdset = CmdSetHandler(self, True)
self.datamap = {"text": self.recv_text,
"_default": self.recv_text}
def __cmdset_storage_get(self):
return [path.strip() for path in self.cmdset_storage_string.split(',')]
@ -336,22 +337,22 @@ class ServerSession(Session):
# Player-visible idle time, not used in idle timeout calcs.
self.cmd_last_visible = self.cmd_last
def data_in(self, text=None, **kwargs):
@staticmethod
def recv_text(session, *args, **kwargs):
"""
Send data User->Evennia. This will in effect execute a command
Recv command data User->Evennia. This will in effect execute a command
string on the server.
Note that oob data is already sent separately to the
oobhandler at this point.
Kwargs:
text (str): A text to relay
kwargs (any): Other parameters from the protocol.
Args:
text (str): First arg is used as text-command input. Other
arguments are ignored.
"""
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "ServerSession.data_in")
text = args[0] if args else None
#explicitly check for None since text can be an empty string, which is
#also valid
if text is not None:
@ -359,47 +360,47 @@ class ServerSession(Session):
#text = to_unicode(escape_control_sequences(text), encoding=self.encoding)
# handle the 'idle' command
if text.strip() == _IDLE_COMMAND:
self.update_session_counters(idle=True)
session.update_session_counters(idle=True)
return
if self.player:
if session.player:
# nick replacement
puppet = self.puppet
puppet = session.puppet
if puppet:
text = puppet.nicks.nickreplace(text,
categories=("inputline", "channel"), include_player=True)
else:
text = self.player.nicks.nickreplace(text,
text = session.player.nicks.nickreplace(text,
categories=("inputline", "channels"), include_player=False)
cmdhandler(self, text, callertype="session", session=self)
self.update_session_counters()
execute_cmd = data_in # alias
cmdhandler(session, text, callertype="session", session=session)
session.update_session_counters()
def data_out(self, text=None, **kwargs):
"""
Send Evennia -> User
Sending data from Evennia->Player
Kwargs:
text (str): A text to relay
kwargs (any): Other parameters to the protocol.
text (str or tuple)
any (str or tuple): Send-commands identified
by their keys. Or "options", carrying options
for the protocol(s).
"""
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "ServerSession.data_out")
print "serversession.data_out:", text, kwargs
if text:
if hasattr(text, "__iter__"):
text, args = text[0], list(text[1:])
else:
text, args = text, []
options = kwargs.get("options", {})
raw = options.get("raw", False)
strip_inlinefunc = options.get("strip_inlinefunc", False)
if _INLINEFUNC_ENABLED and not raw:
text = parse_inlinefunc(text, strip=strip_inlinefunc, session=self)
text = parse_nested_inlinefunc(text, strip=strip_inlinefunc, session=self)
text = [text] + args
text = text if text else ""
if _INLINEFUNC_ENABLED and not "raw" in kwargs:
text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self)
text = parse_nested_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self)
if self.screenreader:
global _ANSI
if not _ANSI:
from evennia.utils import ansi as _ANSI
text = _ANSI.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False)
text = _RE_SCREENREADER_REGEX.sub("", text)
self.sessionhandler.data_out(self, text=text, **kwargs)
# alias
msg = data_out
msg = data_out # alias
def __eq__(self, other):
"Handle session comparisons"
@ -427,6 +428,7 @@ class ServerSession(Session):
"Unicode representation"
return u"%s" % str(self)
# Dummy API hooks for use during non-loggedin operation
def at_cmdset_get(self, **kwargs):

View file

@ -85,6 +85,9 @@ class Session(object):
self.protocol_flags = {}
self.server_data = {}
# map of input data to session methods
self.datamap = {}
# a back-reference to the relevant sessionhandler this
# session is stored in.
self.sessionhandler = sessionhandler
@ -135,25 +138,23 @@ class Session(object):
"""
pass
def data_out(self, text=None, **kwargs):
def data_out(self, **kwargs):
"""
Generic hook for sending data out through the protocol. Server
protocols can use this right away. Portal sessions
should overload this to format/handle the outgoing data as needed.
Kwargs:
text (str): Text data
kwargs (any): Other data to the protocol.
"""
pass
def data_in(self, text=None, **kwargs):
def data_in(self, **kwargs):
"""
Hook for protocols to send incoming data to the engine.
Kwargs:
text (str): Text data
kwargs (any): Other data from the protocol.
"""

View file

@ -18,6 +18,7 @@ from future.utils import listvalues
from time import time
from django.conf import settings
from evennia.commands.cmdhandler import CMD_LOGINSTART
from evennia.utils.logger import log_trace
from evennia.utils.utils import variable_from_module, is_iter, \
to_str, to_unicode, strip_control_sequences, make_iter
@ -57,7 +58,7 @@ _MULTISESSION_MODE = settings.MULTISESSION_MODE
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
_MAX_SERVER_COMMANDS_PER_SECOND = 100.0
_MAX_SESSION_COMMANDS_PER_SECOND = 5.0
_MODEL_MAP = None
def delayed_import():
"""
@ -116,6 +117,47 @@ class SessionHandler(dict):
"""
return dict((sessid, sess.get_sync_data()) for sessid, sess in self.items())
def clean_senddata(self, session, kwargs):
"""
Clean up data for sending across the AMP wire.
Args:
session (Session): The relevant session instance.
kwargs (dict): Every keyword represents a send-instruction.
Returns:
kwargs (dict): A cleaned dictionary of cmdname:args pairs,
where the keys and args have all been converted to
send-safe entities (strings or numbers).
"""
def _validate(data):
if isinstance(data, dict):
newdict = {}
for key, part in data.items():
newdict[key] = _validate(part)
return newdict
elif hasattr(data, "__iter__"):
return [_validate(part) for part in data]
elif isinstance(data, basestring):
try:
return data and to_str(to_unicode(data), encoding=session.encoding)
except LookupError:
# wrong encoding set on the session. Set it to a safe one
session.encoding = "utf-8"
return to_str(to_unicode(data), encoding=session.encoding)
elif hasattr(data, "id") and hasattr(data, "db_date_created") and hasattr(data, '__dbclass__'):
# convert database-object to their string representation.
return _validate(unicode(data))
else:
return data
clean_kwargs = {"options":kwargs.pop("options", {})}
for key in kwargs:
args = _validate(kwargs[key])
clean_kwargs[_validate(key)] = (args,) if args is not None and \
not hasattr(args, "__iter__") else args
return clean_kwargs
#------------------------------------------------------------
# Server-SessionHandler class
@ -170,7 +212,7 @@ class ServerSessionHandler(SessionHandler):
# validate all scripts
_ScriptDB.objects.validate()
self[sess.sessid] = sess
sess.data_in(CMD_LOGINSTART)
sess.data_in(text=CMD_LOGINSTART)
def portal_session_sync(self, portalsessiondata):
"""
@ -498,7 +540,7 @@ class ServerSessionHandler(SessionHandler):
for sess in self.values():
self.data_out(sess, message)
def data_out(self, session, text="", **kwargs):
def data_out(self, session, **kwargs):
"""
Sending data Server -> Portal
@ -506,24 +548,18 @@ class ServerSessionHandler(SessionHandler):
session (Session): Session to relay to.
text (str, optional): text data to return
Notes:
The outdata will be scrubbed for sending across
the wire here.
"""
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "ServerSessionHandler.data_out")
try:
text = text and to_str(to_unicode(text), encoding=session.encoding)
except LookupError:
# wrong encoding set on the session. Set it to a safe one
session.encoding = "utf-8"
text = to_str(to_unicode(text), encoding=session.encoding)
# clean output for sending
kwargs = self.clean_senddata(session, kwargs)
# send across AMP
print "sessionhandler.data_out:", kwargs
self.server.amp_protocol.send_MsgServer2Portal(session,
text=text,
**kwargs)
def data_in(self, session, text="", **kwargs):
def data_in(self, session, **kwargs):
"""
Data Portal -> Server.
We also intercept OOB communication here.
@ -532,25 +568,21 @@ class ServerSessionHandler(SessionHandler):
sessions (Session): Session.
Kwargs:
text (str): Text from protocol.
kwargs (any): Other data from protocol.
"""
#from evennia.server.profiling.timetrace import timetrace
#text = timetrace(text, "ServerSessionHandler.data_in")
if session:
text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding)
if "oob" in kwargs:
# incoming data is always on the form (cmdname, args, kwargs)
global _OOB_HANDLER
if not _OOB_HANDLER:
from evennia.server.oobhandler import OOB_HANDLER as _OOB_HANDLER
funcname, args, kwargs = kwargs.pop("oob")
if funcname:
_OOB_HANDLER.execute_cmd(session, funcname, *args, **kwargs)
# pass the rest off to the session
session.data_in(text=text, **kwargs)
# distribute incoming data to the correct receiving methods.
if session:
for cmdname, args in kwargs.items():
try:
if cmdname in session.datamap:
print "sessionhandler: data_in", cmdname, args
session.datamap[cmdname](session, *args)
else:
session.datamap["_default"](session, *args)
except Exception:
log_trace()
SESSION_HANDLER = ServerSessionHandler()
SESSIONS = SESSION_HANDLER # legacy