Refactor the MAX_COMMAND_RATE throttle, related to #1556
This commit is contained in:
parent
63bf978b39
commit
9e42277fbb
1 changed files with 22 additions and 22 deletions
|
|
@ -15,12 +15,15 @@ from evennia.utils.logger import log_trace
|
||||||
# module import
|
# module import
|
||||||
_MOD_IMPORT = None
|
_MOD_IMPORT = None
|
||||||
|
|
||||||
# throttles
|
# global throttles
|
||||||
_MAX_CONNECTION_RATE = float(settings.MAX_CONNECTION_RATE)
|
_MAX_CONNECTION_RATE = float(settings.MAX_CONNECTION_RATE)
|
||||||
|
# per-session throttles
|
||||||
_MAX_COMMAND_RATE = float(settings.MAX_COMMAND_RATE)
|
_MAX_COMMAND_RATE = float(settings.MAX_COMMAND_RATE)
|
||||||
_MAX_CHAR_LIMIT = int(settings.MAX_CHAR_LIMIT)
|
_MAX_CHAR_LIMIT = int(settings.MAX_CHAR_LIMIT)
|
||||||
|
|
||||||
_MIN_TIME_BETWEEN_CONNECTS = 1.0 / float(settings.MAX_CONNECTION_RATE)
|
_MIN_TIME_BETWEEN_CONNECTS = 1.0 / float(_MAX_CONNECTION_RATE)
|
||||||
|
_MIN_TIME_BETWEEN_COMMANDS = 1.0 / float(_MAX_COMMAND_RATE)
|
||||||
|
|
||||||
_ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING
|
_ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING
|
||||||
_ERROR_MAX_CHAR = settings.MAX_CHAR_LIMIT_WARNING
|
_ERROR_MAX_CHAR = settings.MAX_CHAR_LIMIT_WARNING
|
||||||
|
|
||||||
|
|
@ -58,9 +61,6 @@ class PortalSessionHandler(SessionHandler):
|
||||||
|
|
||||||
self.connection_last = self.uptime
|
self.connection_last = self.uptime
|
||||||
self.connection_task = None
|
self.connection_task = None
|
||||||
self.command_counter = 0
|
|
||||||
self.command_counter_reset = self.uptime
|
|
||||||
self.command_overflow = False
|
|
||||||
|
|
||||||
def at_server_connection(self):
|
def at_server_connection(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -354,8 +354,6 @@ class PortalSessionHandler(SessionHandler):
|
||||||
Data is serialized before passed on.
|
Data is serialized before passed on.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# from evennia.server.profiling.timetrace import timetrace # DEBUG
|
|
||||||
# text = timetrace(text, "portalsessionhandler.data_in") # DEBUG
|
|
||||||
try:
|
try:
|
||||||
text = kwargs['text']
|
text = kwargs['text']
|
||||||
if (_MAX_CHAR_LIMIT > 0) and len(text) > _MAX_CHAR_LIMIT:
|
if (_MAX_CHAR_LIMIT > 0) and len(text) > _MAX_CHAR_LIMIT:
|
||||||
|
|
@ -367,17 +365,25 @@ class PortalSessionHandler(SessionHandler):
|
||||||
pass
|
pass
|
||||||
if session:
|
if session:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if self.command_counter > _MAX_COMMAND_RATE > 0:
|
|
||||||
# data throttle (anti DoS measure)
|
try:
|
||||||
delta_time = now - self.command_counter_reset
|
command_counter_reset = session.command_counter_reset
|
||||||
self.command_counter = 0
|
except AttributeError:
|
||||||
self.command_counter_reset = now
|
command_counter_reset = session.command_counter_reset = now
|
||||||
self.command_overflow = delta_time < 1.0
|
session.command_counter = 0
|
||||||
if self.command_overflow:
|
|
||||||
reactor.callLater(1.0, self.data_in, None)
|
# global command-rate limit
|
||||||
if self.command_overflow:
|
if max(0, now - command_counter_reset) > 1.0:
|
||||||
|
# more than a second since resetting the counter. Refresh.
|
||||||
|
session.command_counter_reset = now
|
||||||
|
session.command_counter = 0
|
||||||
|
|
||||||
|
session.command_counter += 1
|
||||||
|
|
||||||
|
if session.command_counter * _MIN_TIME_BETWEEN_COMMANDS > 1.0:
|
||||||
self.data_out(session, text=[[_ERROR_COMMAND_OVERFLOW], {}])
|
self.data_out(session, text=[[_ERROR_COMMAND_OVERFLOW], {}])
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.portal.amp_protocol:
|
if not self.portal.amp_protocol:
|
||||||
# this can happen if someone connects before AMP connection
|
# this can happen if someone connects before AMP connection
|
||||||
# was established (usually on first start)
|
# was established (usually on first start)
|
||||||
|
|
@ -388,15 +394,9 @@ class PortalSessionHandler(SessionHandler):
|
||||||
kwargs = self.clean_senddata(session, kwargs)
|
kwargs = self.clean_senddata(session, kwargs)
|
||||||
|
|
||||||
# relay data to Server
|
# relay data to Server
|
||||||
self.command_counter += 1
|
|
||||||
session.cmd_last = now
|
session.cmd_last = now
|
||||||
self.portal.amp_protocol.send_MsgPortal2Server(session,
|
self.portal.amp_protocol.send_MsgPortal2Server(session,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
else:
|
|
||||||
# called by the callLater callback
|
|
||||||
if self.command_overflow:
|
|
||||||
self.command_overflow = False
|
|
||||||
reactor.callLater(1.0, self.data_in, None)
|
|
||||||
|
|
||||||
def data_out(self, session, **kwargs):
|
def data_out(self, session, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue