Add support for MSDP LIST/REPORT/UNREPORT. Resolves #1507.

This commit is contained in:
Griatch 2019-03-31 13:37:08 +02:00
parent 7bf4874f7e
commit fccb128952
4 changed files with 110 additions and 25 deletions

View file

@ -93,18 +93,17 @@ Web/Django standard initiative (@strikaco)
+ `validate_password`: Mechanism for validating a password based on predefined Django validators.
+ `set_password`: Apply password to account, using validation checks.
### Server
- Convert ServerConf model to store its values as a Picklefield (same as Attributes) instead of using a custom solution.
- OOB: Add support for MSDP LIST, REPORT, UNREPORT commands (re-mapped to `msdp_list`,
`msdp_report`, `msdp_unreport` inlinefuncs_)
### Utils
- `evennia` launcher now fully handles all django-admin commands, like running tests in parallel.
- `evennia.utils.create.account` now also takes `tags` and `attrs` keywords.
- Added many more unit tests.
### Server
- Convert ServerConf model to store its values as a Picklefield (same as Attributes) instead of using a custom solution.
### Utils
- Swap argument order of `evennia.set_trace` to `set_trace(term_size=(140, 40), debugger='auto')`
since the size is more likely to be changed on the command line.
- `utils.to_str(text, session=None)` now acts as the old `utils.to_unicode` (which was removed).
@ -113,7 +112,8 @@ Web/Django standard initiative (@strikaco)
`force_string` flag was removed and assumed always set).
- `utils.to_bytes(text, session=None)` replaces the old `utils.to_str()` functionality and converts
str to bytes.
- `evennia.MONITOR_HANDLER.all` now takes keyword argument `obj` to only retrieve monitors from that specific
Object (rather than all monitors in the entire handler).
### Contribs

View file

@ -172,16 +172,21 @@ class MonitorHandler(object):
"""
self.monitors = defaultdict(lambda: defaultdict(dict))
def all(self):
def all(self, obj=None):
"""
List all monitors.
List all monitors or all monitors of a given object.
Args:
obj (Object): The object on which to list all monitors.
Returns:
monitors (list): The handled monitors.
"""
output = []
for obj in self.monitors:
objs = [obj] if obj else self.monitors
for obj in objs:
for fieldname in self.monitors[obj]:
for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items():
output.append((obj, fieldname, idstring, persistent, kwargs))

View file

@ -3,7 +3,8 @@ Functions for processing input commands.
All global functions in this module whose name does not start with "_"
is considered an inputfunc. Each function must have the following
callsign:
callsign (where inputfunc name is always lower-case, no matter what the
OOB input name looked like):
inputfunc(session, *args, **kwargs)
@ -138,6 +139,11 @@ def default(session, cmdname, *args, **kwargs):
log_err(err)
_CLIENT_OPTIONS = \
("ANSI", "XTERM256", "MXP", "UTF-8", "SCREENREADER", "ENCODING", "MCCP",
"SCREENHEIGHT", "SCREENWIDTH", "INPUTDEBUG", "RAW", "NOCOLOR", "NOGOAHEAD")
def client_options(session, *args, **kwargs):
"""
This allows the client an OOB way to inform us about its name and capabilities.
@ -165,12 +171,7 @@ def client_options(session, *args, **kwargs):
if not kwargs or kwargs.get("get", False):
# return current settings
options = dict((key, old_flags[key]) for key in old_flags
if key.upper() in ("ANSI", "XTERM256", "MXP",
"UTF-8", "SCREENREADER", "ENCODING",
"MCCP", "SCREENHEIGHT",
"SCREENWIDTH", "INPUTDEBUG",
"RAW", "NOCOLOR",
"NOGOAHEAD"))
if key.upper() in _CLIENT_OPTIONS)
session.msg(client_options=options)
return
@ -239,11 +240,6 @@ def client_options(session, *args, **kwargs):
{session.sessid: {"protocol_flags": flags}})
# GMCP alias
hello = client_options
supports_set = client_options
def get_client_options(session, *args, **kwargs):
"""
Alias wrapper for getting options.
@ -368,10 +364,14 @@ def _on_monitor_change(**kwargs):
obj = kwargs["obj"]
name = kwargs["name"]
session = kwargs["session"]
outputfunc_name = kwargs['outputfunc_name']
# the session may be None if the char quits and someone
# else then edits the object
if session:
session.msg(monitor={"name": name, "value": _GA(obj, fieldname)})
callsign = {outputfunc_name: {"name": name, "value": _GA(obj, fieldname)}}
session.msg(**callsign)
def monitor(session, *args, **kwargs):
@ -384,10 +384,14 @@ def monitor(session, *args, **kwargs):
in the _monitorable dict earlier in this module
are accepted.
stop (bool): Stop monitoring the above name.
outputfunc_name (str, optional): Change the name of
the outputfunc name. This is used e.g. by MSDP which
has its own specific output format.
"""
from evennia.scripts.monitorhandler import MONITOR_HANDLER
name = kwargs.get("name", None)
outputfunc_name = kwargs("outputfunc_name", "monitor")
if name and name in _monitorable and session.puppet:
field_name = _monitorable[name]
obj = session.puppet
@ -396,7 +400,8 @@ def monitor(session, *args, **kwargs):
else:
# the handler will add fieldname and obj to the kwargs automatically
MONITOR_HANDLER.add(obj, field_name, _on_monitor_change, idstring=session.sessid,
persistent=False, name=name, session=session)
persistent=False, name=name, session=session,
outputfunc_name=outputfunc_name)
def unmonitor(session, *args, **kwargs):
@ -407,6 +412,17 @@ def unmonitor(session, *args, **kwargs):
monitor(session, *args, **kwargs)
def monitored(session, *args, **kwargs):
"""
Report on what is being monitored
"""
from evennia.scripts.monitorhandler import MONITOR_HANDLER
obj = session.puppet
monitors = MONITOR_HANDLER.all(obj=obj)
session.msg(monitored=(monitors, {}))
def _on_webclient_options_change(**kwargs):
"""
Called when the webclient options stored on the account changes.
@ -469,3 +485,60 @@ def webclient_options(session, *args, **kwargs):
# kwargs provided: persist them to the account object
for key, value in kwargs.items():
clientoptions[key] = value
# OOB protocol-specific aliases and wrappers
# GMCP aliases
hello = client_options
supports_set = client_options
# MSDP aliases (some of the the generic MSDP commands defined in the MSDP spec are prefixed
# by msdp_ at the protocol level)
# See https://tintin.sourceforge.io/protocols/msdp/
def msdp_list(session, *args, **kwargs):
"""
MSDP LIST command
"""
from evennia.scripts.monitorhandler import MONITOR_HANDLER
args_lower = [arg.lower() for arg in args]
if "commands" in args_lower:
inputfuncs = [key[5:] if key.startswith("msdp_") else key
for key in session.sessionhandler.get_inputfuncs().keys()]
session.msg(commands=(inputfuncs, {}))
if "lists" in args_lower:
session.msg(lists=(['commands', 'lists', 'configurable_variables', 'reportable_variables',
'reported_variables', 'sendable_variables'], {}))
if "configurable_variables" in args_lower:
session.msg(configurable_variables=(_CLIENT_OPTIONS, {}))
if "reportable_variables" in args_lower:
session.msg(reportable_variables=(_monitorable, {}))
if "reported_variables" in args_lower:
obj = session.puppet
monitor_infos = MONITOR_HANDLER.all(obj=obj)
fieldnames = [tup[1] for tup in monitor_infos]
session.msg(reported_variables=(fieldnames, {}))
if "sendable_variables" in args_lower:
# no default sendable variables
session.msg(sendable_variables=([], {}))
def msdp_report(session, *args, **kwargs):
"""
MSDP REPORT command
"""
kwargs['outputfunc_name': 'report']
monitor(session, *args, **kwargs)
def msdp_unreport(session, *args, **kwargs):
"""
MSDP UNREPORT command
"""
unmonitor(session, *args, **kwargs)

View file

@ -350,6 +350,13 @@ class TelnetOOB(object):
for key, var in variables.items():
cmds[key] = [[var], {}]
# remap the 'generic msdp commands' to avoid colliding with builtins etc
# by prepending "msdp_"
lower_case = {key.lower(): key for key in cmds}
for remap in ("list", "report", "reset", "send", "unreport"):
if remap in lower_case:
cmds["msdp_{}".format(remap)] = cmds.pop(lower_case[remap])
# print("msdp data in:", cmds) # DEBUG
self.protocol.data_in(**cmds)