mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 05:16:31 +01:00
Made portalsessionhandler manage command rate limitations directly, using a cmd/s average over 200 commands.
This commit is contained in:
parent
e201cda2c3
commit
9793c57dd4
3 changed files with 40 additions and 24 deletions
|
|
@ -1,14 +1,18 @@
|
|||
"""
|
||||
Sessionhandler for portal sessions
|
||||
"""
|
||||
import time
|
||||
from twisted.internet import reactor
|
||||
from collections import deque
|
||||
from time import time
|
||||
from twisted.internet import reactor, task
|
||||
from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC
|
||||
|
||||
_CONNECTION_RATE = 5.0
|
||||
_MIN_TIME_BETWEEN_CONNECTS = 1.0 / _CONNECTION_RATE
|
||||
_MOD_IMPORT = None
|
||||
|
||||
_MAX_CMD_RATE = 150.0
|
||||
_ERROR_COMMAND_OVERFLOW = "You entered commands too fast. Wait a moment and try again."
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Portal-SessionHandler class
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -31,9 +35,17 @@ class PortalSessionHandler(SessionHandler):
|
|||
self.portal = None
|
||||
self.sessions = {}
|
||||
self.latest_sessid = 0
|
||||
self.uptime = time.time()
|
||||
self.uptime = time()
|
||||
self.connection_time = 0
|
||||
self.time_last_connect = time.time()
|
||||
self.time_last_connect = time()
|
||||
self.cmd_last = time()
|
||||
self.cmd_rate_history = deque([], 200)
|
||||
self.cmd_rate = 0.0
|
||||
self.overflows = 0
|
||||
task.LoopingCall(self._report, interval=30)
|
||||
|
||||
def _report(self):
|
||||
print " INFO: cmd rate: %s, overflows: %s" % (sum(self.cmd_rate_history) / 200.0, self.overflows)
|
||||
|
||||
def at_server_connection(self):
|
||||
"""
|
||||
|
|
@ -41,7 +53,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
Server. At this point, the AMP connection is already
|
||||
established.
|
||||
"""
|
||||
self.connection_time = time.time()
|
||||
self.connection_time = time()
|
||||
|
||||
def connect(self, session):
|
||||
"""
|
||||
|
|
@ -61,7 +73,7 @@ class PortalSessionHandler(SessionHandler):
|
|||
self.latest_sessid += 1
|
||||
session.sessid = self.latest_sessid
|
||||
|
||||
now = time.time()
|
||||
now = time()
|
||||
current_rate = 1.0 / (now - self.time_last_connect)
|
||||
|
||||
if current_rate > _CONNECTION_RATE:
|
||||
|
|
@ -290,6 +302,28 @@ class PortalSessionHandler(SessionHandler):
|
|||
in from the protocol to the server. data is
|
||||
serialized before passed on.
|
||||
"""
|
||||
|
||||
now = time()
|
||||
self.cmd_rate_history.append(1.0 / (now - self.cmd_last))
|
||||
|
||||
if session.logged_in:
|
||||
# command flood protection
|
||||
self.cmd_rate = sum(self.cmd_rate_history) / 200.0
|
||||
if self.cmd_rate > _MAX_CMD_RATE:
|
||||
max_rate_per_session = _MAX_CMD_RATE / len(self.sessions)
|
||||
session_rate = 1.0 / (now - session.cmd_last)
|
||||
session.cmd_last = now
|
||||
if session_rate > max_rate_per_session:
|
||||
self.overflows += 1
|
||||
session.data_out(text=_ERROR_COMMAND_OVERFLOW)
|
||||
if 100 % self.overflows == 0:
|
||||
print "CMD OVERFLOW %s: %s (%s/%s, %s/%s)" % (session.sessid, text,
|
||||
self.cmd_rate, _MAX_CMD_RATE,
|
||||
session_rate, max_rate_per_session)
|
||||
return
|
||||
else:
|
||||
session.cmd_last = now
|
||||
|
||||
self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid,
|
||||
msg=text,
|
||||
data=kwargs)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ class ServerSession(Session):
|
|||
self.player = None
|
||||
self.cmdset_storage_string = ""
|
||||
self.cmdset = CmdSetHandler(self, True)
|
||||
self.cmd_per_second = 0.0
|
||||
|
||||
def __cmdset_storage_get(self):
|
||||
return [path.strip() for path in self.cmdset_storage_string.split(',')]
|
||||
|
|
@ -200,10 +199,6 @@ class ServerSession(Session):
|
|||
oobhandler at this point.
|
||||
|
||||
"""
|
||||
now = time()
|
||||
self.cmd_per_second = 1.0 / (now - self.cmd_last)
|
||||
self.cmd_last = now
|
||||
|
||||
#explicitly check for None since text can be an empty string, which is
|
||||
#also valid
|
||||
if text is not None:
|
||||
|
|
|
|||
|
|
@ -136,8 +136,6 @@ class ServerSessionHandler(SessionHandler):
|
|||
self.sessions = {}
|
||||
self.server = None
|
||||
self.server_data = {"servername": _SERVERNAME}
|
||||
self.cmd_last = time()
|
||||
self.cmd_per_second = 0.0
|
||||
|
||||
def portal_connect(self, portalsession):
|
||||
"""
|
||||
|
|
@ -500,17 +498,6 @@ class ServerSessionHandler(SessionHandler):
|
|||
"""
|
||||
session = self.sessions.get(sessid, None)
|
||||
if session:
|
||||
|
||||
now = time()
|
||||
self.cmd_per_second = 1.0 / (now - self.cmd_last)
|
||||
self.cmd_last = now
|
||||
|
||||
if self.cmd_per_second > _MAX_SERVER_COMMANDS_PER_SECOND:
|
||||
if session.cmd_per_second > _MAX_SESSION_COMMANDS_PER_SECOND:
|
||||
session.data.out(text=_ERROR_COMMAND_OVERFLOW)
|
||||
logger.log_infomsg("overflow kicked in for session %s: %s" % (session.sessid, text))
|
||||
return
|
||||
|
||||
text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding)
|
||||
if "oob" in kwargs:
|
||||
# incoming data is always on the form (cmdname, args, kwargs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue