11
This commit is contained in:
+18
-6
@@ -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
@@ -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.
@@ -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插件已卸载/停用")
|
||||||
Reference in New Issue
Block a user