File: //usr/local/packages/@appstore/SupportService/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