From e7f938769b1c445f6a62a9c2105bbc48b0bc9b84 Mon Sep 17 00:00:00 2001 From: xiaoQQya Date: Fri, 4 Apr 2025 17:49:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugin):=20=E4=B8=BA=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20webhook=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/run.py | 37 +++++++++++++++++++++++++++++++++++++ decorators.py | 28 ++++++++++++++++++++++++++++ plugins/README.md | 8 ++++++++ 3 files changed, 73 insertions(+) create mode 100644 decorators.py diff --git a/app/run.py b/app/run.py index ae22fe1..acea619 100644 --- a/app/run.py +++ b/app/run.py @@ -282,6 +282,43 @@ def delete_file(): return jsonify(response) +def get_hook_actions(plugins): + hook_actions = {} + for _, plugin in plugins.items(): + for name in dir(plugin): + method = getattr(plugin, name) + if callable(method) and hasattr(method, "__hook_action_name__"): + hook_actions[getattr(method, "__hook_action_name__")] = method + return hook_actions + + +@app.route("/webhook", methods=["GET", "POST"]) +def webhook(): + # 验证用户名和密码 + data = read_json() + username = data["webui"]["username"] + password = data["webui"]["password"] + if (username != request.args.get("username")) or ( + password != request.args.get("password") + ): + logging.info(f">>> 用户 {username} webhook 认证失败") + return jsonify({"error": "认证失败"}) + + try: + action = request.args.get("action") + plugins, _, _ = Config.load_plugins(data.get("plugins", {})) + hook_actions = get_hook_actions(plugins) + if action in hook_actions: + cookies = Config.get_cookies(data["cookie"]) + account = Quark(cookies[0], 0) if cookies else None + args = request.args + body = request.get_json() if request.mimetype == "application/json" else {} + hook_actions[action](account=account, **args, **body) + except Exception as e: + logging.error(f">>> webhook 处理报错:{e}") + return Response(status=200) + + # 定时任务执行的函数 def run_python(args): logging.info(f">>> 定时运行任务") diff --git a/decorators.py b/decorators.py new file mode 100644 index 0000000..5147124 --- /dev/null +++ b/decorators.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +# -*- encoding: utf-8 -*- +""" +@File : decorators.py +@Desc : 定义装饰器 +@Version : v1.0 +@Time : 2025/04/04 +@Author : xiaoQQya +@Contact : xiaoQQya@126.com +""" +import functools + + +def hook_action(name): + """回调动作装饰器 + + Args: + name (str): 动作名称 + """ + def decorator(func): + func.__hook_action_name__ = name + + @functools.wraps(func) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + return wrapper + + return decorator diff --git a/plugins/README.md b/plugins/README.md index 53b13e1..4048f9a 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -29,6 +29,14 @@ * `task` 是一个字典,包含任务信息。如果需要修改任务参数,返回修改后的 `task` 字典; * 无修改则不返回或返回 `None`。 +## 插件回调 + +插件支持配置 webhook 回调事件,使用方式如下: + +1. 使用 `@hook_action("xxx_hook")` 装饰器修饰需要接收回调事件的方法,其中装饰器参数为回调事件类型,建议使用 `插件名称_事件类型_hook` 命名,避免不同插件之间类型重复; + +2. 在外部通过 `http://host:port/webhook?username=xxx&password=xxx&action=xxx_hook` 触发回调事件,支持 GET 与 POST 方法,POST 方法只支持 `application/json` 类型参数; + ## 插件示例 参考 [emby.py](emby.py)