HEX
Server: Apache/2.4.63 (Unix)
System: Linux TOMS-220NAS 4.4.302+ #86009 SMP Wed Nov 26 18:19:17 CST 2025 x86_64
User: flavio87 (1026)
PHP: 8.3.27
Disabled: NONE
Upload Files
File: //var/packages/SupportService/target/python_modules/action_handler/action_handler.py
from typing import Optional, Any, Awaitable
import asyncio
import json


class MainTaskNotImplemented(Exception):
    pass


class MainTaskRedefined(Exception):
    pass


class ActionHandler:
    def __init__(self, debug: bool = False):
        self._main_task = None
        self._tasks = list()
        self._main_task_done = False
        self.debug = debug

    @property
    def is_main_task_done(self) -> bool:
        return self._main_task_done

    def update_progress(self, progress: Optional[Any] = None, upload: bool = True) -> None:
        if not upload:
            return
        print(json.dumps({"progress": progress}), flush=True)

    async def _run_tasks(self, request: Any):
        if self._main_task is None:
            raise MainTaskNotImplemented

        task_coroutines = [self._main_task(request)]
        for task in self._tasks:
            if task.__code__.co_argcount == 0:
                task_coroutines.append(task())
            else:
                task_coroutines.append(task(request))
        try:
            result = await asyncio.gather(*task_coroutines)
            print(json.dumps({"result": result[0]}), flush=True)
        except Exception as exception:
            if self.debug:
                raise exception
            print(json.dumps({
                "exception": {
                    "source": "Action",
                    "type": type(exception).__name__,
                    "message": str(exception),
                }
            }), flush=True)

    def run(self, request: Any):
        asyncio.run(self._run_tasks(request))

    def main_task(self, timeout=None) -> Awaitable[Any]:
        def decorator(f: Awaitable[Any]) -> None:
            async def wrapper(*args, **kwargs) -> Any:
                try:
                    self._main_task_done = False
                    return await asyncio.wait_for(f(*args, **kwargs), timeout=timeout)
                except Exception as exception:
                    raise exception
                finally:
                    self._main_task_done = True
            if self._main_task is not None:
                raise MainTaskRedefined
            self._main_task = wrapper
        return decorator

    def task(self) -> Awaitable[Any]:
        def decorator(f: Awaitable[Any]):
            self._tasks.append(f)
            return f
        return decorator