mirror of
https://github.com/evennia/evennia.git
synced 2026-03-20 14:56:30 +01:00
Parallel start/stop/reload systems, for testing
This commit is contained in:
parent
ff887a07ab
commit
5741eef9bc
5 changed files with 109 additions and 39 deletions
|
|
@ -58,7 +58,7 @@ class CmdReload(COMMAND_DEFAULT_CLASS):
|
|||
if self.args:
|
||||
reason = "(Reason: %s) " % self.args.rstrip(".")
|
||||
SESSIONS.announce_all(" Server restart initiated %s..." % reason)
|
||||
SESSIONS.server.shutdown(mode='reload')
|
||||
SESSIONS.portal_restart_server()
|
||||
|
||||
|
||||
class CmdReset(COMMAND_DEFAULT_CLASS):
|
||||
|
|
@ -91,7 +91,7 @@ class CmdReset(COMMAND_DEFAULT_CLASS):
|
|||
Reload the system.
|
||||
"""
|
||||
SESSIONS.announce_all(" Server resetting/restarting ...")
|
||||
SESSIONS.server.shutdown(mode='reset')
|
||||
SESSIONS.portal_reset_server()
|
||||
|
||||
|
||||
class CmdShutdown(COMMAND_DEFAULT_CLASS):
|
||||
|
|
|
|||
|
|
@ -96,6 +96,16 @@ class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol):
|
|||
"""
|
||||
# sending AMP data
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
Called when a new connection is established.
|
||||
|
||||
"""
|
||||
super(AMPServerClientProtocol, self).connectionMade()
|
||||
# first thing we do is to request the Portal to sync all sessions
|
||||
# back with the Server side
|
||||
self.send_AdminServer2Portal(amp.DUMMYSESSION, operation=amp.PSYNC)
|
||||
|
||||
def send_MsgServer2Portal(self, session, **kwargs):
|
||||
"""
|
||||
Access method - executed on the Server for sending data
|
||||
|
|
@ -118,7 +128,7 @@ class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol):
|
|||
operation (char, optional): Identifier for the server
|
||||
operation, as defined by the global variables in
|
||||
`evennia/server/amp.py`.
|
||||
data (str or dict, optional): Data going into the adminstrative.
|
||||
kwargs (dict, optional): Data going into the adminstrative.
|
||||
|
||||
"""
|
||||
return self.data_out(amp.AdminServer2Portal, session.sessid, operation=operation, **kwargs)
|
||||
|
|
@ -180,12 +190,17 @@ class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol):
|
|||
server_sessionhandler.portal_disconnect_all()
|
||||
|
||||
elif operation == amp.PSYNC: # portal_session_sync
|
||||
# force a resync of sessions when portal reconnects to
|
||||
# server (e.g. after a server reboot) the data kwarg
|
||||
# contains a dict {sessid: {arg1:val1,...}}
|
||||
# representing the attributes to sync for each
|
||||
# session.
|
||||
# force a resync of sessions from the portal side
|
||||
server_sessionhandler.portal_sessions_sync(kwargs.get("sessiondata"))
|
||||
elif operation == amp.SRELOAD: # server reload
|
||||
# shut down in reload mode
|
||||
server_sessionhandler.server.shutdown(mode='reload')
|
||||
elif operation == amp.SRESET:
|
||||
# shut down in reset mode
|
||||
server_sessionhandler.server.shutdown(mode='reset')
|
||||
elif operation == amp.SSHUTD: # server shutdown
|
||||
# shutdown in stop mode
|
||||
server_sessionhandler.server.shutdown(mode='shutdown')
|
||||
else:
|
||||
raise Exception("operation %(op)s not recognized." % {'op': operation})
|
||||
return {}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@ SSYNC = chr(8) # server session sync
|
|||
SCONN = chr(11) # server creating new connection (for irc bots and etc)
|
||||
PCONNSYNC = chr(12) # portal post-syncing a session
|
||||
PDISCONNALL = chr(13) # portal session disconnect all
|
||||
SRELOAD = chr(14) # server reloading (have portal start a new server)
|
||||
SRELOAD = chr(14) # server shutdown in reload mode
|
||||
SSTART = chr(15) # server start (portal must already be running anyway)
|
||||
PSHUTD = chr(16) # portal (+server) shutdown
|
||||
SSHUTD = chr(17) # server-only shutdown
|
||||
SSHUTD = chr(17) # server shutdown
|
||||
PSTATUS = chr(18) # ping server or portal status
|
||||
SRESET = chr(19) # server shutdown in reset mode
|
||||
|
||||
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
|
||||
|
|
@ -271,9 +272,22 @@ class AMPMultiConnectionProtocol(amp.AMP):
|
|||
else:
|
||||
super(AMPMultiConnectionProtocol, self).dataReceived(data)
|
||||
|
||||
def makeConnection(self, transport):
|
||||
"""
|
||||
Swallow connection log message here. Copied from original
|
||||
in the amp protocol.
|
||||
|
||||
"""
|
||||
# copied from original, removing the log message
|
||||
if not self._ampInitialized:
|
||||
amp.AMP.__init__(self)
|
||||
self._transportPeer = transport.getPeer()
|
||||
self._transportHost = transport.getHost()
|
||||
amp.BinaryBoxProtocol.makeConnection(self, transport)
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
This is called when an AMP connection is (re-)established AMP calls it on both sides.
|
||||
This is called when an AMP connection is (re-)established. AMP calls it on both sides.
|
||||
|
||||
"""
|
||||
self.factory.broadcasts.append(self)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import sys
|
|||
from twisted.internet import protocol
|
||||
from evennia.server.portal import amp
|
||||
from subprocess import Popen
|
||||
from evennia.utils import logger
|
||||
|
||||
|
||||
def getenv():
|
||||
|
|
@ -69,20 +70,6 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
Protocol subclass for the AMP-server run by the Portal.
|
||||
|
||||
"""
|
||||
def connectionMade(self):
|
||||
"""
|
||||
Called when a new connection is established.
|
||||
|
||||
"""
|
||||
super(AMPServerProtocol, self).connectionMade()
|
||||
|
||||
if len(self.factory.broadcasts) < 2:
|
||||
sessdata = self.factory.portal.sessions.get_all_sync_data()
|
||||
self.send_AdminPortal2Server(amp.DUMMYSESSION,
|
||||
amp.PSYNC,
|
||||
sessiondata=sessdata)
|
||||
self.factory.portal.sessions.at_server_connection()
|
||||
|
||||
def start_server(self, server_twistd_cmd):
|
||||
"""
|
||||
(Re-)Launch the Evennia server.
|
||||
|
|
@ -92,10 +79,29 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
to pass to POpen to start the server.
|
||||
|
||||
"""
|
||||
# start the server
|
||||
# start the Server
|
||||
process = Popen(server_twistd_cmd, env=getenv())
|
||||
# store the pid for future reference
|
||||
self.portal.server_process_id = process.pid
|
||||
self.factory.portal.server_process_id = process.pid
|
||||
self.factory.portal.server_twistd_cmd = server_twistd_cmd
|
||||
return process.pid
|
||||
|
||||
def stop_server(self, mode='reload'):
|
||||
"""
|
||||
Shut down server in one or more modes.
|
||||
|
||||
Args:
|
||||
mode (str): One of 'shutdown', 'reload' or 'reset'.
|
||||
|
||||
"""
|
||||
if mode == 'reload':
|
||||
self.send_AdminPortal2Server(amp.DUMMYSESSION, amp.SRELOAD)
|
||||
return self.start_server(self.factory.portal.server_twistd_cmd)
|
||||
if mode == 'reset':
|
||||
self.send_AdminPortal2Server(amp.DUMMYSESSION, amp.SRESET)
|
||||
return self.start_server(self.factory.portal.server_twistd_cmd)
|
||||
if mode == 'shutdown':
|
||||
self.send_AdminPortal2Server(amp.DUMMYSESSION, amp.SSHUTD)
|
||||
|
||||
# sending amp data
|
||||
|
||||
|
|
@ -173,28 +179,44 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
launcher. It can obviously only accessed when the Portal is already up and running.
|
||||
|
||||
"""
|
||||
def _retval(success, txt):
|
||||
return {"result": amp.dumps((success, txt))}
|
||||
|
||||
server_connected = any(1 for prtcl in self.factory.broadcasts
|
||||
if prtcl is not self and prtcl.transport.connected)
|
||||
server_pid = self.factory.portal.server_process_id
|
||||
|
||||
print("AMP SERVER operation == %s received" % (ord(operation)))
|
||||
print("AMP SERVER arguments: %s" % (amp.loads(arguments)))
|
||||
return {"result": "Received."}
|
||||
logger.log_msg("AMP SERVER operation == %s received" % (ord(operation)))
|
||||
logger.log_msg("AMP SERVER arguments: %s" % (amp.loads(arguments)))
|
||||
|
||||
if operation == amp.SSTART: # portal start
|
||||
# first, check if server is already running
|
||||
if server_connected:
|
||||
return {"result": "Server already running at PID={}"}
|
||||
return _retval(False,
|
||||
"Server already running at PID={spid}".format(spid=server_pid))
|
||||
else:
|
||||
self.start_server(amp.loads(arguments))
|
||||
return {"result": "Server started with PID {}.".format(0)} # TODO
|
||||
spid = self.start_server(amp.loads(arguments))
|
||||
return _retval(True, "Server started with PID {spid}.".format(spid=spid))
|
||||
elif operation == amp.SRELOAD: # reload server
|
||||
if server_connected:
|
||||
self.reload_server(amp.loads(arguments))
|
||||
spid = self.reload_server(amp.loads(arguments))
|
||||
return _retval(True, "Server started with PID {spid}.".format(spid=spid))
|
||||
else:
|
||||
self.start_server(amp.loads(arguments))
|
||||
spid = self.start_server(amp.loads(arguments))
|
||||
return _retval(True, "Server started with PID {spid}.".format(spid=spid))
|
||||
elif operation == amp.SRESET: # reload server
|
||||
if server_connected:
|
||||
spid = self.reload_server(amp.loads(arguments))
|
||||
return _retval(True, "Server started with PID {spid}.".format(spid=spid))
|
||||
else:
|
||||
self.start_server(amp.loads(arguments))
|
||||
spid = self.start_server(amp.loads(arguments))
|
||||
return _retval(True, "Server started with PID {spid}.".format(spid=spid))
|
||||
elif operation == amp.PSHUTD: # portal + server shutdown
|
||||
if server_connected:
|
||||
self.stop_server(amp.loads(arguments))
|
||||
self.stop_server()
|
||||
return _retval(True, "Server stopped.")
|
||||
self.factory.portal.shutdown(restart=False)
|
||||
else:
|
||||
raise Exception("operation %(op)s not recognized." % {'op': operation})
|
||||
|
|
@ -257,6 +279,14 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
|||
elif operation == amp.SRELOAD: # server reload
|
||||
self.factory.portal.server_reload(**kwargs)
|
||||
|
||||
elif operation == amp.PSYNC: # portal sync
|
||||
# Server has (re-)connected and wants the session data from portal
|
||||
sessdata = self.factory.portal.sessions.get_all_sync_data()
|
||||
self.send_AdminPortal2Server(amp.DUMMYSESSION,
|
||||
amp.PSYNC,
|
||||
sessiondata=sessdata)
|
||||
self.factory.portal.sessions.at_server_connection()
|
||||
|
||||
elif operation == amp.SSYNC: # server_session_sync
|
||||
# server wants to save session data to the portal,
|
||||
# maybe because it's about to shut down.
|
||||
|
|
|
|||
|
|
@ -59,7 +59,11 @@ SCONN = chr(11) # server portal connection (for bots)
|
|||
PCONNSYNC = chr(12) # portal post-syncing session
|
||||
PDISCONNALL = chr(13) # portal session discnnect all
|
||||
SRELOAD = chr(14) # server reloading (have portal start a new server)
|
||||
|
||||
SSTART = chr(15) # server start (portal must already be running anyway)
|
||||
PSHUTD = chr(16) # portal (+server) shutdown
|
||||
SSHUTD = chr(17) # server shutdown
|
||||
PSTATUS = chr(18) # ping server or portal status
|
||||
SRESET = chr(19) # server shutdown in reset mode
|
||||
|
||||
# i18n
|
||||
from django.utils.translation import ugettext as _
|
||||
|
|
@ -439,10 +443,19 @@ class ServerSessionHandler(SessionHandler):
|
|||
Called by server when reloading. We tell the portal to start a new server instance.
|
||||
|
||||
"""
|
||||
self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRELOAD)
|
||||
|
||||
def portal_reset_server(self):
|
||||
"""
|
||||
Called by server when reloading. We tell the portal to start a new server instance.
|
||||
|
||||
"""
|
||||
self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=SRESET)
|
||||
|
||||
def portal_shutdown(self):
|
||||
"""
|
||||
Called by server when shutting down the portal (usually because server is going down too).
|
||||
Called by server when it's time to shut down (the portal will shut us down and then shut
|
||||
itself down)
|
||||
|
||||
"""
|
||||
self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION,
|
||||
|
|
@ -572,8 +585,6 @@ class ServerSessionHandler(SessionHandler):
|
|||
sessiondata=session_data,
|
||||
clean=False)
|
||||
|
||||
|
||||
|
||||
def disconnect_all_sessions(self, reason="You have been disconnected."):
|
||||
"""
|
||||
Cleanly disconnect all of the connected sessions.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue