Compare commits
9 Commits
16ef75c3ce
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 89de330e2d | |||
| cd54036ab7 | |||
| 9cb259f2c7 | |||
| ca3cf114e3 | |||
| ac68bb27a3 | |||
| 36324398c3 | |||
| 7deef9092a | |||
| 4d3d841dda | |||
| 6c53a3a18f |
@@ -22,7 +22,7 @@ class DatabaseModel(BaseModel):
|
|||||||
class PluginInterface(ABC):
|
class PluginInterface(ABC):
|
||||||
plugin_instances: Dict[str, "PluginInterface"] = {}
|
plugin_instances: Dict[str, "PluginInterface"] = {}
|
||||||
|
|
||||||
async def callback(self, message: str, chat_id: int, user_id: int) -> str|None:
|
async def callback(self, message: str|None|Literal[""], chat_id: int, user_id: int) -> str|None:
|
||||||
'''
|
'''
|
||||||
继承后重写该方法接受消息并返回消息
|
继承后重写该方法接受消息并返回消息
|
||||||
返回空字符串代表不进行反馈
|
返回空字符串代表不进行反馈
|
||||||
@@ -35,35 +35,87 @@ class PluginInterface(ABC):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
@final
|
@final
|
||||||
def execute(self, path:str) -> Optional[APIRouter]:
|
def register_table(self, db_model: DatabaseModel) -> None:
|
||||||
|
db = get_db()
|
||||||
|
cursor = db.conn.cursor()
|
||||||
|
sql = f"CREATE TABLE IF NOT EXISTS {db_model.table_name} ({', '.join([f'{name} {field_def}' for name, field_def in db_model.column_defs.items()])})"
|
||||||
|
config.Log("Info", f"{ConsoleFrontColor.LIGHTMAGENTA_EX}为表 {db_model.table_name} 创建: {sql}{ConsoleFrontColor.RESET}")
|
||||||
|
try:
|
||||||
|
cursor.execute(sql)
|
||||||
|
except Exception as e:
|
||||||
|
config.Log("Error", f"{ConsoleFrontColor.RED}为表 {db_model.table_name} 创建失败: {e}{ConsoleFrontColor.RESET}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
cursor.execute(f"PRAGMA table_info({db_model.table_name})")
|
||||||
|
existing_columns = {row["name"] for row in cursor.fetchall()}
|
||||||
|
except Exception as e:
|
||||||
|
config.Log("Error", f"{ConsoleFrontColor.RED}查询表 {db_model.table_name} 列信息失败: {e}{ConsoleFrontColor.RESET}")
|
||||||
|
return
|
||||||
|
|
||||||
|
constraint_keywords = ("PRIMARY KEY", "FOREIGN KEY", "UNIQUE", "CHECK")
|
||||||
|
for column_name, column_def in db_model.column_defs.items():
|
||||||
|
column_name_upper = column_name.upper()
|
||||||
|
column_def_upper = column_def.upper()
|
||||||
|
if any(keyword in column_name_upper for keyword in constraint_keywords) or any(
|
||||||
|
column_def_upper.startswith(keyword) for keyword in constraint_keywords
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
if " " in column_name or "(" in column_name:
|
||||||
|
continue
|
||||||
|
if column_name in existing_columns:
|
||||||
|
continue
|
||||||
|
alter_sql = f"ALTER TABLE {db_model.table_name} ADD COLUMN {column_name} {column_def}"
|
||||||
|
config.Log(
|
||||||
|
"Info",
|
||||||
|
f"{ConsoleFrontColor.LIGHTMAGENTA_EX}为表 {db_model.table_name} 添加缺失列: {alter_sql}{ConsoleFrontColor.RESET}",
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
cursor.execute(alter_sql)
|
||||||
|
except Exception as e:
|
||||||
|
config.Log("Error", f"{ConsoleFrontColor.RED}为表 {db_model.table_name} 添加列 {column_name} 失败: {e}{ConsoleFrontColor.RESET}")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
db.conn.commit()
|
||||||
|
except Exception as e:
|
||||||
|
config.Log("Error", f"{ConsoleFrontColor.RED}提交表 {db_model.table_name} 列更新失败: {e}{ConsoleFrontColor.RESET}")
|
||||||
|
|
||||||
|
@final
|
||||||
|
def execute(self) -> Optional[APIRouter]:
|
||||||
'''
|
'''
|
||||||
继承后是否返回路由决定是否启动该插件
|
继承后是否返回路由决定是否启动该插件
|
||||||
若返回None, 则不启动该插件
|
若返回None, 则不启动该插件
|
||||||
'''
|
'''
|
||||||
Architecture.Register(self.__class__, self, self.wake_up, *self.dependencies())
|
|
||||||
router = APIRouter()
|
|
||||||
router.post(path)(self.generate_router_callback())
|
|
||||||
# 在数据库保证必要的表和列存在
|
|
||||||
db = get_db()
|
|
||||||
db_model = self.register_db_model()
|
|
||||||
if db_model:
|
|
||||||
cursor = db.conn.cursor()
|
|
||||||
sql = f"CREATE TABLE IF NOT EXISTS {db_model.table_name} ({', '.join([f'{name} {field_def}' for name, field_def in db_model.column_defs.items()])})"
|
|
||||||
config.Log("Info", f"{ConsoleFrontColor.LIGHTMAGENTA_EX}为表 {db_model.table_name} 创建: {sql}{ConsoleFrontColor.RESET}")
|
|
||||||
try:
|
|
||||||
cursor.execute(sql)
|
|
||||||
except Exception as e:
|
|
||||||
config.Log("Error", f"{ConsoleFrontColor.RED}为表 {db_model.table_name} 创建失败: {e}{ConsoleFrontColor.RESET}")
|
|
||||||
|
|
||||||
|
def setup() -> None:
|
||||||
|
# 在数据库保证必要的表和列存在
|
||||||
|
db_model = self.register_db_model()
|
||||||
|
if db_model is None:
|
||||||
|
pass
|
||||||
|
elif isinstance(db_model, DatabaseModel):
|
||||||
|
self.register_table(db_model)
|
||||||
|
else:
|
||||||
|
for model in db_model:
|
||||||
|
self.register_table(model)
|
||||||
|
self.wake_up()
|
||||||
|
|
||||||
|
Architecture.Register(self.__class__, self, setup, *self.dependencies())
|
||||||
|
router = APIRouter()
|
||||||
|
router.post(f"/{self.__class__.__name__}/callback")(self.generate_router_callback())
|
||||||
|
if self.generate_router_illustrated_guide() is not None:
|
||||||
|
router.get(f"/{self.__class__.__name__}")(self.generate_router_illustrated_guide())
|
||||||
return router
|
return router
|
||||||
|
|
||||||
def generate_router_callback(self) -> Callable|Coroutine:
|
def generate_router_callback(self) -> Callable|Coroutine:
|
||||||
'''
|
'''
|
||||||
继承后重写该方法生成路由回调函数
|
继承后重写该方法生成路由回调函数
|
||||||
'''
|
'''
|
||||||
async def callback(message: str, chat_id: int, user_id: int) -> Any:
|
return self.callback
|
||||||
return await self.callback(message, chat_id, user_id)
|
|
||||||
return callback
|
def generate_router_illustrated_guide(self) -> Callable|Coroutine|None:
|
||||||
|
'''
|
||||||
|
继承后重写该方法生成渲染图鉴与攻略网页的函数
|
||||||
|
'''
|
||||||
|
return None
|
||||||
|
|
||||||
def dependencies(self) -> List[Type]:
|
def dependencies(self) -> List[Type]:
|
||||||
'''
|
'''
|
||||||
@@ -89,7 +141,7 @@ class PluginInterface(ABC):
|
|||||||
config.Log("Info", f"插件{self.__class__.__name__}已注册命令{command}")
|
config.Log("Info", f"插件{self.__class__.__name__}已注册命令{command}")
|
||||||
PluginInterface.plugin_instances[command] = self
|
PluginInterface.plugin_instances[command] = self
|
||||||
|
|
||||||
def register_db_model(self) -> Optional[DatabaseModel]:
|
def register_db_model(self) -> List[DatabaseModel]|DatabaseModel|None:
|
||||||
'''
|
'''
|
||||||
继承后重写该方法注册数据库模型
|
继承后重写该方法注册数据库模型
|
||||||
'''
|
'''
|
||||||
@@ -172,7 +224,7 @@ def ImportPlugins(app: FastAPI, plugin_dir:str = "Plugins") -> None:
|
|||||||
plugin = plugin_class()
|
plugin = plugin_class()
|
||||||
if plugin.is_enable_plugin() == False:
|
if plugin.is_enable_plugin() == False:
|
||||||
continue
|
continue
|
||||||
router = plugin.execute(f"/{module_file.GetFullPath().replace(".py", '')}/{class_name}")
|
router = plugin.execute()
|
||||||
if router:
|
if router:
|
||||||
app.include_router(router, prefix=f"/api", tags=[plugin.get_plugin_tag()])
|
app.include_router(router, prefix=f"/api", tags=[plugin.get_plugin_tag()])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from ..Convention.Runtime.Architecture import Architecture
|
|||||||
|
|
||||||
from fastapi import APIRouter, Request
|
from fastapi import APIRouter, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
import re
|
||||||
|
|
||||||
from ..CoreModules.models import CallbackRequest
|
from ..CoreModules.models import CallbackRequest
|
||||||
from ..CoreModules.plugin_interface import PluginInterface
|
from ..CoreModules.plugin_interface import PluginInterface
|
||||||
@@ -21,13 +22,25 @@ async def callback_verify():
|
|||||||
logger.Log("Info", "收到Callback验证请求")
|
logger.Log("Info", "收到Callback验证请求")
|
||||||
return JSONResponse({"result": "ok"})
|
return JSONResponse({"result": "ok"})
|
||||||
|
|
||||||
|
# 机器人名称模式(用于从@消息中提取,兼容半角/全角空格)
|
||||||
|
AT_PATTERN = re.compile(r'@[^\s]+[\s\u3000]+(.+)', re.DOTALL)
|
||||||
|
|
||||||
|
def parse_message_after_at(message: str) -> str:
|
||||||
|
# 去除首尾空格
|
||||||
|
message = message.strip()
|
||||||
|
|
||||||
|
# 尝试提取@后的内容
|
||||||
|
at_match = AT_PATTERN.search(message)
|
||||||
|
if at_match:
|
||||||
|
return at_match.group(1).strip()
|
||||||
|
return message
|
||||||
|
|
||||||
@router.post("/callback/construct")
|
@router.post("/callback/construct")
|
||||||
async def callback_receive_construct(callback_data: CallbackRequest):
|
async def callback_receive_construct(callback_data: CallbackRequest):
|
||||||
"""以构造好的Callback消息进行处理, 已知方式"""
|
"""以构造好的Callback消息进行处理, 已知方式"""
|
||||||
try:
|
try:
|
||||||
# 解析指令
|
# 解析指令
|
||||||
content = callback_data.content
|
content = parse_message_after_at(callback_data.content)
|
||||||
command = content.split(" ")[0]
|
command = content.split(" ")[0]
|
||||||
message = content[len(command):].strip()
|
message = content[len(command):].strip()
|
||||||
logger.Log("Info", f"识别指令: command={command}")
|
logger.Log("Info", f"识别指令: command={command}")
|
||||||
@@ -65,7 +78,7 @@ async def callback_receive(request: Request):
|
|||||||
return JSONResponse({"result": "error", "message": str(e)})
|
return JSONResponse({"result": "error", "message": str(e)})
|
||||||
|
|
||||||
# 解析指令
|
# 解析指令
|
||||||
content = callback_data.content
|
content = parse_message_after_at(callback_data.content)
|
||||||
command = content.split(" ")[0]
|
command = content.split(" ")[0]
|
||||||
message = content[len(command):].strip()
|
message = content[len(command):].strip()
|
||||||
logger.Log("Info", f"识别指令: command={command}")
|
logger.Log("Info", f"识别指令: command={command}")
|
||||||
@@ -103,6 +116,9 @@ async def handle_command(command: str, message: str,
|
|||||||
if plugin:
|
if plugin:
|
||||||
logger.Log("Info", f"已找到插件注册指令: {command}, class: {plugin.__class__.__name__}")
|
logger.Log("Info", f"已找到插件注册指令: {command}, class: {plugin.__class__.__name__}")
|
||||||
return await plugin.callback(message, chat_id, user_id)
|
return await plugin.callback(message, chat_id, user_id)
|
||||||
|
elif "default" in PluginInterface.plugin_instances:
|
||||||
|
logger.Log("Info", f"未找到插件注册指令: {command}, 使用默认插件: {PluginInterface.plugin_instances["default"].__class__.__name__}")
|
||||||
|
return await PluginInterface.plugin_instances["default"].callback(command+" "+message, chat_id, user_id)
|
||||||
else:
|
else:
|
||||||
return f"❌ 未识别指令: {command}"
|
return f"❌ 未识别指令: {command}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
3
swagger-ui-bundle.js
Normal file
3
swagger-ui-bundle.js
Normal file
File diff suppressed because one or more lines are too long
3
swagger-ui.css
Normal file
3
swagger-ui.css
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user