mirror of
https://github.com/evennia/evennia.git
synced 2026-03-30 20:47:17 +02:00
Starting to clean up and debug the server-side infrastructure
This commit is contained in:
parent
e4d50ff74e
commit
96ace8c75f
9 changed files with 135 additions and 131 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
55
evennia/game_template/server/conf/inputhandler_funcs.py
Normal file
55
evennia/game_template/server/conf/inputhandler_funcs.py
Normal 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
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
#------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue