""" Task Scheduler — real asyncio-based delayed execution """ import asyncio, json, datetime, traceback from typing import Callable _pending: list = [] # list of {"at": timestamp, "task": coroutine_fn, "desc": str, "chat_id": int} async def schedule_task(delay_seconds: float, desc: str, coro_fn, *args, **kwargs): """Schedule coro_fn(*args, **kwargs) to run after delay_seconds.""" async def runner(): await asyncio.sleep(delay_seconds) try: await coro_fn(*args, **kwargs) except Exception as e: print(f"[SCHEDULER] Task '{desc}' failed: {e}\n{traceback.format_exc()}") task = asyncio.create_task(runner()) _pending.append({"desc": desc, "at": datetime.datetime.now().timestamp() + delay_seconds, "task": task}) print(f"[SCHEDULER] Scheduled '{desc}' in {delay_seconds:.0f}s") return task def parse_delay(text: str) -> float | None: """Parse '5 minutes', '30 seconds', '1 hour', '2 mins' → seconds.""" import re text = text.lower().strip() patterns = [ (r'(\d+(?:\.\d+)?)\s*(?:hours?|hrs?|h)\b', 3600), (r'(\d+(?:\.\d+)?)\s*(?:minutes?|mins?|m)\b', 60), (r'(\d+(?:\.\d+)?)\s*(?:seconds?|secs?|s)\b', 1), ] total = 0 found = False for pat, mult in patterns: for m in re.finditer(pat, text): total += float(m.group(1)) * mult found = True return total if found else None