From fabcc87ecd20647f1d66ae87e01e710b2c79e983 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 18 Jan 2018 18:59:46 +0100 Subject: [PATCH] Remove evennia_runner.py (now managed by Portal) --- evennia/server/evennia_runner.py | 354 ------------------------------- 1 file changed, 354 deletions(-) delete mode 100644 evennia/server/evennia_runner.py diff --git a/evennia/server/evennia_runner.py b/evennia/server/evennia_runner.py deleted file mode 100644 index d920c181e8..0000000000 --- a/evennia/server/evennia_runner.py +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/env python -""" - -This runner is controlled by the evennia launcher and should normally -not be launched directly. It manages the two main Evennia processes -(Server and Portal) and most importantly runs a passive, threaded loop -that makes sure to restart Server whenever it shuts down. - -Since twistd does not allow for returning an optional exit code we -need to handle the current reload state for server and portal with -flag-files instead. The files, one each for server and portal either -contains True or False indicating if the process should be restarted -upon returning, or not. A process returning != 0 will always stop, no -matter the value of this file. - -""" -from __future__ import print_function -import os -import sys -from argparse import ArgumentParser -from subprocess import Popen -import Queue -import thread -import evennia - -try: - # check if launched with pypy - import __pypy__ as is_pypy -except ImportError: - is_pypy = False - -SERVER = None -PORTAL = None - -EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -EVENNIA_BIN = os.path.join(EVENNIA_ROOT, "bin") -EVENNIA_LIB = os.path.dirname(evennia.__file__) - -SERVER_PY_FILE = os.path.join(EVENNIA_LIB, 'server', 'server.py') -PORTAL_PY_FILE = os.path.join(EVENNIA_LIB, 'server', 'portal', 'portal.py') - -GAMEDIR = None -SERVERDIR = "server" -SERVER_PIDFILE = None -PORTAL_PIDFILE = None -SERVER_RESTART = None -PORTAL_RESTART = None -SERVER_LOGFILE = None -PORTAL_LOGFILE = None -HTTP_LOGFILE = None -PPROFILER_LOGFILE = None -SPROFILER_LOGFILE = None - -# messages - -CMDLINE_HELP = \ - """ - This program manages the running Evennia processes. It is called - by evennia and should not be started manually. Its main task is to - sit and watch the Server and restart it whenever the user reloads. - The runner depends on four files for its operation, two PID files - and two RESTART files for Server and Portal respectively; these - are stored in the game's server/ directory. - """ - - -PROCESS_IOERROR = \ - """ - {component} IOError: {traceback} - One possible explanation is that 'twistd' was not found. - """ - -PROCESS_RESTART = "{component} restarting ..." - -PROCESS_DOEXIT = "Deferring to external runner." - -# Functions - - -def set_restart_mode(restart_file, flag="reload"): - """ - This sets a flag file for the restart mode. - """ - with open(restart_file, 'w') as f: - f.write(str(flag)) - - -def getenv(): - """ - Get current environment and add PYTHONPATH - """ - sep = ";" if os.name == "nt" else ":" - env = os.environ.copy() - sys.path.insert(0, GAMEDIR) - env['PYTHONPATH'] = sep.join(sys.path) - return env - - -def get_restart_mode(restart_file): - """ - Parse the server/portal restart status - """ - if os.path.exists(restart_file): - with open(restart_file, 'r') as f: - return f.read() - return "shutdown" - - -def get_pid(pidfile): - """ - Get the PID (Process ID) by trying to access - an PID file. - """ - pid = None - if os.path.exists(pidfile): - with open(pidfile, 'r') as f: - pid = f.read() - return pid - - -def cycle_logfile(logfile): - """ - Rotate the old log files to .old - """ - logfile_old = logfile + '.old' - if os.path.exists(logfile): - # Cycle the old logfiles to *.old - if os.path.exists(logfile_old): - # E.g. Windows don't support rename-replace - os.remove(logfile_old) - os.rename(logfile, logfile_old) - -# Start program management - - -def start_services(server_argv, portal_argv, doexit=False): - """ - This calls a threaded loop that launches the Portal and Server - and then restarts them when they finish. - """ - global SERVER, PORTAL - processes = Queue.Queue() - - def server_waiter(queue): - try: - rc = Popen(server_argv, env=getenv()).wait() - except Exception as e: - print(PROCESS_ERROR.format(component="Server", traceback=e)) - return - # this signals the controller that the program finished - queue.put(("server_stopped", rc)) - - def portal_waiter(queue): - try: - rc = Popen(portal_argv, env=getenv()).wait() - except Exception as e: - print(PROCESS_ERROR.format(component="Portal", traceback=e)) - return - # this signals the controller that the program finished - queue.put(("portal_stopped", rc)) - - if portal_argv: - try: - if not doexit and get_restart_mode(PORTAL_RESTART) == "True": - # start portal as interactive, reloadable thread - PORTAL = thread.start_new_thread(portal_waiter, (processes, )) - else: - # normal operation: start portal as a daemon; - # we don't care to monitor it for restart - PORTAL = Popen(portal_argv, env=getenv()) - except IOError as e: - print(PROCESS_IOERROR.format(component="Portal", traceback=e)) - return - - try: - if server_argv: - if doexit: - SERVER = Popen(server_argv, env=getenv()) - else: - # start server as a reloadable thread - SERVER = thread.start_new_thread(server_waiter, (processes, )) - except IOError as e: - print(PROCESS_IOERROR.format(component="Server", traceback=e)) - return - - if doexit: - # Exit immediately - return - - # Reload loop - while True: - - # this blocks until something is actually returned. - from twisted.internet.error import ReactorNotRunning - try: - try: - message, rc = processes.get() - except KeyboardInterrupt: - # this only matters in interactive mode - break - - # restart only if process stopped cleanly - if (message == "server_stopped" and int(rc) == 0 and - get_restart_mode(SERVER_RESTART) in ("True", "reload", "reset")): - print(PROCESS_RESTART.format(component="Server")) - SERVER = thread.start_new_thread(server_waiter, (processes, )) - continue - - # normally the portal is not reloaded since it's run as a daemon. - if (message == "portal_stopped" and int(rc) == 0 and - get_restart_mode(PORTAL_RESTART) == "True"): - print(PROCESS_RESTART.format(component="Portal")) - PORTAL = thread.start_new_thread(portal_waiter, (processes, )) - continue - break - except ReactorNotRunning: - break - - -def main(): - """ - This handles the command line input of the runner, usually created by - the evennia launcher - """ - - parser = ArgumentParser(description=CMDLINE_HELP) - parser.add_argument('--noserver', action='store_true', dest='noserver', - default=False, help='Do not start Server process') - parser.add_argument('--noportal', action='store_true', dest='noportal', - default=False, help='Do not start Portal process') - parser.add_argument('--logserver', action='store_true', dest='logserver', - default=False, help='Log Server output to logfile') - parser.add_argument('--iserver', action='store_true', dest='iserver', - default=False, help='Server in interactive mode') - parser.add_argument('--iportal', action='store_true', dest='iportal', - default=False, help='Portal in interactive mode') - parser.add_argument('--pserver', action='store_true', dest='pserver', - default=False, help='Profile Server') - parser.add_argument('--pportal', action='store_true', dest='pportal', - default=False, help='Profile Portal') - parser.add_argument('--nologcycle', action='store_false', dest='nologcycle', - default=True, help='Do not cycle log files') - parser.add_argument('--doexit', action='store_true', dest='doexit', - default=False, help='Immediately exit after processes have started.') - parser.add_argument('gamedir', help="path to game dir") - parser.add_argument('twistdbinary', help="path to twistd binary") - parser.add_argument('slogfile', help="path to server log file") - parser.add_argument('plogfile', help="path to portal log file") - parser.add_argument('hlogfile', help="path to http log file") - - args = parser.parse_args() - - global GAMEDIR - global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE - global SERVER_PIDFILE, PORTAL_PIDFILE - global SERVER_RESTART, PORTAL_RESTART - global SPROFILER_LOGFILE, PPROFILER_LOGFILE - - GAMEDIR = args.gamedir - sys.path.insert(1, os.path.join(GAMEDIR, SERVERDIR)) - - SERVER_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "server.pid") - PORTAL_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "portal.pid") - SERVER_RESTART = os.path.join(GAMEDIR, SERVERDIR, "server.restart") - PORTAL_RESTART = os.path.join(GAMEDIR, SERVERDIR, "portal.restart") - SERVER_LOGFILE = args.slogfile - PORTAL_LOGFILE = args.plogfile - HTTP_LOGFILE = args.hlogfile - TWISTED_BINARY = args.twistdbinary - SPROFILER_LOGFILE = os.path.join(GAMEDIR, SERVERDIR, "logs", "server.prof") - PPROFILER_LOGFILE = os.path.join(GAMEDIR, SERVERDIR, "logs", "portal.prof") - - # set up default project calls - server_argv = [TWISTED_BINARY, - '--nodaemon', - '--logfile=%s' % SERVER_LOGFILE, - '--pidfile=%s' % SERVER_PIDFILE, - '--python=%s' % SERVER_PY_FILE] - portal_argv = [TWISTED_BINARY, - '--logfile=%s' % PORTAL_LOGFILE, - '--pidfile=%s' % PORTAL_PIDFILE, - '--python=%s' % PORTAL_PY_FILE] - - # Profiling settings (read file from python shell e.g with - # p = pstats.Stats('server.prof') - pserver_argv = ['--savestats', - '--profiler=cprofile', - '--profile=%s' % SPROFILER_LOGFILE] - pportal_argv = ['--savestats', - '--profiler=cprofile', - '--profile=%s' % PPROFILER_LOGFILE] - - # Server - - pid = get_pid(SERVER_PIDFILE) - if pid and not args.noserver: - print("\nEvennia Server is already running as process %(pid)s. Not restarted." % {'pid': pid}) - args.noserver = True - if args.noserver: - server_argv = None - else: - set_restart_mode(SERVER_RESTART, "shutdown") - if not args.logserver: - # don't log to server logfile - del server_argv[2] - print("\nStarting Evennia Server (output to stdout).") - else: - if not args.nologcycle: - cycle_logfile(SERVER_LOGFILE) - print("\nStarting Evennia Server (output to server logfile).") - if args.pserver: - server_argv.extend(pserver_argv) - print("\nRunning Evennia Server under cProfile.") - - # Portal - - pid = get_pid(PORTAL_PIDFILE) - if pid and not args.noportal: - print("\nEvennia Portal is already running as process %(pid)s. Not restarted." % {'pid': pid}) - args.noportal = True - if args.noportal: - portal_argv = None - else: - if args.iportal: - # make portal interactive - portal_argv[1] = '--nodaemon' - set_restart_mode(PORTAL_RESTART, True) - print("\nStarting Evennia Portal in non-Daemon mode (output to stdout).") - else: - if not args.nologcycle: - cycle_logfile(PORTAL_LOGFILE) - cycle_logfile(HTTP_LOGFILE) - set_restart_mode(PORTAL_RESTART, False) - print("\nStarting Evennia Portal in Daemon mode (output to portal logfile).") - if args.pportal: - portal_argv.extend(pportal_argv) - print("\nRunning Evennia Portal under cProfile.") - if args.doexit: - print(PROCESS_DOEXIT) - - # Windows fixes (Windows don't support pidfiles natively) - if os.name == 'nt': - if server_argv: - del server_argv[-2] - if portal_argv: - del portal_argv[-2] - - # Start processes - print("server_argv:", server_argv, portal_argv) - start_services(server_argv, portal_argv, doexit=args.doexit) - - -if __name__ == '__main__': - main()