AnP/Python/Models/QueuesModel.py

79 lines
2.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Self, Any, Callable, Sequence, Optional
from threading import Thread, Lock
from Utils.Checks import Check
from Utils.Common import Common
class QueueItemModel:
def __init__(self:Self, i:int, callback:Callable[[Callable[[], None]], None], *arguments:list[Any|None]) -> None:
self.i:int = i
self.callback:Callable[[Callable[[], None]], None] = callback
self.arguments:list[Any|None] = arguments
self.executing:bool = False
self.thread:Thread|None = None
class QueuesModel:
def __init__(self:Self, key:str, inputs:Optional[int|dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
if Check.is_integer(inputs):
inputs = {"maximum" : inputs}
self.key:str = key
self.items:dict[int, QueueItemModel] = {}
self.i:int = 0
self.p:int = 0
self.maximum:int = Common.get_value(("maximum", "maximum_concurrent", "maximum_simultaneous"), inputs, 1)
self.current:int = 0
def add(self:Self, callback:Callable[[Callable[[], None]], None], *arguments:list[Any|None]) -> int|None:
i:int|None = None
if Check.is_function(callback):
with Lock():
self.items[i := self.i] = QueueItemModel(self.i, callback, *arguments)
self.i += 1
self.next()
return i
def cancel(self:Self, i:int) -> bool:
with Lock():
if i in self.items and not self.items[i].executing:
del self.items[i]
return True
return False
def cancel_all(self:Self) -> None:
with Lock():
for i in list(self.items.keys()):
if not self.items[i].executing:
del self.items[i]
def __end(self:Self, p:int) -> None:
with Lock():
self.current -= 1
del self.items[p]
self.next()
def next(self:Self) -> None:
while self.p < self.i and self.current < self.maximum:
item:QueueItemModel
p:int|None = None
with Lock():
p = min((item.i for item in self.items.values() if not item.executing), default=None)
if p is None:
return
item = self.items[p]
item.executing = True
self.p = p
self.current += 1
item.thread = Thread(target = lambda:item.callback(lambda *results:self.__end(p, *results), *item.arguments))
item.thread.start()