mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	
		
			
	
	
		
			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) |