# pyright: reportArgumentType=false import asyncio from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.interval import IntervalTrigger from astrbot.api.event import MessageChain from astrbot.api.star import Context from astrbot.api import logger from astrbot.api import AstrBotConfig from .jx3api_data import JX3APIService from .sqlite import AsyncSQLiteDB class AsyncTask: """ 基于 APScheduler 的后台异步监控任务管理类 """ def __init__(self, context: Context, config: AstrBotConfig, jx3api: JX3APIService, sqlite: AsyncSQLiteDB): self.context = context self.conf = config self.jx3fun = jx3api self.sql = sqlite self.server = self.conf.get("server", "梦江南") self.scheduler = AsyncIOScheduler() self.tasks = {} logger.info(f"初始化推送功能成功") """===================== 本地读写 =====================""" async def set_local_data(self, key: str, value): try: allowed = {"kfts", "xwts", "smts", "ctts"} if key not in allowed: raise ValueError("非法字段") await self.sql.update( "tuishong", { key: value, }, "id=?", (1,) ) except Exception as e: logger.error(f"数据写入失败:{e}") async def get_local_data(self, key: str, default: int=0): try: allowed = {"kfts", "xwts", "smts", "ctts"} if key not in allowed: return default data = await self.sql.select_one( "tuishong", "id=?", (1,) ) if data: return data.get(key, default) else: return default except Exception as e: logger.error(f"数据读取失败:{e}") """===================== 通用后台任务 =====================""" async def _job_common(self, fetch_func, task_key: str, namefun: str): state = self.tasks[task_key] try: data = await fetch_func() if not isinstance(data, dict): raise ValueError("fetch_func 返回数据不是 dict") state["state_new"] = data.get("status") if state["state_old"] != state["state_new"]: message_chain = MessageChain().message(data.get("data")) for umo in state["umos"]: await self.context.send_message(umo, message_chain) await self.set_local_data(task_key, state["state_new"]) state["state_old"] = state["state_new"] except asyncio.CancelledError: # 调度器 shutdown 时的正常路径 raise except (KeyError, TypeError, ValueError) as e: logger.error(f"{namefun} 数据结构异常: {e}") except Exception as e: logger.exception(f"{namefun} 后台任务执行异常") """===================== 初始化任务 =====================""" async def init_tasks(self): settings = [ ("kfts", "开服监控", lambda: self.jx3fun.kaifu(self.server)), ("xwts", "新闻资讯", lambda: self.jx3fun.xinwen(1)), ("smts", "刷马消息", lambda: self.jx3fun.shuamamsg(self.server,type="horse",subtype="foreshow")), ("ctts", "赤兔消息", lambda: self.jx3fun.shuamamsg(self.server,type="chitu-horse",subtype="share_msg")), ] for key, name, fetch in settings: conf = self.conf.get(key, {}) state_old = await self.get_local_data(key, default=False) self.tasks[key] = { "enable": conf.get("enable", True), "interval": conf.get("time", 60), "umos": conf.get("umos", []), "state_old": state_old, "state_new": state_old } if self.tasks[key]["enable"]: if self.tasks[key]["umos"]: self._add_scheduler(key, name, fetch) else: logger.warning(f"{name} 推送对象为空,任务未启动") if not self.scheduler.running: self.scheduler.start() logger.info("后台监控调度器已启动") """===================== 调度操作 =====================""" def _add_scheduler(self, key, namefun, fetch_func): if self.scheduler.get_job(key): self.scheduler.remove_job(key) interval = self.tasks[key]["interval"] self.scheduler.add_job( func=self._job_common, trigger=IntervalTrigger(seconds=interval), id=key, args=[fetch_func, key, namefun] ) logger.info(f"{namefun}后台任务启动成功,周期:{interval}s") def stop_all_tasks(self): """ 停止并移除所有任务 """ try: self.scheduler.remove_all_jobs() for key in self.tasks: self.tasks[key]["enable"] = False logger.info("已停止全部后台任务") except Exception as e: logger.error(f"停止全部后台任务失败:{e}") async def destroy(self): try: self.stop_all_tasks() if self.scheduler.running: self.scheduler.shutdown(wait=False) self.tasks.clear() logger.info("后台调度器已销毁") except Exception as e: logger.error(f"销毁调度器失败:{e}") async def get_task_info(self, key: str) -> str: try: t = self.tasks[key] return ( f"功能:{key}\n" f"启用:{t['enable']}\n" f"周期:{t['interval']} 秒\n" f"旧状态:{t['state_old']}\n" f"推送对象:{t['umos']}" ) except Exception as e: return f"读取后台配置失败:{e}"