Created setter inputfuncs for the basic GMCP handhakes. Also added

the possibility for the Server to sync a single Session with the
Portal.
This commit is contained in:
Griatch 2016-03-25 11:12:33 +01:00
parent 196306d914
commit f3512971e3
4 changed files with 130 additions and 9 deletions

View file

@ -559,7 +559,8 @@ class AMPProtocol(amp.AMP):
elif operation == SSYNC: # server_session_sync elif operation == SSYNC: # server_session_sync
# server wants to save session data to the portal, # server wants to save session data to the portal,
# maybe because it's about to shut down. # maybe because it's about to shut down.
portal_sessionhandler.server_session_sync(kwargs.get("sessiondata")) portal_sessionhandler.server_session_sync(kwargs.get("sessiondata"),
kwargs.get("clean", True))
# set a flag in case we are about to shut down soon # set a flag in case we are about to shut down soon
self.factory.server_restart_mode = True self.factory.server_restart_mode = True

View file

@ -1,5 +1,19 @@
""" """
Handlers for input commands 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:
inputfunc(session, *args, **kwargs)
There is one special function, the "default" function, which is called
on a no-match. It has this callsign:
default(session, cmdname, *args, **kwargs)
Evennia knows which modules to use for inputfuncs by
settings.INPUT_FUNC_MODULES.
""" """
from future.utils import viewkeys from future.utils import viewkeys
@ -9,11 +23,17 @@ from evennia.commands.cmdhandler import cmdhandler
from evennia.utils.logger import log_err from evennia.utils.logger import log_err
from evennia.utils.utils import to_str from evennia.utils.utils import to_str
_IDLE_COMMAND = settings.IDLE_COMMAND _IDLE_COMMAND = settings.IDLE_COMMAND
_GA = object.__getattribute__ _GA = object.__getattribute__
_SA = object.__setattr__ _SA = object.__setattr__
_NA = lambda o: "N/A" _NA = lambda o: "N/A"
_ERROR_INPUT = "Inputfunc {name}({session}): Wrong/unrecognized input: {inp}"
# All global functions are inputfuncs available to process inputs
def text(session, *args, **kwargs): def text(session, *args, **kwargs):
""" """
Main text input from the client. This will execute a command Main text input from the client. This will execute a command
@ -51,11 +71,16 @@ def text(session, *args, **kwargs):
cmdhandler(session, text, callertype="session", session=session) cmdhandler(session, text, callertype="session", session=session)
session.update_session_counters() session.update_session_counters()
def echo(session, *args, **kwargs): def echo(session, *args, **kwargs):
"""
Echo test function
"""
print "Inputfunc echo:", session, args, kwargs print "Inputfunc echo:", session, args, kwargs
session.data_out(text="Echo returns: ") session.data_out(text="Echo returns: ")
session.data_out(echo=(args, kwargs)) session.data_out(echo=(args, kwargs))
def default(session, cmdname, *args, **kwargs): def default(session, cmdname, *args, **kwargs):
""" """
Default catch-function. This is like all other input functions except Default catch-function. This is like all other input functions except
@ -67,8 +92,89 @@ def default(session, cmdname, *args, **kwargs):
" args, kwargs: {args}, {kwargs}" " args, kwargs: {args}, {kwargs}"
log_err(err.format(sessid=session.sessid, cmdname=cmdname, args=args, kwargs=kwargs)) log_err(err.format(sessid=session.sessid, cmdname=cmdname, args=args, kwargs=kwargs))
def client_settings(session, *args, **kwargs):
"""
This allows the client an OOB way to inform us about its name and capabilities.
This will be integrated into the session settings
Kwargs:
client (str): A client identifier, like "mushclient".
version (str): A client version
ansi (bool): Supports ansi colors
xterm256 (bool): Supports xterm256 colors or not
mxp (bool): Supports MXP or not
utf-8 (bool): Supports UTF-8 or not
screenreader (bool): Screen-reader mode on/off
mccp (bool): MCCP compression on/off
screenheight (int): Screen height in lines
screenwidth (int): Screen width in characters
"""
flags = session.protocol_flags
tflags = flags["TTYPE"]
for key, value in kwargs.iteritems():
key = key.lower()
if key == "client":
tflags["CLIENTNAME"] = to_str(value)
elif key == "version":
if "CLIENTNAME" in tflags:
tflags["CLIENTNAME"] = "%s %s" % (tflags["CLIENTNAME"], to_str(value))
elif key == "ansi":
tflags["ANSI"] = bool(value)
elif key == "xterm256":
tflags["256 COLORS"] = bool(value)
elif key == "mxp":
flags["MXP"] = bool(value)
elif key == "utf-8":
tflags["UTF-8"] = bool(value)
elif key == "screenreader":
flags["SCREENREADER"] = bool(value)
elif key == "mccp":
flags["MCCP"] = bool(value)
elif key == "screenheight":
flags["SCREENHEIGHT"] = int(value)
elif key == "screenwidth":
flags["SCREENWIDTH"] = int(value)
else:
err = _ERROR_INPUT.format(
name="client_settings", session=session, inp=key)
session.msg(text=err)
flags["TTYPE"] = tflags
session.protocol_flags = flags
# we must update the portal as well
session.sessionhandler.session_portal_sync(session)
def login(session, *args, **kwargs):
"""
Peform a login. This only works if session is currently not logged
in. This will also automatically throttle too quick attempts.
Kwargs:
name (str): Player name
password (str): Plain-text password
"""
if not session.logged_in and "name" in kwargs and "password" in kwargs:
from evennia.commands.default.unloggedin import create_normal_player
player = create_normal_player(session, kwargs["name"], kwargs["password"])
if player:
session.sessionhandler.login(session, player)
# aliases for GMCP
core_hello = client_settings # Core.Hello
core_supports_set = client_settings # Core.Supports.Set
char_login = login # Char.Login
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
#------------------------------------------------------------ #------------------------------------------------------------
# All OOB commands must be on the form # All OOB commands must be on the form
# cmdname(session, *args, **kwargs) # cmdname(session, *args, **kwargs)

View file

@ -236,25 +236,27 @@ class PortalSessionHandler(SessionHandler):
""" """
session.load_sync_data(data) session.load_sync_data(data)
def server_session_sync(self, serversessions): def server_session_sync(self, serversessions, clean=True):
""" """
Server wants to save data to the portal, maybe because it's Server wants to save data to the portal, maybe because it's
about to shut down. We don't overwrite any sessions here, just about to shut down. We don't overwrite any sessions here, just
update them in-place and remove any that are out of sync update them in-place.
(which should normally not be the case)
Args: Args:
serversessions (dict): This is a dictionary serversessions (dict): This is a dictionary
`{sessid:{property:value},...}` describing `{sessid:{property:value},...}` describing
the properties to sync on all sessions. the properties to sync on all sessions.
clean (bool): If True, remove any Portal sessions that are
not included in serversessions.
""" """
to_save = [sessid for sessid in serversessions if sessid in self] to_save = [sessid for sessid in serversessions if sessid in self]
to_delete = [sessid for sessid in self if sessid not in to_save]
# save protocols # save protocols
for sessid in to_save: for sessid in to_save:
self[sessid].load_sync_data(serversessions[sessid]) self[sessid].load_sync_data(serversessions[sessid])
if clean:
# disconnect out-of-sync missing protocols # disconnect out-of-sync missing protocols
to_delete = [sessid for sessid in self if sessid not in to_save]
for sessid in to_delete: for sessid in to_delete:
self.server_disconnect(sessid) self.server_disconnect(sessid)

View file

@ -446,6 +446,18 @@ class ServerSessionHandler(SessionHandler):
operation=SSYNC, operation=SSYNC,
sessiondata=sessdata) sessiondata=sessdata)
def session_portal_sync(self, session):
"""
This is called by the server when it wants to sync a single session
with the Portal for whatever reason. Returns a deferred!
"""
sessdata = {session.sessid: session.get_sync_data()}
return self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION,
operation=SSYNC,
sessiondata=sessdata,
clean=False)
def disconnect_all_sessions(self, reason="You have been disconnected."): def disconnect_all_sessions(self, reason="You have been disconnected."):
""" """
Cleanly disconnect all of the connected sessions. Cleanly disconnect all of the connected sessions.