diff --git a/src-python/config.py b/src-python/config.py index bc61ccd5..81d27b54 100644 --- a/src-python/config.py +++ b/src-python/config.py @@ -106,6 +106,14 @@ class Config: def MAX_SPEAKER_THRESHOLD(self): return self._MAX_SPEAKER_THRESHOLD + @property + def WATCHDOG_TIMEOUT(self): + return self._WATCHDOG_TIMEOUT + + @property + def WATCHDOG_INTERVAL(self): + return self._WATCHDOG_INTERVAL + # Read Write @property def ENABLE_SPEAKER2CHATBOX(self): @@ -992,6 +1000,8 @@ class Config: self._MAX_MIC_THRESHOLD = 2000 self._MAX_SPEAKER_THRESHOLD = 4000 + self._WATCHDOG_TIMEOUT = 30 + self._WATCHDOG_INTERVAL = 1 # Read Write self._ENABLE_TRANSLATION = False diff --git a/src-python/model.py b/src-python/model.py index 9c8ac248..4773d9d5 100644 --- a/src-python/model.py +++ b/src-python/model.py @@ -28,6 +28,7 @@ from models.translation.translation_utils import checkCTranslate2Weight, downloa from models.transcription.transcription_whisper import checkWhisperWeight, downloadWhisperWeight from models.overlay.overlay import Overlay from models.overlay.overlay_image import OverlayImage +from models.watchdog.watchdog import Watchdog from config import config @@ -101,6 +102,7 @@ class Model: self.mic_mute_status = None self.mic_mute_status_check = None self.kks = kakasi() + self.watchdog = Watchdog(config.WATCHDOG_TIMEOUT, config.WATCHDOG_INTERVAL) def checkCTranslatorCTranslate2ModelWeight(self): return checkCTranslate2Weight(config.PATH_LOCAL, config.CTRANSLATE2_WEIGHT_TYPE) @@ -780,4 +782,13 @@ class Model: def shutdownOverlay(self): self.overlay.shutdownOverlay() + def startWatchdog(self): + self.watchdog.start() + + def feedWatchdog(self): + self.watchdog.feed() + + def stopWatchdog(self): + self.watchdog.stop() + model = Model() \ No newline at end of file diff --git a/src-python/models/watchdog/watchdog.py b/src-python/models/watchdog/watchdog.py new file mode 100644 index 00000000..10b5b9e1 --- /dev/null +++ b/src-python/models/watchdog/watchdog.py @@ -0,0 +1,30 @@ +import os +import time +from threading import Thread, Event +from utils import printLog + +class Watchdog: + def __init__(self, timeout:int=60, interval:int=1): + self.timeout = timeout + self.interval = interval + self.last_feed_time = time.time() + self._stop_event = Event() + self._watchdog_thread = Thread(target=self._watchdog_loop) + + def start(self): + self._watchdog_thread.start() + + def stop(self): + self._stop_event.set() + self._watchdog_thread.join() + + def feed(self): + self.last_feed_time = time.time() + + def _watchdog_loop(self): + while not self._stop_event.is_set(): + if time.time() - self.last_feed_time > self.timeout: + printLog("Watchdog timeout! Shutting down...") + os._exit(1) + + time.sleep(self.interval) \ No newline at end of file diff --git a/src-python/webui_controller.py b/src-python/webui_controller.py index 49433bea..50c388a2 100644 --- a/src-python/webui_controller.py +++ b/src-python/webui_controller.py @@ -1527,6 +1527,21 @@ class Controller: th_download.daemon = True th_download.start() + @staticmethod + def startWatchdog() -> dict: + model.startWatchdog() + return {"status":200, "result":True} + + @staticmethod + def feedWatchdog() -> dict: + model.feedWatchdog() + return {"status":200, "result":True} + + @staticmethod + def stopWatchdog() -> dict: + model.stopWatchdog() + return {"status":200, "result":True} + def init(self, *args, **kwargs) -> None: printLog("Start Initialization") @@ -1591,4 +1606,6 @@ class Controller: device_manager.setCallbackMicDeviceList(self.updateMicDeviceList) device_manager.setCallbackSpeakerDeviceList(self.updateSpeakerDeviceList) - printLog("End Initialization") \ No newline at end of file + printLog("End Initialization") + + self.startWatchdog() \ No newline at end of file diff --git a/src-python/webui_mainloop.py b/src-python/webui_mainloop.py index 57da7aa2..800f4058 100644 --- a/src-python/webui_mainloop.py +++ b/src-python/webui_mainloop.py @@ -310,6 +310,10 @@ mapping = { # "/run/update_software": {"status": True, "variable":controller.updateSoftware}, # "/run/restart_software": {"status": True, "variable":controller.restartSoftware}, + + # "/run/start_watchdog": {"status": True, "variable":controller.startWatchdog}, + "/run/feed_watchdog": {"status": True, "variable":controller.feedWatchdog}, + # "/run/stop_watchdog": {"status": True, "variable":controller.stopWatchdog}, } class Main: @@ -333,7 +337,7 @@ class Main: th_receiver.daemon = True th_receiver.start() - def handleRequest(self, endpoint, data=None): + def handleRequest(self, endpoint, data=None) -> tuple: handler = mapping.get(endpoint) if handler is None: response = "Invalid endpoint"