From 948d14a0fb379e347c6b0200d91072b584838d23 Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 12 Apr 2020 10:24:31 -0700 Subject: [PATCH 1/4] Made almost the entire networking guts replaceable. --- CHANGELOG.md | 1 + evennia/server/portal/amp.py | 2 +- evennia/server/portal/portal.py | 14 ++-- evennia/server/portal/portalsessionhandler.py | 8 ++- evennia/server/portal/ssh.py | 7 +- evennia/server/portal/ssl.py | 6 +- evennia/server/portal/telnet.py | 9 ++- evennia/server/portal/webclient.py | 8 +-- evennia/server/session.py | 19 +----- evennia/server/sessionhandler.py | 7 +- evennia/settings_default.py | 67 ++++++++++++++++++- 11 files changed, 106 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ffa74b003..57876a7524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - New `utils.format_grid` for easily displaying long lists of items in a block. - Using `lunr` search indexing for better `help` matching and suggestions. Also improve the main help command's default listing output. +- Made most of the networking classes such as Protocols and the SessionHandlers replaceable via `settings.py` for modding enthusiasts. ### Already in master diff --git a/evennia/server/portal/amp.py b/evennia/server/portal/amp.py index 505ea5e3e0..c49ac4e55e 100644 --- a/evennia/server/portal/amp.py +++ b/evennia/server/portal/amp.py @@ -15,7 +15,7 @@ import zlib # Used in Compressed class import pickle from twisted.internet.defer import DeferredList, Deferred -from evennia.utils.utils import to_str, variable_from_module +from evennia.utils.utils import variable_from_module # delayed import _LOGGER = None diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 633e63bb51..e16a9b6910 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -25,7 +25,7 @@ import evennia evennia._init() -from evennia.utils.utils import get_evennia_version, mod_import, make_iter +from evennia.utils.utils import get_evennia_version, mod_import, make_iter, class_from_module from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS from evennia.utils import logger from evennia.server.webserver import EvenniaReverseProxyResource @@ -261,6 +261,7 @@ if TELNET_ENABLED: # Start telnet game connections from evennia.server.portal import telnet + _telnet_protocol = class_from_module(settings.TELNET_PROTOCOL_CLASS) for interface in TELNET_INTERFACES: ifacestr = "" @@ -270,7 +271,7 @@ if TELNET_ENABLED: pstring = "%s:%s" % (ifacestr, port) factory = telnet.TelnetServerFactory() factory.noisy = False - factory.protocol = telnet.TelnetProtocol + factory.protocol = _telnet_protocol factory.sessionhandler = PORTAL_SESSIONS telnet_service = internet.TCPServer(port, factory, interface=interface) telnet_service.setName("EvenniaTelnet%s" % pstring) @@ -284,6 +285,7 @@ if SSL_ENABLED: # Start Telnet+SSL game connection (requires PyOpenSSL). from evennia.server.portal import telnet_ssl + _ssl_protocol = class_from_module(settings.SSL_PROTOCOL_CLASS) for interface in SSL_INTERFACES: ifacestr = "" @@ -294,7 +296,7 @@ if SSL_ENABLED: factory = protocol.ServerFactory() factory.noisy = False factory.sessionhandler = PORTAL_SESSIONS - factory.protocol = telnet_ssl.SSLProtocol + factory.protocol = _ssl_protocol ssl_context = telnet_ssl.getSSLContext() if ssl_context: @@ -317,6 +319,7 @@ if SSH_ENABLED: # evennia/game if necessary. from evennia.server.portal import ssh + _ssh_protocol = class_from_module(settings.SSH_PROTOCOL_CLASS) for interface in SSH_INTERFACES: ifacestr = "" @@ -326,7 +329,7 @@ if SSH_ENABLED: pstring = "%s:%s" % (ifacestr, port) factory = ssh.makeFactory( { - "protocolFactory": ssh.SshProtocol, + "protocolFactory": _ssh_protocol, "protocolArgs": (), "sessions": PORTAL_SESSIONS, } @@ -345,6 +348,7 @@ if WEBSERVER_ENABLED: # Start a reverse proxy to relay data to the Server-side webserver websocket_started = False + _websocket_protocol = class_from_module(settings.WEBSOCKET_PROTOCOL_CLASS) for interface in WEBSERVER_INTERFACES: ifacestr = "" if interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: @@ -379,7 +383,7 @@ if WEBSERVER_ENABLED: factory = Websocket() factory.noisy = False - factory.protocol = webclient.WebSocketClient + factory.protocol = _websocket_protocol factory.sessionhandler = PORTAL_SESSIONS websocket_service = internet.TCPServer(port, factory, interface=w_interface) websocket_service.setName("EvenniaWebSocket%s:%s" % (w_ifacestr, port)) diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 0f4c6cb560..dd6fadfc24 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -9,6 +9,7 @@ from twisted.internet import reactor from django.conf import settings from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC, PDISCONNALL from evennia.utils.logger import log_trace +from evennia.utils.utils import class_from_module # module import _MOD_IMPORT = None @@ -32,9 +33,10 @@ DUMMYSESSION = namedtuple("DummySession", ["sessid"])(0) # ------------------------------------------------------------- # Portal-SessionHandler class # ------------------------------------------------------------- +_BASE_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) -class PortalSessionHandler(SessionHandler): +class PortalSessionHandler(_BASE_HANDLER_CLASS): """ This object holds the sessions connected to the portal at any time. It is synced with the server's equivalent SessionHandler over the AMP @@ -463,4 +465,6 @@ class PortalSessionHandler(SessionHandler): log_trace() -PORTAL_SESSIONS = PortalSessionHandler() +_portal_sessionhandler_class = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) + +PORTAL_SESSIONS = _portal_sessionhandler_class() diff --git a/evennia/server/portal/ssh.py b/evennia/server/portal/ssh.py index b2a891710f..3a47dde433 100644 --- a/evennia/server/portal/ssh.py +++ b/evennia/server/portal/ssh.py @@ -43,10 +43,9 @@ from twisted.conch import interfaces as iconch from twisted.python import components from django.conf import settings -from evennia.server import session from evennia.accounts.models import AccountDB from evennia.utils import ansi -from evennia.utils.utils import to_str +from evennia.utils.utils import to_str, class_from_module _RE_N = re.compile(r"\|n$") _RE_SCREENREADER_REGEX = re.compile( @@ -74,6 +73,8 @@ and put them here: _PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE ) +_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) + # not used atm class SSHServerFactory(protocol.ServerFactory): @@ -84,7 +85,7 @@ class SSHServerFactory(protocol.ServerFactory): return "SSH" -class SshProtocol(Manhole, session.Session): +class SshProtocol(Manhole, _BASE_SESSION): """ Each account connecting over ssh gets this protocol assigned to them. All communication between game and account goes through diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index 44642bd9e9..03aea685d4 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -18,7 +18,7 @@ except ImportError as error: raise ImportError(errstr.format(err=error)) from django.conf import settings -from evennia.server.portal.telnet import TelnetProtocol +from evennia.utils.utils import class_from_module _GAME_DIR = settings.GAME_DIR @@ -43,8 +43,10 @@ example (linux, using the openssl program): {exestring} """ +_TELNET_PROTOCOL = class_from_module(settings.TELNET_PROTOCOL_CLASS) -class SSLProtocol(TelnetProtocol): + +class SSLProtocol(_TELNET_PROTOCOL): """ Communication is the same as telnet, except data transfer is done with encryption. diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 4dbee60f7d..c45f57d6e0 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -25,12 +25,11 @@ from twisted.conch.telnet import ( LINEMODE_TRAPSIG, ) from django.conf import settings -from evennia.server.session import Session from evennia.server.portal import ttype, mssp, telnet_oob, naws, suppress_ga from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP from evennia.server.portal.mxp import Mxp, mxp_parse from evennia.utils import ansi -from evennia.utils.utils import to_bytes +from evennia.utils.utils import to_bytes, class_from_module _RE_N = re.compile(r"\|n$") _RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE) @@ -56,6 +55,10 @@ _HTTP_WARNING = bytes( ) +_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) + + + class TelnetServerFactory(protocol.ServerFactory): "This is only to name this better in logs" noisy = False @@ -64,7 +67,7 @@ class TelnetServerFactory(protocol.ServerFactory): return "Telnet" -class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): +class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION): """ Each player connecting over telnet (ie using most traditional mud clients) gets a telnet protocol instance assigned to them. All diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index faee4c20f4..d56e0a2815 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -17,10 +17,8 @@ from the command line and interprets it as an Evennia Command: `["text", ["look" import re import json import html -from twisted.internet.protocol import Protocol from django.conf import settings -from evennia.server.session import Session -from evennia.utils.utils import to_str, mod_import +from evennia.utils.utils import mod_import, class_from_module from evennia.utils.ansi import parse_ansi from evennia.utils.text2html import parse_html from autobahn.twisted.websocket import WebSocketServerProtocol @@ -39,8 +37,10 @@ CLOSE_NORMAL = WebSocketServerProtocol.CLOSE_STATUS_CODE_NORMAL # called when the browser is navigating away from the page GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY +_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) -class WebSocketClient(WebSocketServerProtocol, Session): + +class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION): """ Implements the server-side of the Websocket connection. """ diff --git a/evennia/server/session.py b/evennia/server/session.py index dab0f4b705..093472e820 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -36,24 +36,7 @@ class Session(object): """ # names of attributes that should be affected by syncing. - _attrs_to_sync = ( - "protocol_key", - "address", - "suid", - "sessid", - "uid", - "csessid", - "uname", - "logged_in", - "puid", - "conn_time", - "cmd_last", - "cmd_last_visible", - "cmd_total", - "protocol_flags", - "server_data", - "cmdset_storage_string", - ) + _attrs_to_sync = settings.SESSION_SYNC_ATTRS def init_session(self, protocol_key, address, sessionhandler): """ diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 0d099d6d30..23850318f2 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -23,6 +23,7 @@ from evennia.utils.utils import ( make_iter, delay, callables_from_module, + class_from_module ) from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT @@ -857,5 +858,9 @@ class ServerSessionHandler(SessionHandler): log_trace() -SESSION_HANDLER = ServerSessionHandler() +# import class from settings +_session_handler_class = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) + +# Instantiate class. These globals are used to provide singleton-like behavior. +SESSION_HANDLER = _session_handler_class() SESSIONS = SESSION_HANDLER # legacy diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 751791b549..b7778161eb 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -465,9 +465,6 @@ CHANNEL_COMMAND_CLASS = "evennia.comms.channelhandler.ChannelCommand" # Typeclasses and other paths ###################################################################### -# Server-side session class used. -SERVER_SESSION_CLASS = "evennia.server.serversession.ServerSession" - # These are paths that will be prefixed to the paths given if the # immediately entered path fail to find a typeclass. It allows for # shorter input strings. They must either base off the game directory @@ -511,6 +508,70 @@ START_LOCATION = "#2" # issues. TYPECLASS_AGGRESSIVE_CACHE = True +###################################################################### +# Networking Replaceable Guts +###################################################################### +# Modify the things below at your own risk. This is here be dragons territory. + +# The Base Session Class is used as a parent class for all Protocols such as +# Telnet and SSH.) Changing this could be really dangerous. It will cascade +# to tons of classes. You generally shouldn't need to touch protocols. +BASE_SESSION_CLASS = "evennia.server.session.Session" + +# Telnet Protocol inherits from whatever above BASE_SESSION_CLASS is specified. +# It is used for all telnet connections, and is also inherited by the SSL Protocol +# (which is just TLS + Telnet). +TELNET_PROTOCOL_CLASS = "evennia.server.portal.telnet.TelnetProtocol" +SSL_PROTOCOL_CLASS = "evennia.server.portal.ssl.SSLProtocol" + +# Websocket Client Protocol. This inherits from BASE_SESSION_CLASS. It is used +# for all webclient connections. +WEBSOCKET_PROTOCOL_CLASS = "evennia.server.portal.webclient.WebSocketClient" + +# Protocol for the SSH interface. This inherits from BASE_SESSION_CLASS. +SSH_PROTOCOL_CLASS = "evennia.server.portal.ssh.SshProtocol" + +# Server-side session class used. This will inherit from BASE_SESSION_CLASS. +# This one isn't as dangerous to replace. +SERVER_SESSION_CLASS = "evennia.server.serversession.ServerSession" + +# The Server SessionHandler manages all ServerSessions, handling logins, +# ensuring the login process happens smoothly, handling expected and +# unexpected disconnects. You shouldn't need to touch it, but you can. +# Replace it to implement altered game logic. +SERVER_SESSION_HANDLER_CLASS = "evennia.server.sessionhandler.ServerSessionHandler" + +# The Portal SessionHandler manages all incoming connections regardless of +# the protocol in use. It is responsible for keeping them going and informing +# the Server Session Handler of the connections and synchronizing them across the +# AMP connection. You shouldn't ever need to change this. But you can. +PORTAL_SESSION_HANDLER_CLASS = "evennia.server.portal.portalsessionhandler.PortalSessionHandler" + + +# These are members / properties / attributes kept on both Server and +# Portal Sessions. They are sync'd at various points, such as logins and +# reloads. If you add to this, you may need to adjust the class __init__ +# so the additions have somewhere to go. These must be simple things that +# can be pickled - stuff you could serialize to JSON is best. +SESSION_SYNC_ATTRS = ( + "protocol_key", + "address", + "suid", + "sessid", + "uid", + "csessid", + "uname", + "logged_in", + "puid", + "conn_time", + "cmd_last", + "cmd_last_visible", + "cmd_total", + "protocol_flags", + "server_data", + "cmdset_storage_string" + ) + ###################################################################### # Options and validators ###################################################################### From 58230504c5f26f19fcd39027edf951780849451f Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 12 Apr 2020 10:29:51 -0700 Subject: [PATCH 2/4] Missed a tiny detail in portalsessionhandler.py --- evennia/server/portal/portalsessionhandler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index dd6fadfc24..746ab40a67 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -33,10 +33,9 @@ DUMMYSESSION = namedtuple("DummySession", ["sessid"])(0) # ------------------------------------------------------------- # Portal-SessionHandler class # ------------------------------------------------------------- -_BASE_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) -class PortalSessionHandler(_BASE_HANDLER_CLASS): +class PortalSessionHandler(SessionHandler): """ This object holds the sessions connected to the portal at any time. It is synced with the server's equivalent SessionHandler over the AMP From 0639d43ddc09b08304e7f3cc9a2f22da58f28177 Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 12 Apr 2020 13:00:47 -0700 Subject: [PATCH 3/4] Cleaned up the pep8 --- evennia/server/portal/portalsessionhandler.py | 4 ++-- evennia/server/portal/ssh.py | 4 ++-- evennia/server/portal/ssl.py | 4 ++-- evennia/server/portal/telnet.py | 4 ++-- evennia/server/portal/webclient.py | 4 ++-- evennia/server/session.py | 7 +------ evennia/server/sessionhandler.py | 4 ++-- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 746ab40a67..6b465cc0f7 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -464,6 +464,6 @@ class PortalSessionHandler(SessionHandler): log_trace() -_portal_sessionhandler_class = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) +_PORTAL_SESSION_HANDLER_CLASS = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) -PORTAL_SESSIONS = _portal_sessionhandler_class() +PORTAL_SESSIONS = _PORTAL_SESSION_HANDLER_CLASS() diff --git a/evennia/server/portal/ssh.py b/evennia/server/portal/ssh.py index 3a47dde433..1fcf296058 100644 --- a/evennia/server/portal/ssh.py +++ b/evennia/server/portal/ssh.py @@ -73,7 +73,7 @@ and put them here: _PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE ) -_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) # not used atm @@ -85,7 +85,7 @@ class SSHServerFactory(protocol.ServerFactory): return "SSH" -class SshProtocol(Manhole, _BASE_SESSION): +class SshProtocol(Manhole, _BASE_SESSION_CLASS): """ Each account connecting over ssh gets this protocol assigned to them. All communication between game and account goes through diff --git a/evennia/server/portal/ssl.py b/evennia/server/portal/ssl.py index 03aea685d4..ce58fdf778 100644 --- a/evennia/server/portal/ssl.py +++ b/evennia/server/portal/ssl.py @@ -43,10 +43,10 @@ example (linux, using the openssl program): {exestring} """ -_TELNET_PROTOCOL = class_from_module(settings.TELNET_PROTOCOL_CLASS) +_TELNET_PROTOCOL_CLASS = class_from_module(settings.TELNET_PROTOCOL_CLASS) -class SSLProtocol(_TELNET_PROTOCOL): +class SSLProtocol(_TELNET_PROTOCOL_CLASS): """ Communication is the same as telnet, except data transfer is done with encryption. diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index c45f57d6e0..62ef3d7338 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -55,7 +55,7 @@ _HTTP_WARNING = bytes( ) -_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) @@ -67,7 +67,7 @@ class TelnetServerFactory(protocol.ServerFactory): return "Telnet" -class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION): +class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS): """ Each player connecting over telnet (ie using most traditional mud clients) gets a telnet protocol instance assigned to them. All diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index d56e0a2815..f38e39fabc 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -37,10 +37,10 @@ CLOSE_NORMAL = WebSocketServerProtocol.CLOSE_STATUS_CODE_NORMAL # called when the browser is navigating away from the page GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY -_BASE_SESSION = class_from_module(settings.BASE_SESSION_CLASS) +_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS) -class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION): +class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS): """ Implements the server-side of the Websocket connection. """ diff --git a/evennia/server/session.py b/evennia/server/session.py index 093472e820..f322c551cf 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -35,9 +35,6 @@ class Session(object): """ - # names of attributes that should be affected by syncing. - _attrs_to_sync = settings.SESSION_SYNC_ATTRS - def init_session(self, protocol_key, address, sessionhandler): """ Initialize the Session. This should be called by the protocol when @@ -104,9 +101,7 @@ class Session(object): the keys given by self._attrs_to_sync. """ - return dict( - (key, value) for key, value in self.__dict__.items() if key in self._attrs_to_sync - ) + return {attr: getattr(self, attr, None) for attr in settings.SESSION_SYNC_ATTRS} def load_sync_data(self, sessdata): """ diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 23850318f2..b25d25ebb4 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -859,8 +859,8 @@ class ServerSessionHandler(SessionHandler): # import class from settings -_session_handler_class = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) +_SESSION_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) # Instantiate class. These globals are used to provide singleton-like behavior. -SESSION_HANDLER = _session_handler_class() +SESSION_HANDLER = _SESSION_HANDLER_CLASS() SESSIONS = SESSION_HANDLER # legacy From d7623cd8a51e54ec4a252c0530a8c9b6943e7b69 Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 12 Apr 2020 17:01:43 -0700 Subject: [PATCH 4/4] Added AMP support to the Replaceable Networking effort. Can now replace the AMP protocols. Also cleaned up some imports. --- evennia/server/amp_client.py | 4 +- evennia/server/portal/amp_server.py | 5 ++- evennia/server/portal/portalsessionhandler.py | 3 +- evennia/server/sessionhandler.py | 40 +++++-------------- evennia/settings_default.py | 5 +++ 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/evennia/server/amp_client.py b/evennia/server/amp_client.py index 3c3f40dc7a..c6ef5ec5cc 100644 --- a/evennia/server/amp_client.py +++ b/evennia/server/amp_client.py @@ -5,9 +5,11 @@ Portal. This module sets up the Client-side communication. """ import os +from django.conf import settings from evennia.server.portal import amp from twisted.internet import protocol from evennia.utils import logger +from evennia.utils.utils import class_from_module class AMPClientFactory(protocol.ReconnectingClientFactory): @@ -33,7 +35,7 @@ class AMPClientFactory(protocol.ReconnectingClientFactory): """ self.server = server - self.protocol = AMPServerClientProtocol + self.protocol = class_from_module(settings.AMP_CLIENT_PROTOCOL_CLASS) self.maxDelay = 10 # not really used unless connecting to multiple servers, but # avoids having to check for its existence on the protocol diff --git a/evennia/server/portal/amp_server.py b/evennia/server/portal/amp_server.py index de8a08ecf9..f4c9463284 100644 --- a/evennia/server/portal/amp_server.py +++ b/evennia/server/portal/amp_server.py @@ -11,6 +11,7 @@ from evennia.server.portal import amp from django.conf import settings from subprocess import Popen, STDOUT from evennia.utils import logger +from evennia.utils.utils import class_from_module def _is_windows(): @@ -56,7 +57,7 @@ class AMPServerFactory(protocol.ServerFactory): """ self.portal = portal - self.protocol = AMPServerProtocol + self.protocol = class_from_module(settings.AMP_SERVER_PROTOCOL_CLASS) self.broadcasts = [] self.server_connection = None self.launcher_connection = None @@ -74,7 +75,7 @@ class AMPServerFactory(protocol.ServerFactory): protocol (Protocol): The created protocol. """ - self.portal.amp_protocol = AMPServerProtocol() + self.portal.amp_protocol = self.protocol() self.portal.amp_protocol.factory = self return self.portal.amp_protocol diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index 6b465cc0f7..8afbdb3780 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -7,7 +7,8 @@ import time from collections import deque, namedtuple from twisted.internet import reactor from django.conf import settings -from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC, PDISCONNALL +from evennia.server.sessionhandler import SessionHandler +from evennia.server.portal.amp import PCONN, PDISCONN, PCONNSYNC, PDISCONNALL from evennia.utils.logger import log_trace from evennia.utils.utils import class_from_module diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index b25d25ebb4..e315dc7a82 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -25,6 +25,7 @@ from evennia.utils.utils import ( callables_from_module, class_from_module ) +from evennia.server.portal import amp from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT from evennia.utils.inlinefuncs import parse_inlinefunc @@ -48,25 +49,6 @@ class DummySession(object): DUMMYSESSION = DummySession() -# AMP signals -PCONN = chr(1) # portal session connect -PDISCONN = chr(2) # portal session disconnect -PSYNC = chr(3) # portal session sync -SLOGIN = chr(4) # server session login -SDISCONN = chr(5) # server session disconnect -SDISCONNALL = chr(6) # server session disconnect all -SSHUTD = chr(7) # server shutdown -SSYNC = chr(8) # server session sync -SCONN = chr(11) # server portal connection (for bots) -PCONNSYNC = chr(12) # portal post-syncing session -PDISCONNALL = chr(13) # portal session discnnect all -SRELOAD = chr(14) # server reloading (have portal start a new server) -SSTART = chr(15) # server start (portal must already be running anyway) -PSHUTD = chr(16) # portal (+server) shutdown -SSHUTD = chr(17) # server shutdown -PSTATUS = chr(18) # ping server or portal status -SRESET = chr(19) # server shutdown in reset mode - # i18n from django.utils.translation import gettext as _ @@ -452,7 +434,7 @@ class ServerSessionHandler(SessionHandler): """ self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SCONN, protocol_path=protocol_path, config=configdict + DUMMYSESSION, operation=amp.SCONN, protocol_path=protocol_path, config=configdict ) def portal_restart_server(self): @@ -460,14 +442,14 @@ class ServerSessionHandler(SessionHandler): Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRELOAD) + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRELOAD) def portal_reset_server(self): """ Called by server when reloading. We tell the portal to start a new server instance. """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRESET) + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRESET) def portal_shutdown(self): """ @@ -475,7 +457,7 @@ class ServerSessionHandler(SessionHandler): itself down) """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=PSHUTD) + self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.PSHUTD) def login(self, session, account, force=False, testmode=False): """ @@ -523,7 +505,7 @@ class ServerSessionHandler(SessionHandler): # sync the portal to the session if not testmode: self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} + session, operation=amp.SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} ) account.at_post_login(session=session) if nsess < 2: @@ -568,7 +550,7 @@ class ServerSessionHandler(SessionHandler): if sync_portal: # inform portal that session should be closed. self.server.amp_protocol.send_AdminServer2Portal( - session, operation=SDISCONN, reason=reason + session, operation=amp.SDISCONN, reason=reason ) def all_sessions_portal_sync(self): @@ -579,7 +561,7 @@ class ServerSessionHandler(SessionHandler): """ sessdata = self.get_all_sync_data() return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata ) def session_portal_sync(self, session): @@ -590,7 +572,7 @@ class ServerSessionHandler(SessionHandler): """ sessdata = {session.sessid: session.get_sync_data()} return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=sessdata, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata, clean=False ) def session_portal_partial_sync(self, session_data): @@ -603,7 +585,7 @@ class ServerSessionHandler(SessionHandler): """ return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SSYNC, sessiondata=session_data, clean=False + DUMMYSESSION, operation=amp.SSYNC, sessiondata=session_data, clean=False ) def disconnect_all_sessions(self, reason="You have been disconnected."): @@ -619,7 +601,7 @@ class ServerSessionHandler(SessionHandler): del session # tell portal to disconnect all sessions self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=SDISCONNALL, reason=reason + DUMMYSESSION, operation=amp.SDISCONNALL, reason=reason ) def disconnect_duplicate_sessions( diff --git a/evennia/settings_default.py b/evennia/settings_default.py index b7778161eb..dcc3c57e1d 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -572,6 +572,11 @@ SESSION_SYNC_ATTRS = ( "cmdset_storage_string" ) +# The following are used for the communications between the Portal and Server. +# Very dragons territory. +AMP_SERVER_PROTOCOL_CLASS = 'evennia.server.portal.amp_server.AMPServerProtocol' +AMP_CLIENT_PROTOCOL_CLASS = 'evennia.server.amp_client.AMPServerClientProtocol' + ###################################################################### # Options and validators ######################################################################