已经可以顺利运行
This commit is contained in:
@@ -9,6 +9,9 @@ from ..Convention.Runtime.GlobalConfig import *
|
|||||||
from ..Convention.Runtime.Architecture import Architecture
|
from ..Convention.Runtime.Architecture import Architecture
|
||||||
|
|
||||||
config = ProjectConfig()
|
config = ProjectConfig()
|
||||||
|
APP_CONFIG = {
|
||||||
|
"docs_url": "/docs",
|
||||||
|
}
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
@@ -34,11 +37,12 @@ async def lifespan(app: FastAPI):
|
|||||||
config.Log("Info", "关闭应用完成...")
|
config.Log("Info", "关闭应用完成...")
|
||||||
# db.close()
|
# db.close()
|
||||||
|
|
||||||
def generate_app(APP_CONFIG: dict) -> FastAPI:
|
def generate_app(kwargs: dict) -> FastAPI:
|
||||||
'''
|
'''
|
||||||
生成FastAPI应用
|
生成FastAPI应用
|
||||||
'''
|
'''
|
||||||
app = FastAPI(**APP_CONFIG, lifespan=lifespan)
|
kwargs.update(**APP_CONFIG)
|
||||||
|
app = FastAPI(**kwargs, lifespan=lifespan)
|
||||||
|
|
||||||
# 添加并发限制中间件
|
# 添加并发限制中间件
|
||||||
app.add_middleware(ConcurrencyLimitMiddleware)
|
app.add_middleware(ConcurrencyLimitMiddleware)
|
||||||
@@ -46,7 +50,7 @@ def generate_app(APP_CONFIG: dict) -> FastAPI:
|
|||||||
# 注册路由
|
# 注册路由
|
||||||
app.include_router(callback.router, prefix="/api", tags=["callback"])
|
app.include_router(callback.router, prefix="/api", tags=["callback"])
|
||||||
app.include_router(health.router, tags=["health"])
|
app.include_router(health.router, tags=["health"])
|
||||||
ImportPlugins(app, config.FindItem("plugin_dir", "Plugins/"))
|
ImportPlugins(app, config.FindItem("plugin_dir", "Plugins"))
|
||||||
|
|
||||||
# 注册至框架中
|
# 注册至框架中
|
||||||
Architecture.Register(FastAPI, app, lambda: None)
|
Architecture.Register(FastAPI, app, lambda: None)
|
||||||
@@ -60,9 +64,12 @@ app: FastAPI = generate_app(config.FindItem("app_config", {}))
|
|||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
"""根路径"""
|
"""根路径"""
|
||||||
|
app_name = config.FindItem("app_name", "Application")
|
||||||
|
app_version = config.FindItem("app_version", "0.0.0")
|
||||||
|
config.SaveProperties()
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"message": config.FindItem("app_name", "Application"),
|
"message": app_name,
|
||||||
"version": config.FindItem("app_version", "0.0.0"),
|
"version": app_version,
|
||||||
"status": "running"
|
"status": "running"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Submodule Convention updated: a79ba69443...8121899d32
@@ -1,3 +1,6 @@
|
|||||||
|
from pickle import NONE
|
||||||
|
|
||||||
|
from ..Convention.Runtime.Config import *
|
||||||
from ..Convention.Runtime.GlobalConfig import ProjectConfig
|
from ..Convention.Runtime.GlobalConfig import ProjectConfig
|
||||||
from ..Convention.Runtime.Architecture import Architecture
|
from ..Convention.Runtime.Architecture import Architecture
|
||||||
from ..Convention.Runtime.File import ToolFile
|
from ..Convention.Runtime.File import ToolFile
|
||||||
@@ -19,7 +22,7 @@ class DatabaseModel(BaseModel):
|
|||||||
class PluginInterface(ABC):
|
class PluginInterface(ABC):
|
||||||
plugin_instances: Dict[str, "PluginInterface"] = {}
|
plugin_instances: Dict[str, "PluginInterface"] = {}
|
||||||
|
|
||||||
def callback(self, message: str, chat_id: int, user_id: int) -> str:
|
async def callback(self, message: str, chat_id: int, user_id: int) -> str|None:
|
||||||
'''
|
'''
|
||||||
继承后重写该方法接受消息并返回消息
|
继承后重写该方法接受消息并返回消息
|
||||||
返回空字符串代表不进行反馈
|
返回空字符串代表不进行反馈
|
||||||
@@ -27,9 +30,8 @@ class PluginInterface(ABC):
|
|||||||
message: 消息内容
|
message: 消息内容
|
||||||
chat_id: 会话ID
|
chat_id: 会话ID
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
Returns:
|
|
||||||
str: 消息内容
|
|
||||||
'''
|
'''
|
||||||
|
config.Log("Warning", f"插件{self.__class__.__name__}未实现callback方法")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def execute(self, path:str) -> Optional[APIRouter]:
|
def execute(self, path:str) -> Optional[APIRouter]:
|
||||||
@@ -39,7 +41,7 @@ class PluginInterface(ABC):
|
|||||||
'''
|
'''
|
||||||
Architecture.Register(self.__class__, self, self.wake_up, *self.dependencies())
|
Architecture.Register(self.__class__, self, self.wake_up, *self.dependencies())
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
router.get(path)(self.generate_router_callback())
|
router.post(path)(self.generate_router_callback())
|
||||||
# 在数据库保证必要的表和列存在
|
# 在数据库保证必要的表和列存在
|
||||||
db = get_db()
|
db = get_db()
|
||||||
db_model = self.register_db_model()
|
db_model = self.register_db_model()
|
||||||
@@ -54,8 +56,8 @@ class PluginInterface(ABC):
|
|||||||
'''
|
'''
|
||||||
继承后重写该方法生成路由回调函数
|
继承后重写该方法生成路由回调函数
|
||||||
'''
|
'''
|
||||||
async def callback(*args: Any, **kwargs: Any) -> Any:
|
async def callback(message: str, chat_id: int, user_id: int) -> Any:
|
||||||
pass
|
return await self.callback(message, chat_id, user_id)
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
def dependencies(self) -> List[Type]:
|
def dependencies(self) -> List[Type]:
|
||||||
@@ -83,7 +85,16 @@ class PluginInterface(ABC):
|
|||||||
'''
|
'''
|
||||||
return DatabaseModel()
|
return DatabaseModel()
|
||||||
|
|
||||||
def ImportPlugins(app: FastAPI, plugin_dir:str = "Plugins/") -> None:
|
def is_enable_plugin(self) -> bool:
|
||||||
|
'''
|
||||||
|
继承后重写该方法判断是否启用该插件
|
||||||
|
'''
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_plugin_tag(self) -> str:
|
||||||
|
return "plugin"
|
||||||
|
|
||||||
|
def ImportPlugins(app: FastAPI, plugin_dir:str = "Plugins") -> None:
|
||||||
'''
|
'''
|
||||||
导入插件
|
导入插件
|
||||||
|
|
||||||
@@ -91,26 +102,31 @@ def ImportPlugins(app: FastAPI, plugin_dir:str = "Plugins/") -> None:
|
|||||||
app: FastAPI应用
|
app: FastAPI应用
|
||||||
plugin_dir: 插件目录
|
plugin_dir: 插件目录
|
||||||
'''
|
'''
|
||||||
plugin_tool_dir = ToolFile(plugin_dir)
|
plugin_tool_dir = ToolFile(plugin_dir)|None
|
||||||
if plugin_tool_dir.Exists() == False:
|
if plugin_tool_dir.Exists() == False:
|
||||||
plugin_tool_dir.MustExistsPath()
|
plugin_tool_dir.MustExistsPath()
|
||||||
return
|
return
|
||||||
if plugin_tool_dir.IsDir() == False:
|
if plugin_tool_dir.IsDir() == False:
|
||||||
config.Log("Error", f"插件目录不是目录: {plugin_tool_dir.GetFullPath()}")
|
config.Log("Error", f"插件目录不是目录: {plugin_tool_dir.GetFullPath()}")
|
||||||
return
|
return
|
||||||
for file in plugin_tool_dir.DirIter():
|
for dir_name, sub_dirs, files in plugin_tool_dir.DirWalk():
|
||||||
if file.endswith(".py") and not file.startswith("__"):
|
for file_name in files:
|
||||||
module_name = file[:-3]
|
module_file = ToolFile(dir_name)|file_name
|
||||||
try:
|
if file_name.endswith(".py") and not file_name.startswith("__"):
|
||||||
module = importlib.import_module(module_name)
|
try:
|
||||||
for class_name in dir(module):
|
module = importlib.import_module(f"{module_file.GetFullPath().replace(".py", '').replace('/', '.').replace('\\', '.')}")
|
||||||
plugin_class = getattr(module, class_name)
|
for class_name in dir(module):
|
||||||
if issubclass(plugin_class, PluginInterface):
|
plugin_class = getattr(module, class_name)
|
||||||
plugin = plugin_class()
|
if not isinstance(plugin_class, type):
|
||||||
router = plugin.execute(f"/{module_name}")
|
continue
|
||||||
if router:
|
if issubclass(plugin_class, PluginInterface):
|
||||||
app.include_router(router, prefix=f"/api", tags=[module_name])
|
plugin = plugin_class()
|
||||||
except Exception as e:
|
if plugin.is_enable_plugin() == False:
|
||||||
config.Log("Error", f"加载插件{module_name}失败: {e}")
|
continue
|
||||||
|
router = plugin.execute(f"/{module_file}")
|
||||||
|
if router:
|
||||||
|
app.include_router(router, prefix=f"/api", tags=[plugin.get_plugin_tag()])
|
||||||
|
except Exception as e:
|
||||||
|
config.Log("Error", f"{ConsoleFrontColor.RED}加载插件 {module_file} 失败: {e}{ConsoleFrontColor.RESET}")
|
||||||
|
|
||||||
__all__ = ["ImportPlugins", "PluginInterface", "DatabaseModel"]
|
__all__ = ["ImportPlugins", "PluginInterface", "DatabaseModel"]
|
||||||
@@ -40,36 +40,42 @@ async def callback_receive(request: Request):
|
|||||||
# 解析指令
|
# 解析指令
|
||||||
content = callback_data.content
|
content = callback_data.content
|
||||||
command = content.split(" ")[0]
|
command = content.split(" ")[0]
|
||||||
|
message = content[len(command):].strip()
|
||||||
config.Log("Info", f"识别指令: command={command}")
|
config.Log("Info", f"识别指令: command={command}")
|
||||||
|
|
||||||
# TODO: 处理指令
|
# 处理指令
|
||||||
return await handle_command(command, content, callback_data.chatid, callback_data.creator)
|
result = await handle_command(command, message, callback_data.chatid, callback_data.creator)
|
||||||
|
if result:
|
||||||
|
return JSONResponse({"result": "ok", "message": result})
|
||||||
|
else:
|
||||||
|
return JSONResponse({"result": "ok"})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
config.Log("Error", f"处理Callback异常: {e}", exc_info=True)
|
config.Log("Error", f"处理Callback异常: {e}")
|
||||||
if ALWAYS_RETURN_OK:
|
if ALWAYS_RETURN_OK:
|
||||||
return JSONResponse({"result": "ok"})
|
return JSONResponse({"result": "ok"})
|
||||||
else:
|
else:
|
||||||
return JSONResponse({"result": "error", "message": str(e)})
|
return JSONResponse({"result": "error", "message": str(e)})
|
||||||
|
|
||||||
|
|
||||||
async def handle_command(command: str, content: str,
|
async def handle_command(command: str, message: str,
|
||||||
chat_id: int, user_id: int) -> str:
|
chat_id: int, user_id: int) -> str|None:
|
||||||
"""处理游戏指令
|
"""处理指令
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command: 指令
|
command: 指令
|
||||||
content: 消息内容
|
message: 消息内容
|
||||||
chat_id: 会话ID
|
chat_id: 会话ID
|
||||||
user_id: 用户ID
|
user_id: 用户ID
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
回复文本
|
回复文本或None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
plugin = PluginInterface.plugin_instances.get(command, None)
|
plugin = PluginInterface.plugin_instances.get(command, None)
|
||||||
if plugin:
|
if plugin:
|
||||||
return plugin.callback(content, chat_id, user_id)
|
config.Log("Info", f"已找到插件注册指令: {command}, class: {plugin.__class__.__name__}")
|
||||||
|
return await plugin.callback(message, chat_id, user_id)
|
||||||
else:
|
else:
|
||||||
return f"❌ 未识别指令: {command}"
|
return f"❌ 未识别指令: {command}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -1,18 +1,21 @@
|
|||||||
# README
|
# PWF
|
||||||
|
|
||||||
|
Plugin-based Web Framework
|
||||||
|
|
||||||
## Clone
|
## Clone
|
||||||
|
|
||||||
use recursive
|
add as submodule
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone --recursive <repository_url>
|
git init
|
||||||
|
git submodule add <repository_url> PWF
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repository_url>
|
git clone <repository_url> PWF
|
||||||
cd Convention
|
cd PWF/Convention
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,6 +25,8 @@ use
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python app.py
|
python app.py
|
||||||
|
# from PWF.Application.app import main
|
||||||
|
# main()
|
||||||
```
|
```
|
||||||
|
|
||||||
to start and generate **Assets** Folder(generate by [ProjectConfig](Convention/Runtime/GlobalConfig.py))
|
to start and generate **Assets** Folder(generate by [ProjectConfig](Convention/Runtime/GlobalConfig.py))
|
||||||
@@ -38,7 +43,6 @@ just because program not running to the place where argument been referenced
|
|||||||
|
|
||||||
### Commandline and Config
|
### Commandline and Config
|
||||||
|
|
||||||
- **--main-webhook-url** main target of the message will be send, **needed**
|
|
||||||
- **--host** default: 0.0.0.0
|
- **--host** default: 0.0.0.0
|
||||||
- **--port** default: 8000
|
- **--port** default: 8000
|
||||||
- **--verbose** default: false
|
- **--verbose** default: false
|
||||||
@@ -46,7 +50,7 @@ just because program not running to the place where argument been referenced
|
|||||||
### Only Config
|
### Only Config
|
||||||
|
|
||||||
- **max_concurrent_requests** default: 100
|
- **max_concurrent_requests** default: 100
|
||||||
- **database_path** file on [Assets](Assets), default: db.db
|
- **database_path** file on Assets, default: db.db
|
||||||
- **plugin_dir** where plugins load, default: Plugins
|
- **plugin_dir** where plugins load, default: Plugins
|
||||||
- **always_return_ok** default: true
|
- **always_return_ok** default: true
|
||||||
|
|
||||||
@@ -58,13 +62,11 @@ from CoreModules.plugin_interface import PluginInterface, DatabaseModel
|
|||||||
|
|
||||||
class MyPlugin(PluginInterface):
|
class MyPlugin(PluginInterface):
|
||||||
def generate_router_callback(self):
|
def generate_router_callback(self):
|
||||||
"""生成路由回调函数,必需实现"""
|
|
||||||
async def callback():
|
async def callback():
|
||||||
return {"message": "Hello from MyPlugin"}
|
return {"message": "Hello from MyPlugin"}
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
def register_db_model(self):
|
def register_db_model(self):
|
||||||
"""注册数据库模型,可选实现"""
|
|
||||||
return DatabaseModel(
|
return DatabaseModel(
|
||||||
table_name="my_plugin_table",
|
table_name="my_plugin_table",
|
||||||
column_names=["id", "data", "created_at"],
|
column_names=["id", "data", "created_at"],
|
||||||
@@ -76,10 +78,8 @@ class MyPlugin(PluginInterface):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def dependencies(self):
|
def dependencies(self):
|
||||||
"""定义依赖的插件类,可选实现"""
|
return []
|
||||||
return [] # 返回空列表表示无依赖
|
|
||||||
|
|
||||||
def wake_up(self):
|
def wake_up(self):
|
||||||
"""依赖插件注册完成后调用,可选实现"""
|
|
||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user