Add sessionhandler.portal_disconnect_all to remove another needless call between server and portal on logout. This means logout from either side will clean up on the respective side and then inform the other side once, rather than triggering a return call.

This commit is contained in:
Griatch 2016-09-13 21:48:43 +02:00
parent 8eb500f8e0
commit 86c970eb62
7 changed files with 54 additions and 9 deletions

View file

@ -118,8 +118,8 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS):
announcement += "%s\n" % self.args
logger.log_info('Server shutdown by %s.' % self.caller.name)
SESSIONS.announce_all(announcement)
SESSIONS.server.shutdown(mode='shutdown')
SESSIONS.portal_shutdown()
SESSIONS.server.shutdown(mode='shutdown')
class CmdPy(COMMAND_DEFAULT_CLASS):

View file

@ -50,6 +50,7 @@ SSHUTD = chr(7) # server shutdown
SSYNC = chr(8) # server session sync
SCONN = chr(11) # server creating new connection (for irc/imc2 bots etc)
PCONNSYNC = chr(12) # portal post-syncing a session
PDISCONNALL = chr(13) # portal session disconnect all
AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed)
BATCH_RATE = 250 # max commands/sec before switching to batch-sending
@ -495,6 +496,10 @@ class AMPProtocol(amp.AMP):
session = server_sessionhandler[sessid]
server_sessionhandler.portal_disconnect(session)
elif operation == PDISCONNALL: # portal_disconnect_all
# portal orders all sessions to close
server_sessionhandler.portal_disconnect_all()
elif operation == PSYNC: # portal_session_sync
# force a resync of sessions when portal reconnects to
# server (e.g. after a server reboot) the data kwarg

View file

@ -168,8 +168,7 @@ class Portal(object):
# we get here due to us calling reactor.stop below. No need
# to do the shutdown procedure again.
return
for session in self.sessions.itervalues():
session.disconnect()
self.sessions.disconnect_all()
self.set_restart_mode(restart)
if os.name == 'nt' and os.path.exists(PORTAL_PIDFILE):
# for Windows we need to remove pid files manually

View file

@ -8,7 +8,8 @@ from time import time
from collections import deque
from twisted.internet import reactor
from django.conf import settings
from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC
from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, \
PCONNSYNC, PDISCONNALL
from evennia.utils.logger import log_trace
# module import
@ -23,6 +24,10 @@ _ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING
_CONNECTION_QUEUE = deque()
class DummySession(object):
sessid = 0
DUMMYSESSION = DummySession()
#------------------------------------------------------------
# Portal-SessionHandler class
#------------------------------------------------------------
@ -152,6 +157,10 @@ class PortalSessionHandler(SessionHandler):
Args:
session (PortalSession): Session to disconnect.
delete (bool, optional): Delete the session from
the handler. Only time to not do this is when
this is called from a loop, such as from
self.disconnect_all().
"""
global _CONNECTION_QUEUE
@ -161,7 +170,7 @@ class PortalSessionHandler(SessionHandler):
_CONNECTION_QUEUE.remove(session)
return
if session.sessid in self:
if session.sessid in self and not hasattr(self, "_disconnect_all"):
# if this was called directly from the protocol, the
# connection is already dead and we just need to cleanup
del self[session.sessid]
@ -170,6 +179,23 @@ class PortalSessionHandler(SessionHandler):
self.portal.amp_protocol.send_AdminPortal2Server(session,
operation=PDISCONN)
def disconnect_all(self):
"""
Disconnect all sessions, informing the Server.
"""
def _callback(result, sessionhandler):
# we set a watchdog to stop self.disconnect from deleting
# sessions while we are looping over them.
sessionhandler._disconnect_all = True
for session in sessionhandler.values():
session.disconnect(session)
del sessionhandler._disconnect_all
# inform Server; wait until finished sending before we continue
# removing all the sessions.
self.portal.amp_protocol.send_AdminPortal2Server(DUMMYSESSION,
operation=PDISCONNALL).addCallback(_callback, self)
def server_connect(self, protocol_path="", config=dict()):
"""
Called by server to force the initialization of a new protocol

View file

@ -506,7 +506,7 @@ if WEBSERVER_ENABLED:
# Start a django-compatible webserver.
from twisted.python import threadpool
from evennia.server.webserver import DjangoWebRoot, WSGIWebServer, NonLoggingSite
from evennia.server.webserver import DjangoWebRoot, WSGIWebServer, Website
# start a thread pool and define the root url (/) as a wsgi resource
# recognized by Django
@ -522,7 +522,7 @@ if WEBSERVER_ENABLED:
# custom overloads
web_root = WEB_PLUGINS_MODULE.at_webserver_root_creation(web_root)
web_site = NonLoggingSite(web_root, logPath=settings.HTTP_LOG_FILE)
web_site = Website(web_root, logPath=settings.HTTP_LOG_FILE)
for proxyport, serverport in WEBSERVER_PORTS:
# create the webserver (we only need the port for this)

View file

@ -54,6 +54,7 @@ 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
# i18n
from django.utils.translation import ugettext as _
@ -342,6 +343,19 @@ class ServerSessionHandler(SessionHandler):
# Portal already knows.
self.disconnect(session, reason="", sync_portal=False)
def portal_disconnect_all(self):
"""
Called from Portal when Portal is closing down. All
Sessions should die. The Portal should not be informed.
"""
# set a watchdog to avoid self.disconnect from deleting
# the session while we are looping over them
self._disconnect_all = True
for session in self.values:
session.disconnect()
del self._disconnect_all
# server-side access methods
def start_bot_session(self, protocol_path, configdict):
@ -459,7 +473,8 @@ class ServerSessionHandler(SessionHandler):
session.at_disconnect()
sessid = session.sessid
del self[sessid]
if sessid in self and not hasattr(self, "_disconnect_all"):
del self[sessid]
if sync_portal:
# inform portal that session should be closed.
self.server.amp_protocol.send_AdminServer2Portal(session,

View file

@ -140,7 +140,7 @@ class DjangoWebRoot(resource.Resource):
# Site with deactivateable logging
#
class NonLoggingSite(server.Site):
class Website(server.Site):
"""
This class will only log http requests if settings.DEBUG is True.
"""