diff --git a/game/evennia.py b/game/evennia.py index 8c55bfc2bf..541f73d4c1 100755 --- a/game/evennia.py +++ b/game/evennia.py @@ -252,7 +252,7 @@ def del_pid(pidfile): if os.path.exists(pidfile): os.remove(pidfile) -def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart=True): +def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART, restart="reload"): """ Send a kill signal to a process based on PID. A customized success/error message will be returned. If clean=True, the system will attempt to manually @@ -321,17 +321,17 @@ def run_menu(): if os.name == 'nt': print "This operation is not supported under Windows. Log into the game to restart/reload the server." return - kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % "Server") + kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % "Server", restart="reload") elif inp == 6: if os.name == 'nt': print "This operation is not supported under Windows." return - kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped if in daemon mode).", errmsg % "Portal") + kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped if in daemon mode).", errmsg % "Portal", restart=True) elif inp == 7: kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False) - kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart=False) + kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart="shutdown") elif inp == 8: - kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart=False) + kill(PORTAL_PIDFILE, SIG, "Stopped Server.", errmsg % "Server", restart="shutdown") elif inp == 9: kill(SERVER_PIDFILE, SIG, "Stopped Portal.", errmsg % "Portal", PORTAL_RESTART, restart=False) return @@ -379,7 +379,7 @@ def handle_args(options, mode, service): print "Restarting from command line is not supported under Windows. Log into the game to restart." return if service == 'server': - kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server') + kill(SERVER_PIDFILE, SIG, "Server reloaded.", errmsg % 'Server', restart="reload") elif service == 'portal': print """ Note: Portal usually don't need to be reloaded unless you are debugging in interactive mode. @@ -389,17 +389,17 @@ def handle_args(options, mode, service): kill(PORTAL_PIDFILE, SIG, "Portal reloaded (or stopped, if it was in daemon mode).", errmsg % 'Portal', PORTAL_RESTART) else: # all # default mode, only restart server - kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server') + kill(SERVER_PIDFILE, SIG, "Server reload.", errmsg % 'Server', restart="reload") elif mode == 'stop': # stop processes, avoiding reload if service == 'server': - kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart=False) + kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart="shutdown") elif service == 'portal': kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False) else: kill(PORTAL_PIDFILE, SIG, "Portal stopped.", errmsg % 'Portal', PORTAL_RESTART, restart=False) - kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart=False) + kill(SERVER_PIDFILE, SIG, "Server stopped.", errmsg % 'Server', restart="shutdown") return None def error_check_python_modules(): diff --git a/game/gamesrc/conf/examples/at_server_startstop.py b/game/gamesrc/conf/examples/at_server_startstop.py index 9d9fbb5c61..74f173c809 100644 --- a/game/gamesrc/conf/examples/at_server_startstop.py +++ b/game/gamesrc/conf/examples/at_server_startstop.py @@ -19,19 +19,48 @@ The module should define at least these global functions: at_server_start() at_server_stop() +at_server_reload_start() +at_server_reload_stop() +at_server_cold_start() +at_server_cold_stop() """ def at_server_start(): """ - This is called every time the server starts up (also after a - reload or reset). + This is called every time the server starts up, regardless of + how it was shut down. """ pass def at_server_stop(): """ - This is called just before a server is shut down, reloaded or - reset. + This is called just before a server is shut down, regardless + of it is fore a reload, reset or shutdown. + """ + pass + +def at_server_reload_start(): + """ + This is called only when server starts back up after a reload. + """ + pass + +def at_server_reload_stop(): + """ + This is called only time the server stops before a reload. + """ + pass + +def at_server_cold_start(): + """ + This is called only when the server starts "cold", i.e. after a + shutdown or a reset. + """ + pass + +def at_server_cold_stop(): + """ + This is called only when the server goes down due to a shutdown or reset. """ pass diff --git a/game/runner.py b/game/runner.py index c4aae801ef..760b7f3489 100644 --- a/game/runner.py +++ b/game/runner.py @@ -74,22 +74,21 @@ if os.name == 'nt': # Functions -def set_restart_mode(restart_file, flag=True): +def set_restart_mode(restart_file, flag="reload"): """ This sets a flag file for the restart mode. """ - f = open(restart_file, 'w') - f.write(str(flag)) - f.close() + with open(restart_file, 'w') as f: + f.write(str(flag)) def get_restart_mode(restart_file): """ Parse the server/portal restart status """ if os.path.exists(restart_file): - flag = open(restart_file, 'r').read() - return flag == "True" - return False + with open(restart_file, 'r') as f: + return f.read() + return "shutdown" def get_pid(pidfile): """ @@ -98,8 +97,8 @@ def get_pid(pidfile): """ pid = None if os.path.exists(pidfile): - f = open(pidfile, 'r') - pid = f.read() + with open(pidfile, 'r') as f: + pid = f.read() return pid def cycle_logfile(logfile): @@ -165,7 +164,7 @@ def start_services(server_argv, portal_argv): if portal_argv: try: - if get_restart_mode(PORTAL_RESTART): + if get_restart_mode(PORTAL_RESTART) == "True": # start portal as interactive, reloadable thread PORTAL = thread.start_new_thread(portal_waiter, (processes, )) else: @@ -185,13 +184,13 @@ def start_services(server_argv, portal_argv): message, rc = processes.get() # restart only if process stopped cleanly - if message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART): + if message == "server_stopped" and int(rc) == 0 and get_restart_mode(SERVER_RESTART) in ("True", "reload", "reset"): print "Evennia Server stopped. Restarting ..." 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): + if message == "portal_stopped" and int(rc) == 0 and get_restart_mode(PORTAL_RESTART) == "True": print "Evennia Portal stopped in interactive mode. Restarting ..." PORTAL = thread.start_new_thread(portal_waiter, (processes, )) continue @@ -261,7 +260,7 @@ def main(): if options.noserver: server_argv = None else: - set_restart_mode(SERVER_RESTART, True) + set_restart_mode(SERVER_RESTART, "shutdown") if options.iserver: # don't log to server logfile del server_argv[2] diff --git a/src/server/server.py b/src/server/server.py index 68c1a7213a..c4bec30789 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -39,7 +39,7 @@ if os.name == 'nt': # a file with a flag telling the server to restart after shutdown or not. SERVER_RESTART = os.path.join(settings.GAME_DIR, 'server.restart') -# module containing hook methods +# module containing hook methods called during start_stop SERVER_STARTSTOP_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE) # module containing plugin services @@ -197,8 +197,16 @@ class Evennia(object): [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()] [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()] - # call server hook. if SERVER_STARTSTOP_MODULE: + # call correct server hook based on start file value + with open(SERVER_RESTART, 'r') as f: + mode = f.read() + if mode in ('True', 'reload'): + # True was the old reload flag, kept for compatibilty + SERVER_STARTSTOP_MODULE.at_server_reload_start() + elif mode in ('reset', 'shutdown'): + SERVER_STARTSTOP_MODULE.at_server_cold_start() + # always call this regardless of start type SERVER_STARTSTOP_MODULE.at_server_start() def set_restart_mode(self, mode=None): @@ -212,19 +220,28 @@ class Evennia(object): returned so the server knows which more it's in. """ if mode == None: - f = open(SERVER_RESTART, 'r') - if os.path.exists(SERVER_RESTART) and 'True' == f.read(): - mode = 'reload' - else: - mode = 'shutdown' - f.close() + with open(SERVER_RESTART, 'r') as f: + # mode is either shutdown, reset or reload + mode = f.read() else: - restart = mode in ('reload', 'reset') - f = open(SERVER_RESTART, 'w') - f.write(str(restart)) - f.close() + with open(SERVER_RESTART, 'w') as f: + f.write(str(mode)) return mode + #if mode == None: + # f = open(SERVER_RESTART, 'r') + # if os.path.exists(SERVER_RESTART) and 'True' == f.read(): + # mode = 'reload' + # else: + # mode = 'shutdown' + # f.close() + #else: + # restart = mode in ('reload', 'reset') + # f = open(SERVER_RESTART, 'w') + # f.write(str(restart)) + # f.close() + #return mode + @defer.inlineCallbacks def shutdown(self, mode=None, _reactor_stopping=False): """ @@ -257,6 +274,10 @@ class Evennia(object): yield [(s.typeclass, s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()] yield self.sessions.all_sessions_portal_sync() ServerConfig.objects.conf("server_restart_mode", "reload") + + if SERVER_STARTSTOP_MODULE: + SERVER_STARTSTOP_MODULE.at_server_reload_stop() + else: if mode == 'reset': # don't call disconnect hooks on reset @@ -270,6 +291,9 @@ class Evennia(object): ServerConfig.objects.conf("server_restart_mode", "reset") + if SERVER_STARTSTOP_MODULE: + SERVER_STARTSTOP_MODULE.at_server_cold_stop() + if SERVER_STARTSTOP_MODULE: SERVER_STARTSTOP_MODULE.at_server_stop() # if _reactor_stopping is true, reactor does not need to be stopped again.