I18n string cleanup and refactoring

This commit is contained in:
Griatch 2021-05-26 21:55:05 +02:00
parent 59dd0b007a
commit 7ff8cbb341
62 changed files with 890 additions and 738 deletions

View file

@ -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

View file

@ -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()
)
)

View file

@ -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):

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -145,6 +145,7 @@ class RSSBotFactory(object):
def start(self):
"""
Called by portalsessionhandler. Starts the bot.
"""
def errback(fail):

View file

@ -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):

View file

@ -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)

View file

@ -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)

View file

@ -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):

View file

@ -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):
"""

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -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()

View file

@ -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):
"""