Starting to clean up and debug the server-side infrastructure

This commit is contained in:
Griatch 2016-02-10 18:41:36 +01:00
parent e4d50ff74e
commit 96ace8c75f
9 changed files with 135 additions and 131 deletions

View file

@ -60,7 +60,7 @@ create_help_entry = None
# utilities
settings = None
lockfuncs = None
oobhandler = None
inputhandler = None
logger = None
gametime = None
ansi = None
@ -167,7 +167,7 @@ def _init():
# handlers
from .scripts.tickerhandler import TICKER_HANDLER
from .server.oobhandler import OOB_HANDLER
from .server.inputhandler import INPUT_HANDLER
from .server.sessionhandler import SESSION_HANDLER
from .comms.channelhandler import CHANNEL_HANDLER

View file

@ -0,0 +1,55 @@
"""
Inputhandler functions
Inputcommands are always called from the client (they handle server
input, hence the name).
This module is loaded by being included in
`settings.INPUT_HANDLER_MODULES`.
All *global functions* included in this module are
considered input-handler functions and can be called
by the client to handle input.
An inputhandler function must have the following call signature:
cmdname(session, *args, **kwargs)
Where session will be the active session and *args, **kwargs are extra
incoming arguments and keyword properties.
A special command is the "default" command, which is called when
no other cmdname matches:
default(session, cmdname, *args, **kwargs)
"""
# import the contents of the default inputhandler_func module
#from evennia.server.inputhandler_funcs import *
# def oob_echo(session, *args, **kwargs):
# """
# Example echo function. Echoes args, kwargs sent to it.
#
# Args:
# session (Session): The Session to receive the echo.
# args (list of str): Echo text.
# kwargs (dict of str, optional): Keyed echo text
#
# """
# session.msg(oob=("echo", args, kwargs))
#
#
# def default(session, cmdname, *args, **kwargs):
# """
# Handles commands without a matching inputhandler func.
#
# Args:
# session (Session): The active Session.
# cmdname (str): The (unmatched) command name
# args, kwargs (any): Arguments to function.
#
# """
# pass

View file

@ -1,58 +0,0 @@
"""
OOB configuration.
This module should be included in (or replace) the
default module set in settings.OOB_PLUGIN_MODULES
A function oob_error will be used as optional error management.
The available OOB commands can be extended by changing
`settings.OOB_PLUGIN_MODULES`
CMD_MAP: This module must contain a global dictionary CMD_MAP. This is
a dictionary that maps the call-name available to a function in this
module (this allows you to map multiple oob cmdnames to a single
actual Python function, for example).
oob functions have the following call signature:
function(session, *args, **kwargs)
where session is the active session and *args, **kwargs are extra
arguments sent with the oob command.
A function mapped to the key "oob_error" will retrieve error strings
if it is defined. It will get the error message as its 1st argument.
oob_error(session, error, *args, **kwargs)
This allows for customizing error handling.
Data is usually returned to the user via a return OOB call:
session.msg(oob=(oobcmdname, (args,), {kwargs}))
Oobcmdnames are case-sensitive. Note that args, kwargs must be
iterable. Non-iterables will be interpreted as a new command name (you
can send multiple oob commands with one msg() call))
"""
# import the contents of the default msdp module
from evennia.server.oob_cmds import *
# def oob_echo(session, *args, **kwargs):
# """
# Example echo function. Echoes args, kwargs sent to it.
#
# Args:
# session (Session): The Session to receive the echo.
# args (list of str): Echo text.
# kwargs (dict of str, optional): Keyed echo text
#
# """
# session.msg(oob=("echo", args, kwargs))
#
## oob command map
# CMD_MAP = {"ECHO": oob_echo}

View file

@ -14,17 +14,16 @@ an object's properties or start a repeating action.
from builtins import object
from collections import defaultdict
from django.conf import settings
from evennia.server.models import ServerConfig
from evennia.server.sessionhandler import SESSIONS
from evennia.scripts.tickerhandler import TickerHandler
from evennia.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj
from evennia.utils import logger
from evennia.utils.utils import make_iter, mod_import
_SA = object.__setattr__
_GA = object.__getattribute__
_DA = object.__delattr__
_SESSIONS = None
# set at the bottom of this module
_OOB_FUNCS = None
@ -66,14 +65,18 @@ class OOBFieldMonitor(object):
fieldname (str): The field to monitor
"""
global _SESSIONS
if not _SESSIONS:
from evennia.server.sessionhandler import SESSIONS as _SESSIONS
for sessid, oobtuples in self.subscribers.items():
# oobtuples is a list [(oobfuncname, args, kwargs), ...],
# a potential list of oob commands to call when this
# field changes.
sessid = SESSIONS.get(sessid)
sessid = _SESSIONS.get(sessid)
if sessid:
for (oobfuncname, args, kwargs) in oobtuples:
OOB_HANDLER.execute_cmd(sessid, oobfuncname, fieldname, self.obj, *args, **kwargs)
INPUT_HANDLER.execute_cmd(sessid, oobfuncname, fieldname, self.obj, *args, **kwargs)
def add(self, session, oobfuncname, *args, **kwargs):
"""
@ -123,7 +126,7 @@ class OOBAtRepeater(object):
def __call__(self, *args, **kwargs):
"Called at regular intervals. Calls the oob function"
OOB_HANDLER.execute_cmd(kwargs["_sessid"], kwargs["_oobfuncname"], *args, **kwargs)
INPUT_HANDLER.execute_cmd(kwargs["_sessid"], kwargs["_oobfuncname"], *args, **kwargs)
# Main OOB Handler
@ -456,30 +459,30 @@ class OOBHandler(TickerHandler):
# access object
OOB_HANDLER = OOBHandler()
# load resources from plugin module. This must happen
# AFTER the OOB_HANDLER has been initialized since the
# commands will want to import it.
_OOB_FUNCS = {}
for modname in make_iter(settings.OOB_PLUGIN_MODULES):
_OOB_FUNCS.update(mod_import(modname).CMD_MAP)
# get the command to receive eventual error strings
_OOB_ERROR = _OOB_FUNCS.get("oob_error", None)
if not _OOB_ERROR:
# no custom error set; create default oob error message function
def oob_error(session, errmsg, *args, **kwargs):
"""
Fallback error handler. This will be used if no custom
oob_error is defined and just echoes the error back to the
session.
Args:
errmsg (str): Error message to echo.
args, kwargs (any): Not used.
"""
session.msg(oob=("err", ("ERROR ", errmsg)))
_OOB_ERROR = oob_error
INPUT_HANDLER = OOBHandler()
## load resources from plugin module. This must happen
## AFTER the OOB_HANDLER has been initialized since the
## commands will want to import it.
#_OOB_FUNCS = {}
#for modname in make_iter(settings.OOB_PLUGIN_MODULES):
# _OOB_FUNCS.update(mod_import(modname).CMD_MAP)
#
## get the command to receive eventual error strings
#_OOB_ERROR = _OOB_FUNCS.get("oob_error", None)
#if not _OOB_ERROR:
# # no custom error set; create default oob error message function
# def oob_error(session, errmsg, *args, **kwargs):
# """
# Fallback error handler. This will be used if no custom
# oob_error is defined and just echoes the error back to the
# session.
#
# Args:
# errmsg (str): Error message to echo.
# args, kwargs (any): Not used.
#
# """
# session.msg(oob=("err", ("ERROR ", errmsg)))
# _OOB_ERROR = oob_error
#

View file

@ -58,9 +58,10 @@ name.
from future.utils import viewkeys
from django.conf import settings
from evennia.utils.utils import to_str
from evennia.server.inputhandler import INPUT_HANDLER
from evennia.commands.cmdhandler import cmdhandler
#from evennia.server.inputhandler import INPUT_HANDLER
from evennia.utils.logger import log_err
from evennia.utils.utils import to_str
_IDLE_COMMAND = settings.IDLE_COMMAND
_GA = object.__getattribute__
@ -104,6 +105,16 @@ def text(session, *args, **kwargs):
cmdhandler(session, text, callertype="session", session=session)
session.update_session_counters()
def default(session, cmdname, *args, **kwargs):
"""
Default catch-function. This is like all other input functions except
it will get `cmdname` as the first argument.
"""
err = "Input command not recognized:\n" \
" name: {cmdname}\n" \
" args, kwargs: {args}, {kwargs}"
log_err(err.format(cmdname=cmdname, args=args, kwargs=kwargs))
#------------------------------------------------------------------------------------

View file

@ -372,7 +372,7 @@ class PortalSessionHandler(SessionHandler):
try:
getattr(session, "send_%s" % cmdname)(session, *cmdargs, **cmdkwargs)
except AttributeError:
session.send_default(session, *cmdargs, **cmdkwargs)
session.send_default(session, cmdname, *cmdargs, **cmdkwargs)
except Exception:
log_trace()

View file

@ -71,11 +71,6 @@ 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):
"""
This is called by all telnet extensions once they are finished.
@ -270,9 +265,9 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
"""
self.sessionhandler.data_out(self, **kwargs)
# send_* methods
@staticmethod
def send_text(session, *args, **kwargs):
def send_text(self, *args, **kwargs):
"""
Send text data. This is an in-band telnet operation.
@ -301,14 +296,14 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
# handle arguments
options = kwargs.get("options", {})
ttype = session.protocol_flags.get('TTYPE', {})
ttype = self.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)
mxp = options.get("mxp", self.protocol_flags.get("MXP", False))
screenreader = options.get("screenreader", self.screenreader)
if screenreader:
# screenreader mode cleans up output
@ -324,11 +319,17 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
prompt = mxp_parse(prompt)
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
prompt += IAC + GA
session.transport.write(mccp_compress(session, prompt))
self.transport.write(mccp_compress(self, prompt))
else:
if echo is not None:
# turn on/off echo
if echo:
self.transport.write(mccp_compress(self, IAC+WILL+ECHO))
else:
self.transport.write(mccp_compress(self, IAC+WONT+ECHO))
if raw:
# no processing
session.sendLine(text)
self.sendLine(text)
return
else:
# we need to make sure to kill the color at the end in order
@ -336,29 +337,19 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
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)
self.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):
def send_prompt(self, *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)
self.send_text(*args, **kwargs)
@staticmethod
def send_oob(session, *args, **kwargs):
def send_default(self, cmdname, *args, **kwargs):
"""
Send oob data
Send other oob data
"""
print "telnet.send_oob not implemented yet! ", args
print "telnet.send_default not implemented yet! ", args

View file

@ -29,11 +29,6 @@ try:
except ImportError:
import pickle
# input handlers
_INPUT_HANDLER_FUNCS = {}
for modname in make_iter(settings.INPUT_HANDLER_MODULES):
_INPUT_HANDLER_FUNCS.update(callables_from_module(modname))
# delayed imports
_PlayerDB = None
@ -68,6 +63,13 @@ _MAX_SERVER_COMMANDS_PER_SECOND = 100.0
_MAX_SESSION_COMMANDS_PER_SECOND = 5.0
_MODEL_MAP = None
# input handlers
_INPUT_HANDLER_FUNCS = {}
for modname in make_iter(settings.INPUT_HANDLER_MODULES):
print modname
_INPUT_HANDLER_FUNCS.update(callables_from_module(modname))
def delayed_import():
"""
Helper method for delayed import of all needed entities.
@ -610,7 +612,7 @@ class ServerSessionHandler(SessionHandler):
print "sessionhandler: data_in", cmdname, cmdargs, cmdkwargs
_INPUT_HANDLER_FUNCS[cmdname](session, *cmdargs, **cmdkwargs)
else:
_INPUT_HANDLER_FUNCS["_default"](session, *cmdargs, **cmdkwargs)
_INPUT_HANDLER_FUNCS["default"](session, cmdname, *cmdargs, **cmdkwargs)
except Exception:
log_trace()

View file

@ -977,7 +977,7 @@ def all_from_module(module):
return {}
# make sure to only return variables actually defined in this module (not imports)
members = getmembers(mod, predicate=lambda obj: getmodule(obj) == mod)
return dict((key, val) for key, val in members.iteritems() if not key.startswith("_"))
return dict((key, val) for key, val in members if not key.startswith("_"))
#return dict((key, val) for key, val in mod.__dict__.items()
# if not (key.startswith("_") or ismodule(val)))
@ -1002,7 +1002,7 @@ def callables_from_module(module):
return {}
# make sure to only return callables actually defined in this module (not imports)
members = getmembers(mod, predicate=lambda obj: callable(obj) and getmodule(obj) == mod)
return dict((key, val) for key, val in members.iteritems() if not key.startswith("_"))
return dict((key, val) for key, val in members if not key.startswith("_"))
def variable_from_module(module, variable=None, default=None):