116 lines
3.1 KiB
Python
116 lines
3.1 KiB
Python
|
import sys
|
||
|
from pathlib import Path
|
||
|
from typing import TYPE_CHECKING
|
||
|
|
||
|
if TYPE_CHECKING:
|
||
|
from threading import Event
|
||
|
from werkzeug.test import Client as FlaskClient
|
||
|
|
||
|
__all__ = [
|
||
|
"ServeGame",
|
||
|
"LocalServeGame",
|
||
|
"WebHostServeGame",
|
||
|
]
|
||
|
|
||
|
|
||
|
class ServeGame:
|
||
|
address: str
|
||
|
|
||
|
|
||
|
def _launch_multiserver(multidata: Path, ready: "Event", stop: "Event") -> None:
|
||
|
import os
|
||
|
import warnings
|
||
|
|
||
|
original_argv = sys.argv
|
||
|
original_stdin = sys.stdin
|
||
|
warnings.simplefilter("ignore")
|
||
|
try:
|
||
|
import asyncio
|
||
|
from MultiServer import main, parse_args
|
||
|
|
||
|
sys.argv = [sys.argv[0], str(multidata), "--host", "127.0.0.1"]
|
||
|
r, w = os.pipe()
|
||
|
sys.stdin = os.fdopen(r, "r")
|
||
|
|
||
|
async def set_ready() -> None:
|
||
|
await asyncio.sleep(.01) # switch back to other task once more
|
||
|
ready.set() # server should be up, set ready state
|
||
|
|
||
|
async def wait_stop() -> None:
|
||
|
await asyncio.get_event_loop().run_in_executor(None, stop.wait)
|
||
|
os.fdopen(w, "w").write("/exit")
|
||
|
|
||
|
async def run() -> None:
|
||
|
# this will run main() until first await, then switch to set_ready()
|
||
|
await asyncio.gather(
|
||
|
main(parse_args()),
|
||
|
set_ready(),
|
||
|
wait_stop(),
|
||
|
)
|
||
|
|
||
|
asyncio.run(run())
|
||
|
finally:
|
||
|
sys.argv = original_argv
|
||
|
sys.stdin = original_stdin
|
||
|
|
||
|
|
||
|
class LocalServeGame(ServeGame):
|
||
|
from multiprocessing import Process
|
||
|
|
||
|
_multidata: Path
|
||
|
_proc: Process
|
||
|
_stop: "Event"
|
||
|
|
||
|
def __init__(self, multidata: Path) -> None:
|
||
|
self.address = ""
|
||
|
self._multidata = multidata
|
||
|
|
||
|
def __enter__(self) -> "LocalServeGame":
|
||
|
from multiprocessing import Manager, Process, set_start_method
|
||
|
|
||
|
try:
|
||
|
set_start_method("spawn")
|
||
|
except RuntimeError:
|
||
|
pass
|
||
|
|
||
|
manager = Manager()
|
||
|
ready: "Event" = manager.Event()
|
||
|
self._stop = manager.Event()
|
||
|
|
||
|
self._proc = Process(target=_launch_multiserver, args=(self._multidata, ready, self._stop))
|
||
|
try:
|
||
|
self._proc.start()
|
||
|
ready.wait(30)
|
||
|
self.address = "localhost:38281"
|
||
|
return self
|
||
|
except BaseException:
|
||
|
self.__exit__(*sys.exc_info())
|
||
|
raise
|
||
|
|
||
|
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
|
||
|
try:
|
||
|
self._stop.set()
|
||
|
self._proc.join(30)
|
||
|
except TimeoutError:
|
||
|
self._proc.terminate()
|
||
|
self._proc.join()
|
||
|
|
||
|
|
||
|
class WebHostServeGame(ServeGame):
|
||
|
_client: "FlaskClient"
|
||
|
_room: str
|
||
|
|
||
|
def __init__(self, app_client: "FlaskClient", room: str) -> None:
|
||
|
self.address = ""
|
||
|
self._client = app_client
|
||
|
self._room = room
|
||
|
|
||
|
def __enter__(self) -> "WebHostServeGame":
|
||
|
from .webhost import start_room
|
||
|
self.address = start_room(self._client, self._room)
|
||
|
return self
|
||
|
|
||
|
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
|
||
|
from .webhost import stop_room
|
||
|
stop_room(self._client, self._room, timeout=30)
|