diff --git a/config.gen.ini b/config.gen.ini index d6ff1a3..9c5bcfe 100644 --- a/config.gen.ini +++ b/config.gen.ini @@ -13,6 +13,7 @@ port = 1080 [basic] ipv6 = False cache_uri = mem:// +sentry_dsn = abcd [misskey] web_domain = misskey2tg.xtaolabs.com diff --git a/defs/misskey.py b/defs/misskey.py index 6afaabe..3d35f5c 100644 --- a/defs/misskey.py +++ b/defs/misskey.py @@ -361,7 +361,7 @@ async def send_group( async def send_update( host: str, cid: int, note: Note, topic_id: Optional[int], show_second: bool -) -> List[Message]: +) -> Message | list[Message]: files = list(note.files) if note.reply: files.extend(iter(note.reply.files)) @@ -375,14 +375,12 @@ async def send_update( file_type = file.type url = await fetch_document(file) if file_type.startswith("image"): - return [await send_photo(host, cid, url, note, topic_id, show_second)] + return await send_photo(host, cid, url, note, topic_id, show_second) elif file_type.startswith("video"): - return [await send_video(host, cid, url, note, topic_id, show_second)] + return await send_video(host, cid, url, note, topic_id, show_second) elif file_type.startswith("audio"): - return [await send_audio(host, cid, url, note, topic_id, show_second)] + return await send_audio(host, cid, url, note, topic_id, show_second) else: - return [ - await send_document(host, cid, url, note, topic_id, show_second) - ] + return await send_document(host, cid, url, note, topic_id, show_second) case _: return await send_group(host, cid, files, note, topic_id, show_second) diff --git a/defs/sentry.py b/defs/sentry.py new file mode 100644 index 0000000..b7528fa --- /dev/null +++ b/defs/sentry.py @@ -0,0 +1,45 @@ +from subprocess import run, PIPE +from time import time + +import sentry_sdk +from pyrogram import Client +from sentry_sdk.integrations.aiohttp import AioHttpIntegration +from sentry_sdk.integrations.httpx import HttpxIntegration +from sentry_sdk.integrations.logging import LoggingIntegration +from sentry_sdk.integrations.redis import RedisIntegration +from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration + +from glover import sentry_dsn + +sentry_sdk_report_time = time() +sentry_sdk_git_hash = ( + run("git rev-parse HEAD", stdout=PIPE, shell=True, check=True) + .stdout.decode() + .strip() +) +sentry_sdk.init( + sentry_dsn, + send_default_pii=True, + traces_sample_rate=1.0, + release=sentry_sdk_git_hash, + environment="production", + integrations=[ + AioHttpIntegration(), + HttpxIntegration(), + LoggingIntegration(), + RedisIntegration(), + SqlalchemyIntegration(), + ], +) + + +async def sentry_init_id(bot: Client): + if not bot.me: + bot.me = await bot.get_me() + data = { + "id": bot.me.id, + "username": bot.me.username, + "name": bot.me.first_name, + "ip_address": "{{auto}}", + } + sentry_sdk.set_user(data) diff --git a/glover.py b/glover.py index e7bf35d..fa4e641 100644 --- a/glover.py +++ b/glover.py @@ -8,6 +8,7 @@ api_hash: str = "" # [Basic] ipv6: Union[bool, str] = "False" cache_uri: str = "mem://" +sentry_dsn: str = "" # [misskey] web_domain: str = "" admin: int = 0 @@ -18,6 +19,7 @@ api_id = config.getint("pyrogram", "api_id", fallback=api_id) api_hash = config.get("pyrogram", "api_hash", fallback=api_hash) ipv6 = config.get("basic", "ipv6", fallback=ipv6) cache_uri = config.get("basic", "cache_uri", fallback=cache_uri) +sentry_dsn = config.get("basic", "sentry_dsn", fallback=sentry_dsn) web_domain = config.get("misskey", "web_domain", fallback=web_domain) admin = config.getint("misskey", "admin", fallback=admin) try: diff --git a/misskey_init.py b/misskey_init.py index 0a3bca4..fed97fa 100644 --- a/misskey_init.py +++ b/misskey_init.py @@ -4,6 +4,7 @@ from asyncio import sleep, Lock from concurrent.futures import ThreadPoolExecutor from typing import Optional, Union +import sentry_sdk from aiohttp import ClientConnectorError from firebase_admin.exceptions import InvalidArgumentError from mipa.exception import WebSocketNotConnected @@ -51,6 +52,7 @@ from init import bot, logs, sqlite class MisskeyBot(commands.Bot): def __init__(self, user: User): super().__init__() + self._BotBase__on_error = self.__on_error self.user_id: int = user.user_id self.instance_user_id: str = user.instance_user_id self.tg_user: User = user @@ -133,7 +135,7 @@ class MisskeyBot(commands.Bot): executor, func, self.tg_user.fcm_token, notice ) except InvalidArgumentError: - logs.error(f"{self.tg_user.user_id} 无效的 FCM Token") + logs.warning(f"{self.tg_user.user_id} 无效的 FCM Token") except Exception as e: logs.error(e) @@ -189,6 +191,11 @@ class MisskeyBot(commands.Bot): if self.tg_user.fcm_token: await self.send_fcm(send_fcm_quote, notice) + @staticmethod + async def __on_error(event_method: str) -> None: + logs.exception(f"MisskeyBot 执行 {event_method} 出错", exc_info=True) + sentry_sdk.capture_exception() + misskey_bot_map: dict[int, MisskeyBot] = {} diff --git a/models/services/revoke.py b/models/services/revoke.py index 05f5c20..5541392 100644 --- a/models/services/revoke.py +++ b/models/services/revoke.py @@ -22,7 +22,8 @@ class RevokeAction: return int(cid), [int(mid) for mid in ids.split(",")] @staticmethod - async def push(uid: int, note_id: str, messages: list[Message]): + async def push(uid: int, note_id: str, messages: Message | list[Message]): + messages = [messages] if isinstance(messages, Message) else messages await cache.set( f"sub:{uid}:{note_id}", RevokeAction.encode_messages(messages), diff --git a/modules/sentry.py b/modules/sentry.py new file mode 100644 index 0000000..ddf4b8b --- /dev/null +++ b/modules/sentry.py @@ -0,0 +1,4 @@ +from init import bot +from defs.sentry import sentry_init_id + +bot.loop.create_task(sentry_init_id(bot)) diff --git a/requirements.txt b/requirements.txt index 75c4710..30d4271 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ aiosqlite==0.19.0 PyYAML==6.0.1 aiofiles==23.1.0 pillow==10.0.0 -cashews==6.2.0 -alembic==1.11.1 +cashews[redis]==6.2.0 +alembic==1.11.2 firebase-admin==6.2.0 +sentry-sdk==1.29.2