implement --auto_shutdown <minutes>, shutting down a multiserver after that many minutes of inactivity
and set WebHost to a default of 6 hours
This commit is contained in:
parent
bd1c9f896b
commit
facecdf487
|
@ -57,8 +57,10 @@ class Client(Endpoint):
|
|||
|
||||
class Context(Node):
|
||||
def __init__(self, host: str, port: int, password: str, location_check_points: int, hint_cost: int,
|
||||
item_cheat: bool, forfeit_mode: str = "disabled", remaining_mode: str = "disabled", auto_shutdown=0):
|
||||
item_cheat: bool, forfeit_mode: str = "disabled", remaining_mode: str = "disabled",
|
||||
auto_shutdown: typing.SupportsFloat = 0):
|
||||
super(Context, self).__init__()
|
||||
self.shutdown_task = None
|
||||
self.data_filename = None
|
||||
self.save_filename = None
|
||||
self.saving = False
|
||||
|
@ -88,7 +90,7 @@ class Context(Node):
|
|||
typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection
|
||||
self.client_game_state: typing.Dict[typing.Tuple[int, int], int] = collections.defaultdict(int)
|
||||
self.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {}
|
||||
self.auto_shutdown = 0
|
||||
self.auto_shutdown = auto_shutdown
|
||||
self.commandprocessor = ServerCommandProcessor(self)
|
||||
self.embedded_blacklist = {"host", "port"}
|
||||
self.client_ids: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {}
|
||||
|
@ -948,6 +950,8 @@ class ServerCommandProcessor(CommandProcessor):
|
|||
def _cmd_exit(self) -> bool:
|
||||
"""Shutdown the server"""
|
||||
asyncio.create_task(self.ctx.server.ws_server._close())
|
||||
if self.ctx.shutdown_task:
|
||||
self.ctx.shutdown_task.cancel()
|
||||
self.ctx.running = False
|
||||
return True
|
||||
|
||||
|
@ -1095,9 +1099,30 @@ def parse_args() -> argparse.Namespace:
|
|||
return args
|
||||
|
||||
|
||||
async def auto_shutdown(ctx):
|
||||
# to be implemented soon
|
||||
pass
|
||||
async def auto_shutdown(ctx, to_cancel=None):
|
||||
await asyncio.sleep(ctx.auto_shutdown * 60)
|
||||
while ctx.running:
|
||||
if not ctx.client_activity_timers.values():
|
||||
asyncio.create_task(ctx.server.ws_server._close())
|
||||
ctx.running = False
|
||||
if to_cancel:
|
||||
for task in to_cancel:
|
||||
task.cancel()
|
||||
logging.info("Shutting down due to inactivity.")
|
||||
else:
|
||||
newest_activity = max(ctx.client_activity_timers.values())
|
||||
delta = datetime.datetime.now(datetime.timezone.utc) - newest_activity
|
||||
seconds = ctx.auto_shutdown * 60 - delta.total_seconds()
|
||||
if seconds < 0:
|
||||
asyncio.create_task(ctx.server.ws_server._close())
|
||||
ctx.running = False
|
||||
if to_cancel:
|
||||
for task in to_cancel:
|
||||
task.cancel()
|
||||
logging.info("Shutting down due to inactivity.")
|
||||
else:
|
||||
await asyncio.sleep(seconds)
|
||||
|
||||
|
||||
async def main(args: argparse.Namespace):
|
||||
logging.basicConfig(format='[%(asctime)s] %(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO))
|
||||
|
@ -1128,9 +1153,18 @@ async def main(args: argparse.Namespace):
|
|||
ip = args.host if args.host else Utils.get_public_ipv4()
|
||||
logging.info('Hosting game at %s:%d (%s)' % (ip, ctx.port,
|
||||
'No password' if not ctx.password else 'Password: %s' % ctx.password))
|
||||
|
||||
await ctx.server
|
||||
await console(ctx)
|
||||
console_task = asyncio.create_task(console(ctx))
|
||||
if ctx.auto_shutdown:
|
||||
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, [console_task]))
|
||||
await console_task
|
||||
if ctx.shutdown_task:
|
||||
await ctx.shutdown_task
|
||||
|
||||
if __name__ == '__main__':
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main(parse_args()))
|
||||
try:
|
||||
loop.run_until_complete(main(parse_args()))
|
||||
except asyncio.exceptions.CancelledError:
|
||||
pass
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
import typing
|
||||
import multiprocessing
|
||||
import functools
|
||||
from pony.flask import Pony
|
||||
from pony.orm import Database, Required, Optional, commit, select, db_session
|
||||
from pony.orm import Database, db_session
|
||||
|
||||
import websockets
|
||||
from flask import Flask, flash, request, redirect, url_for, render_template, Response, g
|
||||
from flask import Flask, flash, request, redirect, url_for, render_template, Response
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
|
||||
|
||||
UPLOAD_FOLDER = os.path.relpath('uploads')
|
||||
LOGS_FOLDER = os.path.relpath('logs')
|
||||
multidata_folder = os.path.join(UPLOAD_FOLDER, "multidata")
|
||||
|
@ -116,39 +114,7 @@ def host_multidata(filename: str):
|
|||
return render_template("host_multidata.html", filename=filename)
|
||||
|
||||
|
||||
def run_server_process(multidata: str):
|
||||
async def main():
|
||||
logging.basicConfig(format='[%(asctime)s] %(message)s',
|
||||
level=logging.INFO,
|
||||
filename=os.path.join(LOGS_FOLDER, multidata + ".txt"))
|
||||
ctx = Context("", 0, "", 1, 1000,
|
||||
True, "enabled", "goal")
|
||||
ctx.load(os.path.join(multidata_folder, multidata), True)
|
||||
ctx.auto_shutdown = 24 * 60 * 60 # 24 hours
|
||||
ctx.init_save()
|
||||
|
||||
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, 0, ping_timeout=None,
|
||||
ping_interval=None)
|
||||
|
||||
await ctx.server
|
||||
for wssocket in ctx.server.ws_server.sockets:
|
||||
socketname = wssocket.getsockname()
|
||||
if wssocket.family == socket.AF_INET6:
|
||||
logging.info(f'Hosting game at [{get_public_ipv6()}]:{socketname[1]}')
|
||||
elif wssocket.family == socket.AF_INET:
|
||||
logging.info(f'Hosting game at {get_public_ipv4()}:{socketname[1]}')
|
||||
while ctx.running:
|
||||
await asyncio.sleep(1)
|
||||
logging.info("Shutting down")
|
||||
|
||||
import asyncio
|
||||
if ".." not in sys.path:
|
||||
sys.path.append("..")
|
||||
from MultiServer import Context, server
|
||||
from Utils import get_public_ipv4, get_public_ipv6
|
||||
import socket
|
||||
asyncio.run(main())
|
||||
|
||||
from WebHost.customserver import run_server_process
|
||||
|
||||
if __name__ == "__main__":
|
||||
multiprocessing.freeze_support()
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import functools
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import websockets
|
||||
|
||||
from WebHost import LOGS_FOLDER, multidata_folder
|
||||
|
||||
|
||||
def run_server_process(multidata: str):
|
||||
async def main():
|
||||
logging.basicConfig(format='[%(asctime)s] %(message)s',
|
||||
level=logging.INFO,
|
||||
filename=os.path.join(LOGS_FOLDER, multidata + ".txt"))
|
||||
ctx = Context("", 0, "", 1, 1000,
|
||||
True, "enabled", "goal", 0)
|
||||
ctx.load(os.path.join(multidata_folder, multidata), True)
|
||||
ctx.auto_shutdown = 24 * 60 * 60 # 24 hours
|
||||
ctx.init_save()
|
||||
|
||||
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, 0, ping_timeout=None,
|
||||
ping_interval=None)
|
||||
|
||||
await ctx.server
|
||||
for wssocket in ctx.server.ws_server.sockets:
|
||||
socketname = wssocket.getsockname()
|
||||
if wssocket.family == socket.AF_INET6:
|
||||
logging.info(f'Hosting game at [{get_public_ipv6()}]:{socketname[1]}')
|
||||
elif wssocket.family == socket.AF_INET:
|
||||
logging.info(f'Hosting game at {get_public_ipv4()}:{socketname[1]}')
|
||||
ctx.auto_shutdown = 6 * 60
|
||||
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, []))
|
||||
while ctx.running:
|
||||
await asyncio.sleep(1)
|
||||
await ctx.shutdown_task
|
||||
logging.info("Shutting down")
|
||||
|
||||
import asyncio
|
||||
if ".." not in sys.path:
|
||||
sys.path.append("..")
|
||||
from MultiServer import Context, server, auto_shutdown
|
||||
from Utils import get_public_ipv4, get_public_ipv6
|
||||
import socket
|
||||
asyncio.run(main())
|
Loading…
Reference in New Issue