feat(plugin-schedule): add DB-driven plugin scheduler and xiuren scheduled push
This commit is contained in:
183
db/plugin_schedule_db.py
Normal file
183
db/plugin_schedule_db.py
Normal file
@@ -0,0 +1,183 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from db.base import BaseDBOperator
|
||||
from db.connection import DBConnectionManager
|
||||
|
||||
|
||||
class PluginScheduleDBOperator(BaseDBOperator):
|
||||
"""插件定时任务配置与日志表操作。"""
|
||||
|
||||
def __init__(self, db_manager: DBConnectionManager):
|
||||
super().__init__(db_manager)
|
||||
|
||||
def init_tables(self) -> bool:
|
||||
try:
|
||||
self.execute_update(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS t_plugin_schedules (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
plugin_name VARCHAR(128) NOT NULL,
|
||||
action_key VARCHAR(64) NOT NULL,
|
||||
action_name VARCHAR(128) NOT NULL,
|
||||
description VARCHAR(255) DEFAULT '',
|
||||
trigger_type VARCHAR(64) NOT NULL,
|
||||
trigger_config JSON NOT NULL,
|
||||
target_scope VARCHAR(64) NOT NULL DEFAULT 'all_enabled_groups',
|
||||
target_config JSON DEFAULT NULL,
|
||||
payload JSON DEFAULT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_plugin_action (plugin_name, action_key)
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
self.execute_update(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS t_plugin_schedule_logs (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
schedule_id BIGINT NOT NULL,
|
||||
triggered_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
summary VARCHAR(255) DEFAULT '',
|
||||
detail_json JSON DEFAULT NULL,
|
||||
INDEX idx_schedule_time (schedule_id, triggered_at)
|
||||
)
|
||||
"""
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"初始化插件调度表失败: {e}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _parse_json_field(row: Dict[str, Any], key: str):
|
||||
value = row.get(key)
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
row[key] = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
row[key] = {}
|
||||
elif value is None:
|
||||
row[key] = {}
|
||||
|
||||
def list_schedules(self) -> List[Dict[str, Any]]:
|
||||
rows = self.execute_query("SELECT * FROM t_plugin_schedules ORDER BY plugin_name, action_name") or []
|
||||
for row in rows:
|
||||
self._parse_json_field(row, "trigger_config")
|
||||
self._parse_json_field(row, "target_config")
|
||||
self._parse_json_field(row, "payload")
|
||||
return rows
|
||||
|
||||
def list_enabled_schedules(self) -> List[Dict[str, Any]]:
|
||||
rows = self.execute_query(
|
||||
"SELECT * FROM t_plugin_schedules WHERE enabled = 1 ORDER BY plugin_name, action_name"
|
||||
) or []
|
||||
for row in rows:
|
||||
self._parse_json_field(row, "trigger_config")
|
||||
self._parse_json_field(row, "target_config")
|
||||
self._parse_json_field(row, "payload")
|
||||
return rows
|
||||
|
||||
def get_schedule(self, schedule_id: int) -> Optional[Dict[str, Any]]:
|
||||
row = self.execute_query(
|
||||
"SELECT * FROM t_plugin_schedules WHERE id = %s",
|
||||
(schedule_id,),
|
||||
fetch_one=True,
|
||||
)
|
||||
if not row:
|
||||
return None
|
||||
self._parse_json_field(row, "trigger_config")
|
||||
self._parse_json_field(row, "target_config")
|
||||
self._parse_json_field(row, "payload")
|
||||
return row
|
||||
|
||||
def upsert_default_schedule(self, data: Dict[str, Any]) -> bool:
|
||||
try:
|
||||
sql = """
|
||||
INSERT INTO t_plugin_schedules (
|
||||
plugin_name, action_key, action_name, description,
|
||||
trigger_type, trigger_config, target_scope, target_config, payload, enabled
|
||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
action_name = VALUES(action_name),
|
||||
description = VALUES(description)
|
||||
"""
|
||||
params = (
|
||||
data["plugin_name"],
|
||||
data["action_key"],
|
||||
data["action_name"],
|
||||
data.get("description", ""),
|
||||
data["trigger_type"],
|
||||
json.dumps(data.get("trigger_config", {}), ensure_ascii=False),
|
||||
data.get("target_scope", "all_enabled_groups"),
|
||||
json.dumps(data.get("target_config", {}), ensure_ascii=False),
|
||||
json.dumps(data.get("payload", {}), ensure_ascii=False),
|
||||
1 if data.get("enabled", False) else 0,
|
||||
)
|
||||
return self.execute_update(sql, params)
|
||||
except Exception as e:
|
||||
logger.error(f"upsert 插件默认调度失败: {e}, data={data}")
|
||||
return False
|
||||
|
||||
def update_schedule(self, schedule_id: int, updates: Dict[str, Any]) -> bool:
|
||||
fields = []
|
||||
values = []
|
||||
|
||||
for key in (
|
||||
"action_name",
|
||||
"description",
|
||||
"trigger_type",
|
||||
"target_scope",
|
||||
"enabled",
|
||||
):
|
||||
if key in updates:
|
||||
fields.append(f"{key} = %s")
|
||||
if key == "enabled":
|
||||
values.append(1 if updates[key] else 0)
|
||||
else:
|
||||
values.append(updates[key])
|
||||
|
||||
for key in ("trigger_config", "target_config", "payload"):
|
||||
if key in updates:
|
||||
fields.append(f"{key} = %s")
|
||||
values.append(json.dumps(updates.get(key, {}), ensure_ascii=False))
|
||||
|
||||
if not fields:
|
||||
return True
|
||||
|
||||
values.append(schedule_id)
|
||||
sql = f"UPDATE t_plugin_schedules SET {', '.join(fields)} WHERE id = %s"
|
||||
return self.execute_update(sql, tuple(values))
|
||||
|
||||
def create_log(self, schedule_id: int, status: str, summary: str, detail: Dict[str, Any]) -> bool:
|
||||
sql = """
|
||||
INSERT INTO t_plugin_schedule_logs (schedule_id, status, summary, detail_json)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
"""
|
||||
params = (
|
||||
schedule_id,
|
||||
status,
|
||||
summary,
|
||||
json.dumps(detail or {}, ensure_ascii=False),
|
||||
)
|
||||
return self.execute_update(sql, params)
|
||||
|
||||
def get_logs(self, schedule_id: int, limit: int = 100) -> List[Dict[str, Any]]:
|
||||
rows = self.execute_query(
|
||||
"""
|
||||
SELECT * FROM t_plugin_schedule_logs
|
||||
WHERE schedule_id = %s
|
||||
ORDER BY triggered_at DESC
|
||||
LIMIT %s
|
||||
""",
|
||||
(schedule_id, int(limit)),
|
||||
) or []
|
||||
for row in rows:
|
||||
self._parse_json_field(row, "detail_json")
|
||||
return rows
|
||||
Reference in New Issue
Block a user