This commit is contained in:
qsc
2025-12-05 12:54:25 +08:00
parent 34b8f7267d
commit 2ebf83680b
5 changed files with 88 additions and 37 deletions
+18 -6
View File
@@ -17,26 +17,26 @@ class AsyncSQLite:
async def fetch_one(self, sql: str, params=None): async def fetch_one(self, sql: str, params=None):
await self.init() await self.init()
async with self.conn.execute(sql, params or ()) as cursor: async with self.conn.execute(sql, params or ()) as cursor: # type: ignore
row = await cursor.fetchone() row = await cursor.fetchone()
return dict(row) if row else None return dict(row) if row else None
async def fetch_all(self, sql: str, params=None): async def fetch_all(self, sql: str, params=None):
await self.init() await self.init()
async with self.conn.execute(sql, params or ()) as cursor: async with self.conn.execute(sql, params or ()) as cursor: # type: ignore
rows = await cursor.fetchall() rows = await cursor.fetchall()
return [dict(r) for r in rows] return [dict(r) for r in rows]
async def execute(self, sql: str, params=None): async def execute(self, sql: str, params=None):
await self.init() await self.init()
async with self.conn.execute(sql, params or ()): async with self.conn.execute(sql, params or ()): # type: ignore
await self.conn.commit() await self.conn.commit() # type: ignore
return True return True
async def executemany(self, sql: str, params_list): async def executemany(self, sql: str, params_list):
await self.init() await self.init()
await self.conn.executemany(sql, params_list) await self.conn.executemany(sql, params_list) # type: ignore
await self.conn.commit() await self.conn.commit() # type: ignore
return True return True
async def insert_record(self, table: str, data: dict): async def insert_record(self, table: str, data: dict):
@@ -56,3 +56,15 @@ class AsyncSQLite:
where_clause = " AND ".join(f"`{k}`=?" for k in where.keys()) where_clause = " AND ".join(f"`{k}`=?" for k in where.keys())
sql = f"DELETE FROM `{table}` WHERE {where_clause}" sql = f"DELETE FROM `{table}` WHERE {where_clause}"
return await self.execute(sql, tuple(where.values())) return await self.execute(sql, tuple(where.values()))
async def clear_table(self, table: str):
"""
清空指定表中的所有记录。
Args:
table: 要清空的表名。
Returns:
如果操作成功则返回 True。
"""
sql = f"DELETE FROM `{table}`"
# 使用 execute 函数执行 DELETE 语句
return await self.execute(sql)
+10 -10
View File
@@ -4,11 +4,11 @@ from typing import Dict, Any, Optional, List, Union
from astrbot.api import logger from astrbot.api import logger
from .request import APIClient from .request import APIClient
from .async_mysql import AsyncMySQL from .aiosqlite import AsyncSQLite
from .function_basic import load_template,flatten_field,extract_fields,gold_to_string from .function_basic import load_template,flatten_field,extract_fields,gold_to_string
class JX3Service: class JX3Service:
def __init__(self, api_config,db: AsyncMySQL ): def __init__(self, api_config,db: AsyncSQLite ):
self._api = APIClient() self._api = APIClient()
self._db = db self._db = db
self._api_config = api_config self._api_config = api_config
@@ -82,7 +82,7 @@ class JX3Service:
data: Optional[Dict[str, Any]] = await self._base_request( data: Optional[Dict[str, Any]] = await self._base_request(
"jx3_richang", "GET", params=params "jx3_richang", "GET", params=params
) )
logger.info(f"richang 接口返回数据: {data}")
if not data: if not data:
return_data["msg"] = "获取接口信息失败" return_data["msg"] = "获取接口信息失败"
return return_data return return_data
@@ -101,10 +101,10 @@ class JX3Service:
) )
# 安全地处理列表索引 # 安全地处理列表索引
luck = data.get('luck', [None, None, None]) luck = data.get('luck', [])
luck_msg = f"[宠物福缘]\n{luck[0] or ''},{luck[1] or ''},{luck[2] or ''}\n" luck_msg = f"[宠物福缘]\n{', '.join(luck)}\n"
card = data.get('card', [None, None, None]) card = data.get('card', [])
card_msg = f"[家园声望·加倍道具]\n{card[0] or ''},{card[1] or ''},{card[2] or ''}\n" card_msg = f"[家园声望·加倍道具]\n{', '.join(card)}\n"
team = data.get('team', [None, None, None]) team = data.get('team', [None, None, None])
team_msg = f"[武林通鉴·公共任务]\n{team[0] or ''}\n[武林通鉴·团队秘境]\n{team[2] or ''}\n" team_msg = f"[武林通鉴·公共任务]\n{team[0] or ''}\n[武林通鉴·团队秘境]\n{team[2] or ''}\n"
@@ -335,7 +335,7 @@ class JX3Service:
sql = """ sql = """
INSERT INTO searchdata INSERT INTO searchdata
(typeName, name, showName, picUrl, searchId, searchDescType) (typeName, name, showName, picUrl, searchId, searchDescType)
VALUES (%s, %s, %s, %s, %s, %s) VALUES (?, ?, ?, ?, ?, ?)
""" """
# 增强数据提取的安全性 # 增强数据提取的安全性
values_list = [ values_list = [
@@ -352,7 +352,7 @@ class JX3Service:
# 插入数据 # 插入数据
try: try:
await self._db.truncate_table("searchdata") await self._db.clear_table("searchdata")
await self._db.executemany(sql, values_list) await self._db.executemany(sql, values_list)
except Exception as e: except Exception as e:
logger.error(f"数据插入失败: {e}") logger.error(f"数据插入失败: {e}")
@@ -382,7 +382,7 @@ class JX3Service:
# 进一步从 DB 查找 ID # 进一步从 DB 查找 ID
try: try:
sql = "SELECT searchId FROM searchdata WHERE showName=%s" sql = "SELECT searchId FROM searchdata WHERE showName=?"
sqldata = await self._db.fetch_one(sql, (showName,)) sqldata = await self._db.fetch_one(sql, (showName,))
searchId = sqldata["searchId"] if sqldata else None searchId = sqldata["searchId"] if sqldata else None
except Exception as e: except Exception as e:
Binary file not shown.
+59 -20
View File
@@ -1,6 +1,9 @@
import json import json
import shutil
import asyncio import asyncio
import pathlib
from pathlib import Path from pathlib import Path
from typing import Union
from datetime import datetime from datetime import datetime
from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult, MessageChain from astrbot.api.event import filter, AstrMessageEvent, MessageEventResult, MessageChain
@@ -8,7 +11,7 @@ from astrbot.api.star import Context, Star, register, StarTools
from astrbot.api import logger from astrbot.api import logger
from astrbot.api import AstrBotConfig from astrbot.api import AstrBotConfig
from .core.async_mysql import AsyncMySQL from .core.aiosqlite import AsyncSQLite
from .core.jx3_service import JX3Service from .core.jx3_service import JX3Service
@@ -25,10 +28,22 @@ class Jx3ApiPlugin(Star):
#获取配置 #获取配置
self.conf = config self.conf = config
# 本地数据存储路径 # 本地数据存储路径
self.local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3") local_data_dir = StarTools.get_data_dir("astrbot_plugin_jx3")
# api数据文件 # 插件数据文件路径
self.api_file_path = Path(__file__).parent / "api_config.json" data_file_path = Path(__file__).parent / "data"
# 读取文件内容 # --- 调用函数完成检查和复制 ---
try:
self.file_local_data = self.check_and_copy_db(
local_data_dir=local_data_dir,
db_filename="local_data.db",
default_db_dir=data_file_path
)
except FileNotFoundError as e:
# 处理默认文件丢失的严重错误
logger.critical(f"插件初始化失败:{e}")
raise # 中断初始化
# 读取配置文件
self.api_file_path = Path(__file__).parent / "data" / "api_config.json"
with open(self.api_file_path, 'r', encoding='utf-8') as f: with open(self.api_file_path, 'r', encoding='utf-8') as f:
self.api_config = json.load(f) self.api_config = json.load(f)
# 初始化数据 # 初始化数据
@@ -39,24 +54,48 @@ class Jx3ApiPlugin(Star):
async def initialize(self): async def initialize(self):
"""可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。"""
# 数据库配置
db_config = {
'host': '38.12.28.24',
'port': 3306,
'user': 'asrtbot',
'password': 'qsc123456',
'db': 'asrtbot',
'charset': 'utf8mb4',
'autocommit': True
}
#创建类实例 #创建类实例
self.db = AsyncMySQL(db_config) self.db = AsyncSQLite(str(self.file_local_data))
self.jx3fun = JX3Service(self.api_config,self.db) self.jx3fun = JX3Service(self.api_config,self.db)
# 周期函数调用 # 周期函数调用
logger.info("jx3api插件创建实例完成") logger.info("jx3api插件创建实例完成")
def check_and_copy_db(self, local_data_dir: Union[str, Path], db_filename: str, default_db_dir: Union[str, Path]) -> pathlib.Path:
"""
检查本地数据目录中是否存在指定的数据库文件。
如果不存在,则从默认目录复制该文件。
Args:
local_data_dir: 目标数据库文件所在的文件夹路径。
db_filename: 数据库文件的名称 (例如: 'local_data.db')。
default_db_dir: 默认/源数据库文件所在的文件夹路径。
Returns:
最终的数据库文件的完整 pathlib.Path 对象。
Raises:
FileNotFoundError: 如果默认的源数据库文件不存在。
"""
# 目标路径
target_dir = pathlib.Path(local_data_dir)
target_file_path = target_dir / db_filename
# 源文件路径
source_file_path = pathlib.Path(default_db_dir) / db_filename
# 假设默认文件名为 local_data.db
if not target_file_path.exists():
logger.warning(f"本地数据库文件 {target_file_path.name} 不存在,正在从默认位置复制...")
# 1. 确保目标文件夹存在
target_dir.mkdir(parents=True, exist_ok=True)
# 2. 检查源文件是否存在
if not source_file_path.exists():
raise FileNotFoundError(f"默认数据库源文件未找到!请检查路径: {source_file_path}")
# 3. 复制文件
shutil.copy(source_file_path, target_file_path)
logger.info(f"数据库文件已成功复制到: {target_file_path}")
else:
logger.info(f"本地数据库文件 {target_file_path} 已存在,跳过复制。")
return target_file_path
def inidata(self): def inidata(self):
"""数据初始化""" """数据初始化"""
self.test_server = False self.test_server = False
@@ -114,7 +153,7 @@ class Jx3ApiPlugin(Star):
if data["code"] == 200: if data["code"] == 200:
yield event.plain_result(data["data"]) yield event.plain_result(data["data"])
else: else:
yield event.plain_result("msg") yield event.plain_result(data["msg"])
return return
except Exception as e: except Exception as e:
logger.error(f"功能函数执行错误: {e}") logger.error(f"功能函数执行错误: {e}")
@@ -129,7 +168,7 @@ class Jx3ApiPlugin(Star):
if data["code"] == 200: if data["code"] == 200:
yield event.plain_result(data["data"]) yield event.plain_result(data["data"])
else: else:
yield event.plain_result("msg") yield event.plain_result(data["msg"])
return return
except Exception as e: except Exception as e:
logger.error(f"功能函数执行错误: {e}") logger.error(f"功能函数执行错误: {e}")
@@ -295,7 +334,7 @@ class Jx3ApiPlugin(Star):
async def terminate(self): async def terminate(self):
"""可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。"""
await self.db.close_pool() await self.db.close()
# 后台进程销毁 # 后台进程销毁
self.kf_task.cancel() self.kf_task.cancel()
logger.info("jx3api插件已卸载/停用") logger.info("jx3api插件已卸载/停用")