2026-01-06 22:04:52 +08:00
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
IS_WINDOWS: bool = sys.platform == "win32"
|
|
|
|
|
|
|
|
|
|
if IS_WINDOWS:
|
|
|
|
|
import win32api
|
|
|
|
|
else:
|
|
|
|
|
import signal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WhileStopper:
|
2026-01-08 20:04:24 +08:00
|
|
|
_is_registered: bool
|
|
|
|
|
_stop_requested: bool
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
2026-01-08 20:04:24 +08:00
|
|
|
self._is_registered = False
|
|
|
|
|
self._stop_requested = False
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
def is_stop_requested(self) -> bool:
|
2026-01-08 20:04:24 +08:00
|
|
|
if not self._is_registered:
|
|
|
|
|
raise RuntimeError("unexpected stopper status")
|
2026-01-06 22:04:52 +08:00
|
|
|
|
2026-01-08 20:04:24 +08:00
|
|
|
return self._stop_requested
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
def register(self):
|
2026-01-08 20:04:24 +08:00
|
|
|
if self._is_registered:
|
|
|
|
|
raise RuntimeError("unexpected stopper status")
|
2026-01-06 22:04:52 +08:00
|
|
|
|
2026-01-08 20:04:24 +08:00
|
|
|
self._stop_requested = False
|
2026-01-06 22:04:52 +08:00
|
|
|
if IS_WINDOWS:
|
2026-01-08 20:04:24 +08:00
|
|
|
win32api.SetConsoleCtrlHandler(_win_handler, True)
|
2026-01-06 22:04:52 +08:00
|
|
|
else:
|
2026-01-08 20:04:24 +08:00
|
|
|
signal.signal(signal.SIGINT, _posix_handler)
|
|
|
|
|
self._is_registered = True
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
def unregister(self):
|
2026-01-08 20:04:24 +08:00
|
|
|
if not self._is_registered:
|
|
|
|
|
raise RuntimeError("unexpected stopper status")
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
if IS_WINDOWS:
|
2026-01-08 20:04:24 +08:00
|
|
|
win32api.SetConsoleCtrlHandler(_win_handler, False)
|
2026-01-06 22:04:52 +08:00
|
|
|
else:
|
|
|
|
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
2026-01-08 20:04:24 +08:00
|
|
|
self._is_registered = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INSTANCE: WhileStopper = WhileStopper()
|
|
|
|
|
"""The singleton of WhileStopper"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _win_handler(ctrl_type: int) -> bool:
|
|
|
|
|
INSTANCE._stop_requested = True
|
|
|
|
|
return True
|
2026-01-06 22:04:52 +08:00
|
|
|
|
|
|
|
|
|
2026-01-08 20:04:24 +08:00
|
|
|
def _posix_handler(signal, frame) -> None:
|
|
|
|
|
INSTANCE._stop_requested = True
|