I18n string cleanup and refactoring
This commit is contained in:
parent
59dd0b007a
commit
7ff8cbb341
62 changed files with 890 additions and 738 deletions
|
|
@ -9,8 +9,6 @@ manager's conf() method.
|
|||
|
||||
"""
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from evennia.utils.idmapper.models import WeakSharedMemoryModel
|
||||
from evennia.utils import logger, utils
|
||||
|
|
|
|||
|
|
@ -93,7 +93,10 @@ def loads(data):
|
|||
|
||||
|
||||
def _get_logger():
|
||||
"Delay import of logger until absolutely necessary"
|
||||
"""
|
||||
Delay import of logger until absolutely necessary
|
||||
|
||||
"""
|
||||
global _LOGGER
|
||||
if not _LOGGER:
|
||||
from evennia.utils import logger as _LOGGER
|
||||
|
|
@ -102,7 +105,10 @@ def _get_logger():
|
|||
|
||||
@wraps
|
||||
def catch_traceback(func):
|
||||
"Helper decorator"
|
||||
"""
|
||||
Helper decorator
|
||||
|
||||
"""
|
||||
|
||||
def decorator(*args, **kwargs):
|
||||
try:
|
||||
|
|
@ -353,6 +359,7 @@ class AMPMultiConnectionProtocol(amp.AMP):
|
|||
def dataReceived(self, data):
|
||||
"""
|
||||
Handle non-AMP messages, such as HTTP communication.
|
||||
|
||||
"""
|
||||
# print("dataReceived: {}".format(data))
|
||||
if data[:1] == NUL:
|
||||
|
|
@ -413,6 +420,7 @@ class AMPMultiConnectionProtocol(amp.AMP):
|
|||
that is irrelevant. If a true connection error happens, the
|
||||
portal will continuously try to reconnect, showing the problem
|
||||
that way.
|
||||
|
||||
"""
|
||||
# print("ConnectionLost: {}: {}".format(self, reason))
|
||||
try:
|
||||
|
|
@ -422,20 +430,20 @@ class AMPMultiConnectionProtocol(amp.AMP):
|
|||
|
||||
# Error handling
|
||||
|
||||
def errback(self, e, info):
|
||||
def errback(self, err, info):
|
||||
"""
|
||||
Error callback.
|
||||
Handles errors to avoid dropping connections on server tracebacks.
|
||||
|
||||
Args:
|
||||
e (Failure): Deferred error instance.
|
||||
err (Failure): Deferred error instance.
|
||||
info (str): Error string.
|
||||
|
||||
"""
|
||||
e.trap(Exception)
|
||||
err.trap(Exception)
|
||||
_get_logger().log_err(
|
||||
"AMP Error from {info}: {trcbck} {err}".format(
|
||||
info=info, trcbck=e.getTraceback(), err=e.getErrorMessage()
|
||||
info=info, trcbck=err.getTraceback(), err=err.getErrorMessage()
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ class AMPServerFactory(protocol.ServerFactory):
|
|||
noisy = False
|
||||
|
||||
def logPrefix(self):
|
||||
"How this is named in logs"
|
||||
"""
|
||||
How this is named in logs
|
||||
|
||||
"""
|
||||
return "AMP"
|
||||
|
||||
def __init__(self, portal):
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ class GrapevineClient(WebSocketClientProtocol, Session):
|
|||
# incoming broadcast from network
|
||||
payload = data["payload"]
|
||||
|
||||
print("channels/broadcast:", payload["channel"], self.channel)
|
||||
# print("channels/broadcast:", payload["channel"], self.channel)
|
||||
if str(payload["channel"]) != self.channel:
|
||||
# only echo from channels this particular bot actually listens to
|
||||
return
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ class Portal(object):
|
|||
|
||||
Returns:
|
||||
server_twistd_cmd (list): An instruction for starting the server, to pass to Popen.
|
||||
|
||||
"""
|
||||
server_twistd_cmd = [
|
||||
"twistd",
|
||||
|
|
@ -196,7 +197,10 @@ class Portal(object):
|
|||
return server_twistd_cmd
|
||||
|
||||
def get_info_dict(self):
|
||||
"Return the Portal info, for display."
|
||||
"""
|
||||
Return the Portal info, for display.
|
||||
|
||||
"""
|
||||
return INFO_DICT
|
||||
|
||||
def shutdown(self, _reactor_stopping=False, _stop_server=False):
|
||||
|
|
@ -354,7 +358,8 @@ if SSH_ENABLED:
|
|||
for port in SSH_PORTS:
|
||||
pstring = "%s:%s" % (ifacestr, port)
|
||||
factory = ssh.makeFactory(
|
||||
{"protocolFactory": _ssh_protocol, "protocolArgs": (), "sessions": PORTAL_SESSIONS,}
|
||||
{"protocolFactory": _ssh_protocol,
|
||||
"protocolArgs": (), "sessions": PORTAL_SESSIONS}
|
||||
)
|
||||
factory.noisy = False
|
||||
ssh_service = internet.TCPServer(port, factory, interface=interface)
|
||||
|
|
@ -390,7 +395,7 @@ if WEBSERVER_ENABLED:
|
|||
if WEBSOCKET_CLIENT_ENABLED and not websocket_started:
|
||||
# start websocket client port for the webclient
|
||||
# we only support one websocket client
|
||||
from evennia.server.portal import webclient
|
||||
from evennia.server.portal import webclient # noqa
|
||||
from autobahn.twisted.websocket import WebSocketServerFactory
|
||||
|
||||
w_interface = WEBSOCKET_CLIENT_INTERFACE
|
||||
|
|
@ -417,10 +422,13 @@ if WEBSERVER_ENABLED:
|
|||
if WEB_PLUGINS_MODULE:
|
||||
try:
|
||||
web_root = WEB_PLUGINS_MODULE.at_webproxy_root_creation(web_root)
|
||||
except Exception as e: # Legacy user has not added an at_webproxy_root_creation function in existing web plugins file
|
||||
except Exception:
|
||||
# Legacy user has not added an at_webproxy_root_creation function in existing
|
||||
# web plugins file
|
||||
INFO_DICT["errors"] = (
|
||||
"WARNING: WEB_PLUGINS_MODULE is enabled but at_webproxy_root_creation() not found - "
|
||||
"copy 'evennia/game_template/server/conf/web_plugins.py to mygame/server/conf."
|
||||
"WARNING: WEB_PLUGINS_MODULE is enabled but at_webproxy_root_creation() "
|
||||
"not found copy 'evennia/game_template/server/conf/web_plugins.py to "
|
||||
"mygame/server/conf."
|
||||
)
|
||||
web_root = Website(web_root, logPath=settings.HTTP_LOG_FILE)
|
||||
web_root.is_portal = True
|
||||
|
|
@ -435,4 +443,3 @@ for plugin_module in PORTAL_SERVICES_PLUGIN_MODULES:
|
|||
# external plugin services to start
|
||||
if plugin_module:
|
||||
plugin_module.start_plugin_services(PORTAL)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""
|
||||
Sessionhandler for portal sessions
|
||||
Sessionhandler for portal sessions.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ 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
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
# module import
|
||||
_MOD_IMPORT = None
|
||||
|
|
@ -35,6 +37,8 @@ DUMMYSESSION = namedtuple("DummySession", ["sessid"])(0)
|
|||
# Portal-SessionHandler class
|
||||
# -------------------------------------------------------------
|
||||
|
||||
DOS_PROTECTION_MSG = _("{servername} DoS protection is active. You are queued to connect in {num} seconds ...")
|
||||
|
||||
|
||||
class PortalSessionHandler(SessionHandler):
|
||||
"""
|
||||
|
|
@ -111,16 +115,12 @@ class PortalSessionHandler(SessionHandler):
|
|||
_CONNECTION_QUEUE.appendleft(session)
|
||||
if len(_CONNECTION_QUEUE) > 1:
|
||||
session.data_out(
|
||||
text=[
|
||||
[
|
||||
"%s DoS protection is active. You are queued to connect in %g seconds ..."
|
||||
% (
|
||||
settings.SERVERNAME,
|
||||
len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS,
|
||||
)
|
||||
],
|
||||
text=(
|
||||
(DOS_PROTECTION_MSG.format(
|
||||
servername=settings.SERVERNAME,
|
||||
num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS),),
|
||||
{},
|
||||
]
|
||||
)
|
||||
)
|
||||
now = time.time()
|
||||
if (
|
||||
|
|
@ -220,6 +220,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
def disconnect_all(self):
|
||||
"""
|
||||
Disconnect all sessions, informing the Server.
|
||||
|
||||
"""
|
||||
|
||||
def _callback(result, sessionhandler):
|
||||
|
|
@ -478,5 +479,4 @@ class PortalSessionHandler(SessionHandler):
|
|||
|
||||
|
||||
_PORTAL_SESSION_HANDLER_CLASS = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS)
|
||||
|
||||
PORTAL_SESSIONS = _PORTAL_SESSION_HANDLER_CLASS()
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ class RSSBotFactory(object):
|
|||
def start(self):
|
||||
"""
|
||||
Called by portalsessionhandler. Starts the bot.
|
||||
|
||||
"""
|
||||
|
||||
def errback(fail):
|
||||
|
|
|
|||
|
|
@ -61,24 +61,25 @@ CTRL_D = "\x04"
|
|||
CTRL_BACKSLASH = "\x1c"
|
||||
CTRL_L = "\x0c"
|
||||
|
||||
_NO_AUTOGEN = """
|
||||
_NO_AUTOGEN = f"""
|
||||
Evennia could not generate SSH private- and public keys ({{err}})
|
||||
Using conch default keys instead.
|
||||
|
||||
If this error persists, create the keys manually (using the tools for your OS)
|
||||
and put them here:
|
||||
{}
|
||||
{}
|
||||
""".format(
|
||||
_PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE
|
||||
)
|
||||
{_PRIVATE_KEY_FILE}
|
||||
{_PUBLIC_KEY_FILE}
|
||||
"""
|
||||
|
||||
_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
||||
|
||||
|
||||
# not used atm
|
||||
class SSHServerFactory(protocol.ServerFactory):
|
||||
"This is only to name this better in logs"
|
||||
"""
|
||||
This is only to name this better in logs
|
||||
|
||||
"""
|
||||
noisy = False
|
||||
|
||||
def logPrefix(self):
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class SSLProtocol(_TELNET_PROTOCOL_CLASS):
|
|||
"""
|
||||
Communication is the same as telnet, except data transfer
|
||||
is done with encryption.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -62,6 +63,7 @@ def verify_SSL_key_and_cert(keyfile, certfile):
|
|||
This function looks for RSA key and certificate in the current
|
||||
directory. If files ssl.key and ssl.cert does not exist, they
|
||||
are created.
|
||||
|
||||
"""
|
||||
|
||||
if not (os.path.exists(keyfile) and os.path.exists(certfile)):
|
||||
|
|
@ -74,10 +76,11 @@ def verify_SSL_key_and_cert(keyfile, certfile):
|
|||
|
||||
try:
|
||||
# create the RSA key and store it.
|
||||
KEY_LENGTH = 1024
|
||||
rsaKey = Key(RSA.generate(KEY_LENGTH))
|
||||
keyString = rsaKey.toString(type="OPENSSH")
|
||||
file(keyfile, "w+b").write(keyString)
|
||||
KEY_LENGTH = 2048
|
||||
rsa_key = Key(RSA.generate(KEY_LENGTH))
|
||||
key_string = rsa_key.toString(type="OPENSSH")
|
||||
with open(keyfile, "w+b") as fil:
|
||||
fil.write(key_string)
|
||||
except Exception as err:
|
||||
print(NO_AUTOGEN.format(err=err, keyfile=keyfile))
|
||||
sys.exit(5)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,10 @@ _BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
|||
|
||||
|
||||
class TelnetServerFactory(protocol.ServerFactory):
|
||||
"This is only to name this better in logs"
|
||||
"""
|
||||
This exists only to name this better in logs.
|
||||
|
||||
"""
|
||||
noisy = False
|
||||
|
||||
def logPrefix(self):
|
||||
|
|
@ -71,6 +74,7 @@ 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
|
||||
communication between game and player goes through here.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -81,6 +85,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
"""
|
||||
Unused by default, but a good place to put debug printouts
|
||||
of incoming data.
|
||||
|
||||
"""
|
||||
# print(f"telnet dataReceived: {data}")
|
||||
try:
|
||||
|
|
@ -145,11 +150,15 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
Client refuses do(linemode). This is common for MUD-specific
|
||||
clients, but we must ask for the sake of raw telnet. We ignore
|
||||
this error.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def _send_nop_keepalive(self):
|
||||
"""Send NOP keepalive unless flag is set"""
|
||||
"""
|
||||
Send NOP keepalive unless flag is set
|
||||
|
||||
"""
|
||||
if self.protocol_flags.get("NOPKEEPALIVE"):
|
||||
self._write(IAC + NOP)
|
||||
|
||||
|
|
@ -158,7 +167,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
Allow to toggle the NOP keepalive for those sad clients that
|
||||
can't even handle a NOP instruction. This is turned off by the
|
||||
protocol_flag NOPKEEPALIVE (settable e.g. by the default
|
||||
`@option` command).
|
||||
`option` command).
|
||||
|
||||
"""
|
||||
if self.nop_keep_alive and self.nop_keep_alive.running:
|
||||
self.nop_keep_alive.stop()
|
||||
|
|
@ -172,6 +182,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
When all have reported, a sync with the server is performed.
|
||||
The system will force-call this sync after a small time to handle
|
||||
clients that don't reply to handshakes at all.
|
||||
|
||||
"""
|
||||
if timeout:
|
||||
if self.handshakes > 0:
|
||||
|
|
@ -186,6 +197,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
def at_login(self):
|
||||
"""
|
||||
Called when this session gets authenticated by the server.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
@ -321,7 +333,10 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
self.data_in(text=dat + b"\n")
|
||||
|
||||
def _write(self, data):
|
||||
"""hook overloading the one used in plain telnet"""
|
||||
"""
|
||||
Hook overloading the one used in plain telnet
|
||||
|
||||
"""
|
||||
data = data.replace(b"\n", b"\r\n").replace(b"\r\r\n", b"\r\n")
|
||||
super()._write(mccp_compress(self, data))
|
||||
|
||||
|
|
@ -347,7 +362,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
|
||||
def disconnect(self, reason=""):
|
||||
"""
|
||||
generic hook for the engine to call in order to
|
||||
Generic hook for the engine to call in order to
|
||||
disconnect this protocol.
|
||||
|
||||
Args:
|
||||
|
|
@ -376,6 +391,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
|
||||
Keyword Args:
|
||||
kwargs (any): Options to the protocol
|
||||
|
||||
"""
|
||||
self.sessionhandler.data_out(self, **kwargs)
|
||||
|
||||
|
|
@ -442,7 +458,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
prompt = mxp_parse(prompt)
|
||||
prompt = to_bytes(prompt, self)
|
||||
prompt = prompt.replace(IAC, IAC + IAC).replace(b"\n", b"\r\n")
|
||||
if not self.protocol_flags.get("NOPROMPTGOAHEAD",
|
||||
if not self.protocol_flags.get("NOPROMPTGOAHEAD",
|
||||
self.protocol_flags.get("NOGOAHEAD", True)):
|
||||
prompt += IAC + GA
|
||||
self.transport.write(mccp_compress(self, prompt))
|
||||
|
|
@ -488,6 +504,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS):
|
|||
def send_default(self, cmdname, *args, **kwargs):
|
||||
"""
|
||||
Send other oob data
|
||||
|
||||
"""
|
||||
if not cmdname == "options":
|
||||
self.oob.data_out(cmdname, *args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -46,32 +46,29 @@ _CERTIFICATE_ISSUER = {
|
|||
|
||||
# messages
|
||||
|
||||
NO_AUTOGEN = """
|
||||
NO_AUTOGEN = f"""
|
||||
Evennia could not auto-generate the SSL private- and public keys ({{err}}).
|
||||
If this error persists, create them manually (using the tools for your OS). The files
|
||||
should be placed and named like this:
|
||||
{}
|
||||
{}
|
||||
""".format(
|
||||
_PRIVATE_KEY_FILE, _PUBLIC_KEY_FILE
|
||||
)
|
||||
{_PRIVATE_KEY_FILE}
|
||||
{_PUBLIC_KEY_FILE}
|
||||
"""
|
||||
|
||||
NO_AUTOCERT = """
|
||||
Evennia's could not auto-generate the SSL certificate ({{err}}).
|
||||
The private key already exists here:
|
||||
{}
|
||||
{_PRIVATE_KEY_FILE}
|
||||
If this error persists, create the certificate manually (using the private key and
|
||||
the tools for your OS). The file should be placed and named like this:
|
||||
{}
|
||||
""".format(
|
||||
_PRIVATE_KEY_FILE, _CERTIFICATE_FILE
|
||||
)
|
||||
{_CERTIFICATE_FILE}
|
||||
"""
|
||||
|
||||
|
||||
class SSLProtocol(TelnetProtocol):
|
||||
"""
|
||||
Communication is the same as telnet, except data transfer
|
||||
is done with encryption set up by the portal at start time.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ _BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
|||
class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS):
|
||||
"""
|
||||
Implements the server-side of the Websocket connection.
|
||||
|
||||
"""
|
||||
|
||||
# nonce value, used to prevent the webclient from erasing the
|
||||
|
|
@ -155,7 +156,7 @@ class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS):
|
|||
# in case anyone wants to expose this functionality later.
|
||||
#
|
||||
# sendClose() under autobahn/websocket/interfaces.py
|
||||
ret = self.sendClose(CLOSE_NORMAL, reason)
|
||||
self.sendClose(CLOSE_NORMAL, reason)
|
||||
|
||||
def onClose(self, wasClean, code=None, reason=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ http://localhost:4001/webclient.)
|
|||
The WebClient resource in this module will
|
||||
handle these requests and act as a gateway
|
||||
to sessions connected over the webclient.
|
||||
|
||||
"""
|
||||
import json
|
||||
import re
|
||||
|
|
@ -27,7 +28,7 @@ from django.utils.functional import Promise
|
|||
from django.conf import settings
|
||||
from evennia.utils.ansi import parse_ansi
|
||||
from evennia.utils import utils
|
||||
from evennia.utils.utils import to_bytes, to_str
|
||||
from evennia.utils.utils import to_bytes
|
||||
from evennia.utils.text2html import parse_html
|
||||
from evennia.server import session
|
||||
|
||||
|
|
@ -223,10 +224,13 @@ class AjaxWebClient(resource.Resource):
|
|||
return jsonify({"msg": host_string, "csessid": csessid})
|
||||
|
||||
def mode_keepalive(self, request):
|
||||
|
||||
"""
|
||||
This is called by render_POST when the
|
||||
client is replying to the keepalive.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
|
||||
"""
|
||||
csessid = self.get_client_sessid(request)
|
||||
self.last_alive[csessid] = (time.time(), False)
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ class Evennia:
|
|||
The main Evennia server handler. This object sets up the database and
|
||||
tracks and interlinks all the twisted network services that make up
|
||||
evennia.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, application):
|
||||
|
|
@ -243,6 +244,7 @@ class Evennia:
|
|||
This allows for changing default cmdset locations and default
|
||||
typeclasses in the settings file and have them auto-update all
|
||||
already existing objects.
|
||||
|
||||
"""
|
||||
global INFO_DICT
|
||||
|
||||
|
|
@ -471,7 +473,10 @@ class Evennia:
|
|||
ServerConfig.objects.conf("runtime", _GAMETIME_MODULE.runtime())
|
||||
|
||||
def get_info_dict(self):
|
||||
"Return the server info, for display."
|
||||
"""
|
||||
Return the server info, for display.
|
||||
|
||||
"""
|
||||
return INFO_DICT
|
||||
|
||||
# server start/stop hooks
|
||||
|
|
@ -480,6 +485,7 @@ class Evennia:
|
|||
"""
|
||||
This is called every time the server starts up, regardless of
|
||||
how it was shut down.
|
||||
|
||||
"""
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
SERVER_STARTSTOP_MODULE.at_server_start()
|
||||
|
|
@ -488,6 +494,7 @@ class Evennia:
|
|||
"""
|
||||
This is called just before a server is shut down, regardless
|
||||
of it is fore a reload, reset or shutdown.
|
||||
|
||||
"""
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
SERVER_STARTSTOP_MODULE.at_server_stop()
|
||||
|
|
@ -495,6 +502,7 @@ class Evennia:
|
|||
def at_server_reload_start(self):
|
||||
"""
|
||||
This is called only when server starts back up after a reload.
|
||||
|
||||
"""
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
SERVER_STARTSTOP_MODULE.at_server_reload_start()
|
||||
|
|
@ -505,7 +513,7 @@ class Evennia:
|
|||
after reconnecting.
|
||||
|
||||
Args:
|
||||
mode (str): One of reload, reset or shutdown.
|
||||
mode (str): One of 'reload', 'reset' or 'shutdown'.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -555,6 +563,7 @@ class Evennia:
|
|||
def at_server_reload_stop(self):
|
||||
"""
|
||||
This is called only time the server stops before a reload.
|
||||
|
||||
"""
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
SERVER_STARTSTOP_MODULE.at_server_reload_stop()
|
||||
|
|
@ -563,6 +572,7 @@ class Evennia:
|
|||
"""
|
||||
This is called only when the server starts "cold", i.e. after a
|
||||
shutdown or a reset.
|
||||
|
||||
"""
|
||||
# We need to do this just in case the server was killed in a way where
|
||||
# the normal cleanup operations did not have time to run.
|
||||
|
|
@ -590,6 +600,7 @@ class Evennia:
|
|||
def at_server_cold_stop(self):
|
||||
"""
|
||||
This is called only when the server goes down due to a shutdown or reset.
|
||||
|
||||
"""
|
||||
if SERVER_STARTSTOP_MODULE:
|
||||
SERVER_STARTSTOP_MODULE.at_server_cold_stop()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from evennia.comms.models import ChannelDB
|
|||
from evennia.utils import logger
|
||||
from evennia.utils.utils import make_iter, lazy_property, class_from_module
|
||||
from evennia.commands.cmdsethandler import CmdSetHandler
|
||||
from evennia.server.session import Session
|
||||
from evennia.scripts.monitorhandler import MONITOR_HANDLER
|
||||
from evennia.typeclasses.attributes import AttributeHandler, InMemoryAttributeBackend, DbHolder
|
||||
|
||||
|
|
@ -22,9 +21,6 @@ _SA = object.__setattr__
|
|||
_ObjectDB = None
|
||||
_ANSI = None
|
||||
|
||||
# i18n
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
||||
|
||||
|
||||
|
|
@ -45,7 +41,10 @@ class ServerSession(_BASE_SESSION_CLASS):
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initiate to avoid AttributeErrors down the line"""
|
||||
"""
|
||||
Initiate to avoid AttributeErrors down the line
|
||||
|
||||
"""
|
||||
self.puppet = None
|
||||
self.account = None
|
||||
self.cmdset_storage_string = ""
|
||||
|
|
@ -321,7 +320,10 @@ class ServerSession(_BASE_SESSION_CLASS):
|
|||
self.sessionhandler.data_in(session or self, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Handle session comparisons"""
|
||||
"""
|
||||
Handle session comparisons
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.address == other.address
|
||||
except AttributeError:
|
||||
|
|
@ -368,6 +370,7 @@ class ServerSession(_BASE_SESSION_CLASS):
|
|||
def at_cmdset_get(self, **kwargs):
|
||||
"""
|
||||
A dummy hook all objects with cmdsets need to have
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
@ -414,7 +417,10 @@ class ServerSession(_BASE_SESSION_CLASS):
|
|||
|
||||
# @ndb.deleter
|
||||
def ndb_del(self):
|
||||
"""Stop accidental deletion."""
|
||||
"""
|
||||
Stop accidental deletion.
|
||||
|
||||
"""
|
||||
raise Exception("Cannot delete the ndb object!")
|
||||
|
||||
ndb = property(ndb_get, ndb_set, ndb_del)
|
||||
|
|
@ -423,5 +429,8 @@ class ServerSession(_BASE_SESSION_CLASS):
|
|||
# Mock access method for the session (there is no lock info
|
||||
# at this stage, so we just present a uniform API)
|
||||
def access(self, *args, **kwargs):
|
||||
"""Dummy method to mimic the logged-in API."""
|
||||
"""
|
||||
Dummy method to mimic the logged-in API.
|
||||
|
||||
"""
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ from django.conf import settings
|
|||
from evennia.commands.cmdhandler import CMD_LOGINSTART
|
||||
from evennia.utils.logger import log_trace
|
||||
from evennia.utils.utils import (
|
||||
variable_from_module, class_from_module,
|
||||
is_iter,
|
||||
make_iter,
|
||||
delay,
|
||||
|
|
@ -29,6 +28,7 @@ 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 codecs import decode as codecs_decode
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ _ServerConfig = None
|
|||
_ScriptDB = None
|
||||
_OOB_HANDLER = None
|
||||
|
||||
_ERR_BAD_UTF8 = "Your client sent an incorrect UTF-8 sequence."
|
||||
_ERR_BAD_UTF8 = _("Your client sent an incorrect UTF-8 sequence.")
|
||||
|
||||
|
||||
class DummySession(object):
|
||||
|
|
@ -48,9 +48,6 @@ class DummySession(object):
|
|||
|
||||
DUMMYSESSION = DummySession()
|
||||
|
||||
# i18n
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
_SERVERNAME = settings.SERVERNAME
|
||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
|
|
@ -61,7 +58,6 @@ _MODEL_MAP = None
|
|||
_FUNCPARSER = None
|
||||
|
||||
|
||||
|
||||
# input handlers
|
||||
|
||||
_INPUT_FUNCS = {}
|
||||
|
|
@ -103,24 +99,36 @@ class SessionHandler(dict):
|
|||
"""
|
||||
|
||||
def __getitem__(self, key):
|
||||
"Clean out None-sessions automatically."
|
||||
"""
|
||||
Clean out None-sessions automatically.
|
||||
|
||||
"""
|
||||
if None in self:
|
||||
del self[None]
|
||||
return super().__getitem__(key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"Clean out None-sessions automatically."
|
||||
"""
|
||||
Clean out None-sessions automatically.
|
||||
|
||||
"""
|
||||
if None in self:
|
||||
del self[None]
|
||||
return super().get(key, default)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"Don't assign None sessions"
|
||||
"""
|
||||
Don't assign None sessions"
|
||||
|
||||
"""
|
||||
if key is not None:
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def __contains__(self, key):
|
||||
"None-keys are not accepted."
|
||||
"""
|
||||
None-keys are not accepted.
|
||||
|
||||
"""
|
||||
return False if key is None else super().__contains__(key)
|
||||
|
||||
def get_sessions(self, include_unloggedin=False):
|
||||
|
|
@ -158,9 +166,8 @@ class SessionHandler(dict):
|
|||
|
||||
Args:
|
||||
session (Session): The relevant session instance.
|
||||
kwargs (dict) Each keyword represents a send-instruction, with the keyword itself being the name
|
||||
of the instruction (like "text"). Suitable values for each
|
||||
keyword are:
|
||||
kwargs (dict) Each keyword represents a send-instruction, with the keyword itself being
|
||||
the name of the instruction (like "text"). Suitable values for each keyword are:
|
||||
- arg -> [[arg], {}]
|
||||
- [args] -> [[args], {}]
|
||||
- {kwargs} -> [[], {kwargs}]
|
||||
|
|
@ -177,7 +184,8 @@ class SessionHandler(dict):
|
|||
global _FUNCPARSER
|
||||
if not _FUNCPARSER:
|
||||
from evennia.utils.funcparser import FuncParser
|
||||
_FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES, raise_errors=True)
|
||||
_FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES,
|
||||
raise_errors=True)
|
||||
|
||||
options = kwargs.pop("options", None) or {}
|
||||
raw = options.get("raw", False)
|
||||
|
|
@ -199,7 +207,10 @@ class SessionHandler(dict):
|
|||
return data
|
||||
|
||||
def _validate(data):
|
||||
"Helper function to convert data to AMP-safe (picketable) values"
|
||||
"""
|
||||
Helper function to convert data to AMP-safe (picketable) values"
|
||||
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
newdict = {}
|
||||
for key, part in data.items():
|
||||
|
|
@ -210,7 +221,8 @@ class SessionHandler(dict):
|
|||
elif isinstance(data, (str, bytes)):
|
||||
data = _utf8(data)
|
||||
|
||||
if _FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED and not raw and isinstance(self, ServerSessionHandler):
|
||||
if (_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
|
||||
and not raw and isinstance(self, ServerSessionHandler)):
|
||||
# only apply funcparser on the outgoing path (sessionhandler->)
|
||||
# data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session)
|
||||
data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session)
|
||||
|
|
@ -261,14 +273,11 @@ class SessionHandler(dict):
|
|||
|
||||
class ServerSessionHandler(SessionHandler):
|
||||
"""
|
||||
This object holds the stack of sessions active in the game at
|
||||
any time.
|
||||
This object holds the stack of sessions active in the game at any time.
|
||||
|
||||
A session register with the handler in two steps, first by
|
||||
registering itself with the connect() method. This indicates an
|
||||
non-authenticated session. Whenever the session is authenticated
|
||||
the session together with the related account is sent to the login()
|
||||
method.
|
||||
A session register with the handler in two steps, first by registering itself with the connect()
|
||||
method. This indicates an non-authenticated session. Whenever the session is authenticated the
|
||||
session together with the related account is sent to the login() method.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -468,9 +477,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
|
||||
def login(self, session, account, force=False, testmode=False):
|
||||
"""
|
||||
Log in the previously unloggedin session and the account we by
|
||||
now should know is connected to it. After this point we assume
|
||||
the session to be logged in one way or another.
|
||||
Log in the previously unloggedin session and the account we by now should know is connected
|
||||
to it. After this point we assume the session to be logged in one way or another.
|
||||
|
||||
Args:
|
||||
session (Session): The Session to authenticate.
|
||||
|
|
@ -627,7 +635,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
# mean connecting from the same host would not catch duplicates
|
||||
sid = id(curr_session)
|
||||
doublet_sessions = [
|
||||
sess for sess in self.values() if sess.logged_in and sess.uid == uid and id(sess) != sid
|
||||
sess for sess in self.values()
|
||||
if sess.logged_in and sess.uid == uid and id(sess) != sid
|
||||
]
|
||||
|
||||
for session in doublet_sessions:
|
||||
|
|
@ -737,8 +746,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
puppet (Object): Object puppeted
|
||||
|
||||
Returns.
|
||||
sessions (Session or list): Can be more than one of Object is controlled by
|
||||
more than one Session (MULTISESSION_MODE > 1).
|
||||
sessions (Session or list): Can be more than one of Object is controlled by more than
|
||||
one Session (MULTISESSION_MODE > 1).
|
||||
|
||||
"""
|
||||
sessions = puppet.sessid.get()
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ from django.core.cache import caches
|
|||
from collections import deque
|
||||
from evennia.utils import logger
|
||||
import time
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
class Throttle(object):
|
||||
class Throttle:
|
||||
"""
|
||||
Keeps a running count of failed actions per IP address.
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ class Throttle(object):
|
|||
caches for automatic key eviction and persistence configurability.
|
||||
"""
|
||||
|
||||
error_msg = "Too many failed attempts; you must wait a few minutes before trying again."
|
||||
error_msg = _("Too many failed attempts; you must wait a few minutes before trying again.")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
|
|
@ -34,7 +35,7 @@ class Throttle(object):
|
|||
"""
|
||||
try:
|
||||
self.storage = caches['throttle']
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.log_trace("Throttle: Errors encountered; using default cache.")
|
||||
self.storage = caches['default']
|
||||
|
||||
|
|
@ -123,7 +124,10 @@ class Throttle(object):
|
|||
|
||||
# If this makes it engage, log a single activation event
|
||||
if not previously_throttled and currently_throttled:
|
||||
logger.log_sec(f"Throttle Activated: {failmsg} (IP: {ip}, {self.limit} hits in {self.timeout} seconds.)")
|
||||
logger.log_sec(
|
||||
f"Throttle Activated: {failmsg} (IP: {ip}, "
|
||||
f"{self.limit} hits in {self.timeout} seconds.)"
|
||||
)
|
||||
|
||||
self.record_ip(ip)
|
||||
|
||||
|
|
@ -136,14 +140,15 @@ class Throttle(object):
|
|||
|
||||
"""
|
||||
exists = self.get(ip)
|
||||
if not exists: return False
|
||||
if not exists:
|
||||
return False
|
||||
|
||||
cache_key = self.get_cache_key(ip)
|
||||
self.storage.delete(cache_key)
|
||||
self.unrecord_ip(ip)
|
||||
|
||||
# Return True if NOT exists
|
||||
return ~bool(self.get(ip))
|
||||
return not bool(self.get(ip))
|
||||
|
||||
def record_ip(self, ip, *args, **kwargs):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue