From ed98623cdaa0f1cc1f8bd9e32584c3c842663a80 Mon Sep 17 00:00:00 2001 From: KenanZhu <3471685733@qq.com> Date: Fri, 26 Jun 2026 09:56:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(timer):=20=E6=96=B0=E5=A2=9E=20ALTimerTask?= =?UTF-8?q?Poller=20=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E8=BD=AE=E8=AF=A2?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/ALTimerTaskPoller.py | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/gui/ALTimerTaskPoller.py diff --git a/src/gui/ALTimerTaskPoller.py b/src/gui/ALTimerTaskPoller.py new file mode 100644 index 0000000..343f03a --- /dev/null +++ b/src/gui/ALTimerTaskPoller.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +""" +Copyright (c) 2026 KenanZhu. +All rights reserved. + +This software is provided "as is", without any warranty of any kind. +You may use, modify, and distribute this file under the terms of the MIT License. +See the LICENSE file for details. +""" +import queue + +from PySide6.QtCore import ( + QObject, + QTimer, + Signal, + Slot +) + +from gui.ALMainWorker import TimerTaskWorker + + +class ALTimerTaskPoller(QObject): + + taskRunning = Signal(dict) + taskFinished = Signal(bool, dict) + taskExecuted = Signal(dict) + taskError = Signal(dict) + + def __init__( + self, + parent=None, + input_queue: queue.Queue = None, + output_queue: queue.Queue = None, + config_paths: list = None + ): + + super().__init__(parent) + self.__input_queue = input_queue or queue.Queue() + self.__output_queue = output_queue or queue.Queue() + self.__config_paths = config_paths or [] + self.__task_queue = queue.Queue() + self.__timer = QTimer(self) + self.__timer.timeout.connect(self.__poll) + self.__worker = None + self.__stopped = False + + def start( + self + ): + + self.__stopped = False + self.__timer.start(500) + + def stop( + self + ): + + self.__stopped = True + self.__timer.stop() + self.__cleanupWorker() + + def enqueue( + self, + task: dict + ): + + self.__task_queue.put(task) + + def isRunning( + self + ) -> bool: + + return self.__worker is not None + + def updateConfigPaths( + self, + config_paths: list + ): + + self.__config_paths = config_paths + + @Slot() + def __poll( + self + ): + + if self.__worker is not None: + return + try: + task = self.__task_queue.get_nowait() + self.__timer.stop() + self.taskRunning.emit(task) + self.__worker = TimerTaskWorker( + task, + self.__input_queue, + self.__output_queue, + self.__config_paths + ) + self.__worker.timerTaskWorkerIsFinished.connect(self.__onFinished) + self.__worker.start() + except queue.Empty: + pass + + @Slot(bool, dict) + def __onFinished( + self, + is_error: bool, + task: dict + ): + + self.__worker.timerTaskWorkerIsFinished.disconnect(self.__onFinished) + self.__worker.wait(1000) + self.__worker.deleteLater() + self.__worker = None + task["executed"] = True + self.taskFinished.emit(is_error, task) + if not is_error: + self.taskExecuted.emit(task) + else: + self.taskError.emit(task) + if not self.__stopped: + self.__timer.start(500) + + def __cleanupWorker( + self + ): + + if self.__worker is None: + return + try: + self.__worker.timerTaskWorkerIsFinished.disconnect(self.__onFinished) + except (TypeError, RuntimeError): + pass + self.__worker.wait(2000) + self.__worker.deleteLater() + self.__worker = None