From d5ccd105a21a6ee61fc45ac6e0b56c5ce93d1958 Mon Sep 17 00:00:00 2001 From: snowykami Date: Sun, 20 Oct 2024 03:05:15 +0800 Subject: [PATCH] :sparkles: add: nonebot-plugin-gotify --- config/default.yml | 3 +- .../nonebot_plugin_gotify/__init__.py | 109 ++++++++++++++++++ .../nonebot_plugin_gotify/adapter_ctx.py | 12 ++ .../nonebot_plugin_gotify/config.py | 22 ++++ .../nonebot_plugin_gotify/gotify.py | 23 ++++ .../nonebot_plugin_gotify/on.py | 0 .../nonebot_plugin_gotify/r.txt | 0 7 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/__init__.py create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/adapter_ctx.py create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/config.py create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/gotify.py create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/on.py create mode 100644 src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/r.txt diff --git a/config/default.yml b/config/default.yml index ed78f4b8b..13a74c032 100644 --- a/config/default.yml +++ b/config/default.yml @@ -5,4 +5,5 @@ nonebot: nickname: [ "liteyuki" ] default_language: zh driver: ~fastapi+~httpx+~websockets - alconna_use_command_start: true \ No newline at end of file + alconna_use_command_start: true + gotify_token: "empty token" \ No newline at end of file diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/__init__.py b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/__init__.py new file mode 100644 index 000000000..fdc6b9563 --- /dev/null +++ b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/__init__.py @@ -0,0 +1,109 @@ +import asyncio +import aiohttp +from nonebot import logger, on_message, Bot +from nonebot.internal.adapter import Event +from nonebot.plugin import PluginMetadata +from nonebot import get_driver + +from .adapter_ctx import Context +from .config import plugin_config, Config, NOTICE, MESSAGE +from .gotify import Message, msg_chan, fetch_msg + +__plugin_meta__ = PluginMetadata( + name="Gotify", + description="使用Gotify API发送消息", + usage="后台服务插件,无需用户交互", +) + +# on plugin load +driver = get_driver() + +async def push_thread(): + async with aiohttp.ClientSession() as session: + while True: + msg = await fetch_msg() + try: + logger.debug(f"Pushing message: {msg}") + async with session.post( + url=plugin_config.gotify_url + "/message", + params={"token": plugin_config.gotify_token}, + data={ + "title": msg.title, + "message": msg.message, + "priority": msg.priority, + }, + ) as resp: + if resp.status != 200: + logger.error( + f"Push message to server failed: {await resp.text()}" + ) + else: + logger.info(f"Push message to server success: {msg}") + except Exception as e: + logger.error(f"Push message to server failed: {e}") + +@driver.on_startup +async def start_push_thread(): + asyncio.create_task(push_thread()) + logger.info( + f"Gotify plugin loaded, server: {plugin_config.gotify_url}, token: {plugin_config.gotify_token}" + ) + +if MESSAGE in plugin_config.gotify_includes: + @on_message().handle() + async def _(event: Event): + ctx = Context( + user_id=event.get_user_id(), + nickname="", + message=event.get_plaintext(), + message_type=event.get_type(), + ) + ctx.handle(event) + + msg_chan << Message( + title=plugin_config.gotify_title.format(**ctx.model_dump()), + message=plugin_config.gotify_message.format(**ctx.model_dump()), + ) + +if NOTICE in plugin_config.gotify_includes: + @driver.on_startup + async def startup(): + if NOTICE in plugin_config.gotify_includes: + msg_chan << Message( + title=plugin_config.gotify_nickname, + message="Bot started", + priority=plugin_config.gotify_priority, + ) + + + @driver.on_shutdown + async def shutdown(): + if NOTICE in plugin_config.gotify_includes: + msg_chan << Message( + title=plugin_config.gotify_nickname, + message="Bot stopped", + priority=plugin_config.gotify_priority, + ) + + + @driver.on_bot_connect + async def bot_connect(bot: Bot): + if NOTICE in plugin_config.gotify_includes: + msg_chan << Message( + title=plugin_config.gotify_nickname, + message=f"Bot connected: {bot.self_id}", + priority=plugin_config.gotify_priority, + ) + + + @driver.on_bot_disconnect + async def bot_disconnect(bot: Bot): + if NOTICE in plugin_config.gotify_includes: + msg_chan << Message( + title=plugin_config.gotify_nickname, + message=f"Bot disconnected: {bot.self_id}", + priority=plugin_config.gotify_priority, + ) + + + diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/adapter_ctx.py b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/adapter_ctx.py new file mode 100644 index 000000000..30f2fed63 --- /dev/null +++ b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/adapter_ctx.py @@ -0,0 +1,12 @@ +from pydantic import BaseModel, field_validator + + +class Context(BaseModel): + user_id: str + nickname: str + message: str + message_type: str | None = None + + def handle(self, event): + pass + diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/config.py b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/config.py new file mode 100644 index 000000000..2bd057c61 --- /dev/null +++ b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/config.py @@ -0,0 +1,22 @@ +from nonebot import get_plugin_config +from pydantic import BaseModel, field_validator + +NOTICE = "notice" +MESSAGE = "message" + +class Config(BaseModel): + # required fields + gotify_token: str + + # optional fields + gotify_url: str = "http://127.0.0.1:40266" + gotify_priority: int = 5 + gotify_nickname: str = "NoneBot" + gotify_title: str = "{message_type}: {nickname}({user_id})" + gotify_message: str = "{message}" + gotify_includes: list[str, ...] = [NOTICE, MESSAGE] + + +plugin_config = get_plugin_config(Config) +if plugin_config.gotify_url.endswith("/"): + plugin_config.gotify_url = plugin_config.gotify_url[:-1] diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/gotify.py b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/gotify.py new file mode 100644 index 000000000..d8166fe13 --- /dev/null +++ b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/gotify.py @@ -0,0 +1,23 @@ +import asyncio +from asyncio import Future +from collections.abc import Coroutine +from typing import Any + +import aiohttp +from magicoca import Chan +from nonebot import logger +from pydantic import BaseModel + +from .config import plugin_config + +msg_chan = Chan["Message"]() + + +class Message(BaseModel): + title: str + message: str + priority: int = plugin_config.gotify_priority + + +def fetch_msg() -> Future[Any]: + return asyncio.get_event_loop().run_in_executor(func=msg_chan.recv, executor=None) diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/on.py b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/on.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/r.txt b/src/liteyuki_plugins/nonebot/nonebot_plugins/nonebot_plugin_gotify/r.txt new file mode 100644 index 000000000..e69de29bb