Working launcher sends, no reception on server side yet
This commit is contained in:
parent
b4d2fe7284
commit
c46d181566
2 changed files with 130 additions and 37 deletions
|
|
@ -81,6 +81,8 @@ ENFORCED_SETTING = False
|
||||||
|
|
||||||
# communication constants
|
# communication constants
|
||||||
|
|
||||||
|
AMP_CONNECTION = None
|
||||||
|
|
||||||
SRELOAD = chr(14) # server reloading (have portal start a new server)
|
SRELOAD = chr(14) # server reloading (have portal start a new server)
|
||||||
SSTART = chr(15) # server start
|
SSTART = chr(15) # server start
|
||||||
PSHUTD = chr(16) # portal (+server) shutdown
|
PSHUTD = chr(16) # portal (+server) shutdown
|
||||||
|
|
@ -461,11 +463,13 @@ class MsgLauncher2Portal(amp.Command):
|
||||||
response = [('result', amp.String())]
|
response = [('result', amp.String())]
|
||||||
|
|
||||||
|
|
||||||
def send_instruction(instruction, arguments, callback, errback):
|
def send_instruction(operation, arguments, callback=None, errback=None, autostop=False):
|
||||||
"""
|
"""
|
||||||
Send instruction and handle the response.
|
Send instruction and handle the response.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
global AMP_CONNECTION
|
||||||
|
|
||||||
if None in (AMP_HOST, AMP_PORT, AMP_INTERFACE):
|
if None in (AMP_HOST, AMP_PORT, AMP_INTERFACE):
|
||||||
print(ERROR_AMP_UNCONFIGURED)
|
print(ERROR_AMP_UNCONFIGURED)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -477,36 +481,42 @@ def send_instruction(instruction, arguments, callback, errback):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _callback(result):
|
def _callback(result):
|
||||||
|
if callback:
|
||||||
callback(result)
|
callback(result)
|
||||||
prot.transport.loseConnection()
|
prot.transport.loseConnection()
|
||||||
|
if autostop:
|
||||||
reactor.stop()
|
reactor.stop()
|
||||||
|
|
||||||
def _errback(fail):
|
def _errback(fail):
|
||||||
|
if errback:
|
||||||
errback(fail)
|
errback(fail)
|
||||||
prot.transport.loseConnection()
|
prot.transport.loseConnection()
|
||||||
|
if autostop:
|
||||||
reactor.stop()
|
reactor.stop()
|
||||||
|
|
||||||
if instruction == PSTATUS:
|
if operation == PSTATUS:
|
||||||
prot.callRemote(MsgStatus, status="").addCallbacks(_callback, _errback)
|
prot.callRemote(MsgStatus, status="").addCallbacks(_callback, _errback)
|
||||||
else:
|
else:
|
||||||
|
print("callRemote MsgLauncher %s %s" % (ord(operation), arguments))
|
||||||
prot.callRemote(
|
prot.callRemote(
|
||||||
MsgLauncher2Portal,
|
MsgLauncher2Portal,
|
||||||
instruction=instruction,
|
operation=operation,
|
||||||
arguments=pickle.dumps(arguments, pickle.HIGHEST_PROTOCOL).addCallbacks(
|
arguments=pickle.dumps(arguments, pickle.HIGHEST_PROTOCOL)).addCallbacks(
|
||||||
_callback, _errback))
|
_callback, _errback)
|
||||||
|
|
||||||
def _on_connect_fail(fail):
|
def _on_connect_fail(fail):
|
||||||
"This is called if portal is not reachable."
|
"This is called if portal is not reachable."
|
||||||
errback(fail)
|
errback(fail)
|
||||||
|
if autostop:
|
||||||
reactor.stop()
|
reactor.stop()
|
||||||
|
|
||||||
point = endpoints.TCP4ClientEndpoint(reactor, AMP_HOST, AMP_PORT)
|
point = endpoints.TCP4ClientEndpoint(reactor, AMP_HOST, AMP_PORT)
|
||||||
deferred = endpoints.connectProtocol(point, amp.AMP())
|
deferred = endpoints.connectProtocol(point, amp.AMP())
|
||||||
deferred.addCallbacks(_on_connect, _on_connect_fail)
|
deferred.addCallbacks(_on_connect, _on_connect_fail)
|
||||||
reactor.run()
|
return deferred
|
||||||
|
|
||||||
|
|
||||||
def send_status():
|
def send_status(repeat=False):
|
||||||
"""
|
"""
|
||||||
Send ping to portal
|
Send ping to portal
|
||||||
|
|
||||||
|
|
@ -519,24 +529,70 @@ def send_status():
|
||||||
pstatus, sstatus = "NOT RUNNING", "NOT RUNNING"
|
pstatus, sstatus = "NOT RUNNING", "NOT RUNNING"
|
||||||
print("Portal: {}\nServer: {}".format(pstatus, sstatus))
|
print("Portal: {}\nServer: {}".format(pstatus, sstatus))
|
||||||
|
|
||||||
send_instruction(PSTATUS, None, _callback, _errback)
|
send_instruction(PSTATUS, None, _callback, _errback, autostop=True)
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
def send_repeating_status(callback=None):
|
def wait_for_status(portal_running=True, server_running=True, callback=None, errback=None,
|
||||||
|
rate=0.5, retries=20):
|
||||||
"""
|
"""
|
||||||
Repeat the status ping until a reply is returned or timeout is reached.
|
Repeat the status ping until the desired state combination is achieved.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
callback (callable): Takes the response on a successful status-reply
|
portal_running (bool or None): Desired portal run-state. If None, any state is accepted.
|
||||||
|
server_running (bool or None): Desired server run-state. If None, any state is accepted.
|
||||||
|
the portal must be running.
|
||||||
|
callback (callable): Will be called with portal_state, server_state when
|
||||||
|
condition is fulfilled.
|
||||||
|
errback (callable): Will be called with portal_state, server_state if the
|
||||||
|
request is timed out.
|
||||||
|
rate (float): How often to retry.
|
||||||
|
retries (int): How many times to retry before timing out and calling `errback`.
|
||||||
"""
|
"""
|
||||||
def _callback(response):
|
def _callback(response):
|
||||||
pstatus, sstatus = response['status'].split("|")
|
prun, srun = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
||||||
print("Portal: {}\nServer: {}".format(pstatus, sstatus))
|
if ((portal_running is None or prun == portal_running) and
|
||||||
|
(server_running is None or srun == server_running)):
|
||||||
|
# the correct state was achieved
|
||||||
|
if callback:
|
||||||
|
callback(prun, srun)
|
||||||
|
else:
|
||||||
|
reactor.stop()
|
||||||
|
else:
|
||||||
|
if retries <= 0:
|
||||||
|
if errback:
|
||||||
|
errback(prun, srun)
|
||||||
|
else:
|
||||||
|
print("Timeout.")
|
||||||
|
reactor.stop()
|
||||||
|
else:
|
||||||
|
reactor.callLater(rate, wait_for_status,
|
||||||
|
portal_running, server_running,
|
||||||
|
callback, errback, rate, retries - 1)
|
||||||
|
|
||||||
def _errback(fail):
|
def _errback(fail):
|
||||||
send_instruction(PSTATUS, None, _callback, _errback)
|
"""
|
||||||
|
Portal not running
|
||||||
|
"""
|
||||||
|
if not portal_running:
|
||||||
|
# this is what we want
|
||||||
|
if callback:
|
||||||
|
callback(portal_running, server_running)
|
||||||
|
else:
|
||||||
|
reactor.stop()
|
||||||
|
else:
|
||||||
|
if retries <= 0:
|
||||||
|
if errback:
|
||||||
|
errback(portal_running, server_running)
|
||||||
|
else:
|
||||||
|
print("Timeout.")
|
||||||
|
reactor.stop()
|
||||||
|
else:
|
||||||
|
reactor.callLater(rate, wait_for_status,
|
||||||
|
portal_running, server_running,
|
||||||
|
callback, errback, rate, retries - 1)
|
||||||
|
|
||||||
send_instruction(PSTATUS, None, callback or _callback, _errback)
|
return send_instruction(PSTATUS, None, _callback, _errback)
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -572,18 +628,22 @@ def start_evennia(pprofiler=False, sprofiler=False):
|
||||||
"""
|
"""
|
||||||
portal_cmd, server_cmd = get_twistd_cmdline(pprofiler, sprofiler)
|
portal_cmd, server_cmd = get_twistd_cmdline(pprofiler, sprofiler)
|
||||||
|
|
||||||
|
def _server_started(*args):
|
||||||
|
print("... Server started.\nEvennia running.")
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
|
def _portal_started(*args):
|
||||||
|
send_instruction(SSTART, server_cmd, _server_started)
|
||||||
|
|
||||||
def _portal_running(response):
|
def _portal_running(response):
|
||||||
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
||||||
print("Portal is already running as process {pid}. Not restarted.".format(pid=0)) # TODO PID
|
print("Portal is already running as process {pid}. Not restarted.".format(pid=0)) # TODO PID
|
||||||
if server_running:
|
if server_running:
|
||||||
print("Server is already running as process {pid}. Not restarted.".format(pid=0)) # TODO PID
|
print("Server is already running as process {pid}. Not restarted.".format(pid=0)) # TODO PID
|
||||||
|
reactor.stop()
|
||||||
else:
|
else:
|
||||||
print("Server starting {}...".format("(under cProfile)" if pprofiler else ""))
|
print("Server starting {}...".format("(under cProfile)" if pprofiler else ""))
|
||||||
send_instruction(SSTART, server_cmd, lambda x: 0, lambda e: 0) # TODO
|
send_instruction(SSTART, server_cmd, _server_started)
|
||||||
|
|
||||||
def _portal_cold_started(response):
|
|
||||||
"Called once the portal is up after a cold boot. It needs to know how to start the Server."
|
|
||||||
send_instruction(SSTART, server_cmd, lambda x: 0, lambda e: 0) # TODO
|
|
||||||
|
|
||||||
def _portal_not_running(fail):
|
def _portal_not_running(fail):
|
||||||
print("Portal starting {}...".format("(under cProfile)" if sprofiler else ""))
|
print("Portal starting {}...".format("(under cProfile)" if sprofiler else ""))
|
||||||
|
|
@ -591,10 +651,10 @@ def start_evennia(pprofiler=False, sprofiler=False):
|
||||||
Popen(portal_cmd)
|
Popen(portal_cmd)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(PROCESS_ERROR.format(component="Portal", traceback=e))
|
print(PROCESS_ERROR.format(component="Portal", traceback=e))
|
||||||
send_repeating_status(_portal_cold_started)
|
wait_for_status(True, None, _portal_started)
|
||||||
|
|
||||||
# first, check if the portal/server is running already
|
|
||||||
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
def reload_evennia(sprofiler=False):
|
def reload_evennia(sprofiler=False):
|
||||||
|
|
@ -604,13 +664,22 @@ def reload_evennia(sprofiler=False):
|
||||||
"""
|
"""
|
||||||
_, server_cmd = get_twistd_cmdline(False, sprofiler)
|
_, server_cmd = get_twistd_cmdline(False, sprofiler)
|
||||||
|
|
||||||
|
def _server_restarted(*args):
|
||||||
|
print("... Server re-started.", args)
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
|
def _server_reloaded(*args):
|
||||||
|
print("... Server reloaded.", args)
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
def _portal_running(response):
|
def _portal_running(response):
|
||||||
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
||||||
if server_running:
|
if server_running:
|
||||||
print("Server reloading ...")
|
print("Server reloading ...")
|
||||||
|
send_instruction(SRELOAD, server_cmd, _server_reloaded)
|
||||||
else:
|
else:
|
||||||
print("Server down. Starting anew.")
|
print("Server down. Re-starting ...")
|
||||||
send_instruction(SRELOAD, server_cmd, lambda x: 0, lambda e: 0) # TODO
|
send_instruction(SSTART, server_cmd, _server_restarted)
|
||||||
|
|
||||||
def _portal_not_running(fail):
|
def _portal_not_running(fail):
|
||||||
print("Evennia not running. Starting from scratch ...")
|
print("Evennia not running. Starting from scratch ...")
|
||||||
|
|
@ -618,6 +687,7 @@ def reload_evennia(sprofiler=False):
|
||||||
|
|
||||||
# get portal status
|
# get portal status
|
||||||
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
def stop_evennia():
|
def stop_evennia():
|
||||||
|
|
@ -625,17 +695,29 @@ def stop_evennia():
|
||||||
This instructs the Portal to stop the Server and then itself.
|
This instructs the Portal to stop the Server and then itself.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
def _portal_stopped(*args):
|
||||||
|
print("... Portal stopped.\nEvennia shut down.")
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
|
def _server_stopped(*args):
|
||||||
|
print("... Server stopped.", args)
|
||||||
|
send_instruction(PSHUTD, {})
|
||||||
|
wait_for_status(False, None, _portal_stopped)
|
||||||
|
|
||||||
def _portal_running(response):
|
def _portal_running(response):
|
||||||
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
||||||
print("Portal stopping ...")
|
|
||||||
if server_running:
|
if server_running:
|
||||||
print("Server stopping ...")
|
print("Server stopping ...")
|
||||||
send_instruction(PSHUTD, {}, lambda x: 0, lambda e: 0) # TODO
|
send_instruction(SSHUTD, {}, _server_stopped)
|
||||||
|
else:
|
||||||
|
send_instruction(PSHUTD, {})
|
||||||
|
wait_for_status(False, False, _portal_stopped)
|
||||||
|
|
||||||
def _portal_not_running(fail):
|
def _portal_not_running(fail):
|
||||||
print("Evennia is not running.")
|
print("Evennia is not running.")
|
||||||
|
|
||||||
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
def stop_server_only():
|
def stop_server_only():
|
||||||
|
|
@ -643,11 +725,16 @@ def stop_server_only():
|
||||||
Only stop the Server-component of Evennia (this is not useful except for debug)
|
Only stop the Server-component of Evennia (this is not useful except for debug)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
def _server_stopped(*args):
|
||||||
|
print("... Server stopped.")
|
||||||
|
reactor.stop()
|
||||||
|
|
||||||
def _portal_running(response):
|
def _portal_running(response):
|
||||||
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
_, server_running = [stat == 'RUNNING' for stat in response['status'].split("|")]
|
||||||
if server_running:
|
if server_running:
|
||||||
print("Server stopping ...")
|
print("Server stopping ...")
|
||||||
send_instruction(SSHUTD, {}, lambda x: 0, lambda e: 0) # TODO
|
send_instruction(SSHUTD, {})
|
||||||
|
wait_for_status(True, False, _server_stopped)
|
||||||
else:
|
else:
|
||||||
print("Server is not running.")
|
print("Server is not running.")
|
||||||
|
|
||||||
|
|
@ -655,6 +742,7 @@ def stop_server_only():
|
||||||
print("Evennia is not running.")
|
print("Evennia is not running.")
|
||||||
|
|
||||||
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
|
||||||
|
reactor.run()
|
||||||
|
|
||||||
|
|
||||||
def evennia_version():
|
def evennia_version():
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
||||||
"""
|
"""
|
||||||
super(AMPServerProtocol, self).connectionMade()
|
super(AMPServerProtocol, self).connectionMade()
|
||||||
|
|
||||||
|
if len(self.factory.broadcasts) < 2:
|
||||||
sessdata = self.factory.portal.sessions.get_all_sync_data()
|
sessdata = self.factory.portal.sessions.get_all_sync_data()
|
||||||
self.send_AdminPortal2Server(amp.DUMMYSESSION,
|
self.send_AdminPortal2Server(amp.DUMMYSESSION,
|
||||||
amp.PSYNC,
|
amp.PSYNC,
|
||||||
|
|
@ -135,6 +136,10 @@ class AMPServerProtocol(amp.AMPMultiConnectionProtocol):
|
||||||
server_connected = any(1 for prtcl in self.factory.broadcasts
|
server_connected = any(1 for prtcl in self.factory.broadcasts
|
||||||
if prtcl is not self and prtcl.transport.connected)
|
if prtcl is not self and prtcl.transport.connected)
|
||||||
|
|
||||||
|
print("AMP SERVER operation == %s received" % (ord(operation)))
|
||||||
|
print("AMP SERVER arguments: %s" % (amp.loads(arguments)))
|
||||||
|
return {"result": "Received."}
|
||||||
|
|
||||||
if operation == amp.SSTART: # portal start (server start or reload)
|
if operation == amp.SSTART: # portal start (server start or reload)
|
||||||
# first, check if server is already running
|
# first, check if server is already running
|
||||||
if server_connected:
|
if server_connected:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue