Changed the OOB message structure to include sending text data as well; still not working fully.
This commit is contained in:
parent
529f13c689
commit
4817ec90b3
8 changed files with 249 additions and 240 deletions
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue