Skip to content

Commit b681b7b

Browse files
committed
🐛 send StatusUpdateEvent after connected & 🔊 better logger & 🚨 make ruff happy
1 parent 4345dd1 commit b681b7b

File tree

7 files changed

+121
-67
lines changed

7 files changed

+121
-67
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
[![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://pydantic.dev)
1313
[![PyPI Version](https://img.shields.io/pypi/v/nonebot-plugin-all4one.svg?style=flat-square)](https://pypi.python.org/pypi/nonebot-plugin-all4one)
1414
[![OneBot 4A](https://img.shields.io/badge/OneBot-4A-black?style=flat-square)](https://onebot4all.vercel.app/)
15-
[![NoneBot Version](https://img.shields.io/badge/nonebot-2.3.0+-red.svg?style=flat-square)](https://v2.nonebot.dev/)
15+
[![NoneBot Version](https://img.shields.io/badge/nonebot-2.3.0+-red.svg?style=flat-square)](https://v2.nonebot.dev/)
1616
[![NoneBot Registry](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-all4one)](https://registry.nonebot.dev/plugin/nonebot-plugin-all4one:nonebot_plugin_all4one)
1717
[![Supported Adapters](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-all4one)](https://registry.nonebot.dev/plugin/nonebot-plugin-all4one:nonebot_plugin_all4one)
1818

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import importlib.metadata as importlib_metadata
2+
3+
# from importlib.resources import read_text
4+
5+
6+
def read_version() -> str:
7+
try:
8+
return importlib_metadata.version(__package__ or "nonebot_plugin_all4one")
9+
except importlib_metadata.PackageNotFoundError:
10+
return "0.1.0"
11+
# return read_text("nonebot_plugin_all4one", "VERSION").strip()
12+
13+
14+
__version__ = read_version()

nonebot_plugin_all4one/logger.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from nonebot.utils import logger_wrapper
2+
3+
log = logger_wrapper("041")

nonebot_plugin_all4one/middlewares/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
from pathlib import Path
33
from typing import Optional, cast
44

5-
from nonebot.log import logger
6-
5+
from ..logger import log
76
from .base import Middleware
87

98
MIDDLEWARE_MAP = {}
@@ -23,4 +22,4 @@
2322
):
2423
MIDDLEWARE_MAP[middleware.get_name()] = middleware
2524
except Exception:
26-
logger.warning(f"Failed to import {module_name}")
25+
log("WARNING", f"Failed to import {module_name}")

nonebot_plugin_all4one/middlewares/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ async def get_bot_self(self) -> BotSelf:
6060
user_id=self.self_id,
6161
**{
6262
"supported_actions": await self.get_supported_actions(),
63-
"supported_message_segments": await self.get_supported_message_segments(),
63+
"supported_message_segments": await self.get_supported_message_segments(), # noqa: E501
6464
},
6565
)
6666

@@ -100,7 +100,8 @@ async def send_message(
100100
"""发送消息
101101
102102
参数:
103-
detail_type: 发送的类型,可以为 private、group 或扩展的类型,和消息事件的 detail_type 字段对应
103+
detail_type: 发送的类型,可以为 private、group 或扩展的类型,
104+
和消息事件的 detail_type 字段对应
104105
user_id: 用户 ID,当 detail_type 为 private 时必须传入
105106
group_id: 群 ID,当 detail_type 为 group 时必须传入
106107
guild_id: Guild 群组 ID,当 detail_type 为 channel 时必须传入

nonebot_plugin_all4one/middlewares/onebot_v11.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ def get_platform(self):
5050
return "qq"
5151

5252
async def to_onebot_event(self, event: Event) -> list[OneBotEvent]:
53-
replaced_by_detail_type = (
54-
"notice_type",
55-
"message_type",
56-
"request_type",
57-
"meta_event_type",
58-
)
5953
should_be_str = (
6054
"message_id",
6155
"user_id",

nonebot_plugin_all4one/onebotimpl/__init__.py

Lines changed: 98 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
from functools import partial
55
from collections.abc import AsyncGenerator
66
from contextlib import asynccontextmanager
7-
from typing import Any, Union, Literal, Optional, cast
7+
from typing import Any, Union, Literal, ClassVar, Optional, cast
88
from asyncio import Task, Queue, sleep, gather, wait_for, create_task
99

1010
import msgpack
11-
from nonebot.log import logger
1211
from nonebot.adapters import Bot
1312
from nonebot.utils import escape_tag
1413
from nonebot.exception import WebSocketClosed
@@ -38,7 +37,9 @@
3837
WebSocketServerSetup,
3938
)
4039

40+
from ..logger import log
4141
from .utils import encode_data
42+
from ..__version__ import __version__
4243
from ..middlewares import MIDDLEWARE_MAP, Middleware
4344
from .config import (
4445
Config,
@@ -50,6 +51,10 @@
5051

5152

5253
class OneBotImplementation:
54+
USER_AGENT: ClassVar[str] = f"OneBot4All NoneBot-Plugin-All4One/{__version__}"
55+
ONEBOT_VERSION: ClassVar[str] = "A"
56+
IMPL_NAME: ClassVar[str] = "nonebot-plugin-all4one"
57+
5358
def __init__(self, driver: Driver):
5459
self.driver = driver
5560
self.config = Config(**self.driver.config.model_dump())
@@ -89,14 +94,10 @@ def register_middleware(self, middleware: type[Middleware]):
8994
"""注册一个中间件"""
9095
name = middleware.get_name()
9196
if name in self._middlewares:
92-
logger.opt(colors=True).warning(
93-
f'Middleware "<y>{escape_tag(name)}</y>" already exists'
94-
)
97+
log("WARNING", f'Middleware "<y>{escape_tag(name)}</y>" already exists')
9598
return
9699
self._middlewares[name] = middleware
97-
logger.opt(colors=True).info(
98-
f'Succeeded to load middleware "<y>{escape_tag(name)}</y>"'
99-
)
100+
log("INFO", f'Succeeded to load middleware "<y>{escape_tag(name)}</y>"')
100101

101102
async def _call_api(self, data: dict[str, Any]) -> Any:
102103
try:
@@ -190,9 +191,9 @@ async def get_version(
190191
kwargs: 扩展字段
191192
"""
192193
return {
193-
"impl": "nonebot-plugin-all4one",
194-
"version": "0.1.0",
195-
"onebot_version": "12",
194+
"impl": self.IMPL_NAME,
195+
"version": __version__,
196+
"onebot_version": self.ONEBOT_VERSION,
196197
}
197198

198199
def _check_access_token(
@@ -215,20 +216,20 @@ async def _ws_send(
215216
websocket: WebSocket,
216217
conn: Union[WebsocketConfig, WebsocketReverseConfig],
217218
) -> None:
218-
queue = Queue()
219+
queue = Queue[Event]()
219220
self.queues.append(queue)
220221
try:
221222
while True:
222223
event = await queue.get()
223-
await websocket.send(encode_data(event.dict(), conn.use_msgpack))
224+
await websocket.send(encode_data(event.model_dump(), conn.use_msgpack))
224225
except WebSocketClosed:
225-
logger.opt(colors=True).warning(
226-
"<y><bg #f8bbd0>WebSocket Closed</bg #f8bbd0></y>"
227-
)
228-
except Exception:
229-
logger.opt(colors=True).exception(
230-
"<r><bg #f8bbd0>Error while process data from websocket"
231-
". Trying to reconnect...</bg #f8bbd0></r>"
226+
log("WARNING", "<y>WebSocket Closed</y>")
227+
except Exception as e:
228+
log(
229+
"ERROR",
230+
"<r>Error while process data from websocket. "
231+
"Trying to reconnect...</r>",
232+
e,
232233
)
233234
finally:
234235
self.queues.remove(queue)
@@ -247,7 +248,7 @@ async def _ws_recv(self, websocket: WebSocket) -> None:
247248
if "echo" in data:
248249
echo = data["echo"]
249250
resp = await self._call_api(data)
250-
# 格式错误(包括实现不支持 MessagePack 的情况)、必要字段缺失或字段类型错误
251+
# 格式错误(包括实现不支持 MessagePack 的情况)、必要字段缺失或类型错误
251252
except (json.JSONDecodeError, msgpack.UnpackException):
252253
resp = {
253254
"status": "failed",
@@ -267,11 +268,13 @@ async def _ws_recv(self, websocket: WebSocket) -> None:
267268
resp["echo"] = echo
268269
await websocket.send(encode_data(resp, isinstance(raw_data, bytes)))
269270
except WebSocketClosed:
270-
logger.opt(colors=True).warning("WebSocket closed by peer")
271+
log("WARNING", "WebSocket closed by peer")
271272
# 与 WebSocket 服务器的连接发生了意料之外的错误
272-
except Exception:
273-
logger.opt(colors=True).exception(
274-
"<r><bg #f8bbd0>Error while process data from websocket</bg #f8bbd0></r>"
273+
except Exception as e:
274+
log(
275+
"ERROR",
276+
"<r>Error while process data from websocket</r>",
277+
e,
275278
)
276279

277280
async def _handle_http(
@@ -283,7 +286,7 @@ async def _handle_http(
283286
if response := self._check_access_token(request, conn.access_token):
284287
return response
285288

286-
# 如果收到不支持的 Content-Type 请求头,必须返回 HTTP 状态码 415 Unsupported Media Type
289+
# 如果收到不支持的 Content-Type 请求头,必须返回 HTTP 状态码 415
287290
content_type = request.headers.get("Content-Type")
288291
if content_type not in ("application/json", "application/msgpack"):
289292
return Response(415, content="Invalid Content-Type")
@@ -341,6 +344,19 @@ async def _handle_ws(self, conn: WebsocketConfig, websocket: WebSocket) -> None:
341344
conn.use_msgpack,
342345
)
343346
)
347+
await websocket.send(
348+
encode_data(
349+
StatusUpdateMetaEvent(
350+
id=uuid.uuid4().hex,
351+
time=datetime.now(),
352+
type="meta",
353+
detail_type="status_update",
354+
sub_type="",
355+
status=await self.get_status(),
356+
).model_dump(),
357+
conn.use_msgpack,
358+
)
359+
)
344360
t1 = create_task(self._ws_send(websocket, conn))
345361
t2 = create_task(self._ws_recv(websocket))
346362
await t2
@@ -351,22 +367,32 @@ async def _http_webhook(self, conn: HTTPWebhookConfig):
351367
"Content-Type": (
352368
"application/msgpack" if conn.use_msgpack else "application/json"
353369
),
354-
"User-Agent": "OneBot/12 NoneBot Plugin All4One/0.1.0",
355-
"X-OneBot-Version": "12",
356-
"X-Impl": "nonebot-plugin-all4one",
370+
"User-Agent": self.USER_AGENT,
371+
"X-OneBot-Version": self.ONEBOT_VERSION,
372+
"X-Impl": self.IMPL_NAME,
357373
}
358374
if conn.access_token:
359375
headers["Authorization"] = f"Bearer {conn.access_token}"
360-
queue = Queue()
376+
queue = Queue[Event]()
361377
self.queues.append(queue)
378+
await queue.put(
379+
StatusUpdateMetaEvent(
380+
id=uuid.uuid4().hex,
381+
time=datetime.now(),
382+
type="meta",
383+
detail_type="status_update",
384+
sub_type="",
385+
status=await self.get_status(),
386+
)
387+
)
362388
while True:
363389
try:
364390
event = await queue.get()
365391
request = Request(
366392
"POST",
367393
str(conn.url),
368394
headers=headers,
369-
content=encode_data(event.dict(), conn.use_msgpack),
395+
content=encode_data(event.model_dump(), conn.use_msgpack),
370396
)
371397
resp = await self.request(request)
372398
if resp.status_code == 200:
@@ -380,32 +406,33 @@ async def _http_webhook(self, conn: HTTPWebhookConfig):
380406
elif content_type == "application/json":
381407
data = json.loads(resp.content)
382408
else:
383-
logger.error("Invalid Content-Type")
409+
log("ERROR", "Invalid Content-Type")
384410
continue
385411
for action in data:
386412
await self._call_api(action)
387413
# 动作请求执行出错
388-
except Exception:
389-
logger.exception("HTTP Webhook Response action failed")
414+
except Exception as e:
415+
log("ERROR", "HTTP Webhook Response action failed", e)
390416
# 事件推送成功,并不做更多处理
391417
elif resp.status_code == 204:
392418
pass
393419
# 事件推送失败
394420
else:
395-
logger.error(f"HTTP Webhook event push failed: {resp}")
421+
log("ERROR", f"HTTP Webhook event push failed: {resp}")
396422
except (NotImplementedError, TypeError):
397-
logger.error(
398-
f"Current driver {self.driver.type} does not support http client"
423+
log(
424+
"ERROR",
425+
f"Current driver {self.driver.type} does not support http client",
399426
)
400427
self.queues.remove(queue)
401428
break
402-
except Exception:
403-
logger.exception("HTTP Webhook event push failed")
429+
except Exception as e:
430+
log("ERROR", "HTTP Webhook event push failed", e)
404431

405432
async def _websocket_rev(self, conn: WebsocketReverseConfig) -> None:
406433
headers = {
407-
"User-Agent": "OneBot/12 NoneBot Plugin All4One/0.1.0",
408-
"Sec-WebSocket-Protocol": "12.nonebot-plugin-all4one",
434+
"User-Agent": self.USER_AGENT,
435+
"Sec-WebSocket-Protocol": f"{self.ONEBOT_VERSION}.{self.IMPL_NAME}",
409436
}
410437
if conn.access_token:
411438
headers["Authorization"] = f"Bearer {conn.access_token}"
@@ -432,28 +459,44 @@ async def _websocket_rev(self, conn: WebsocketReverseConfig) -> None:
432459
conn.use_msgpack,
433460
)
434461
)
462+
await ws.send(
463+
encode_data(
464+
StatusUpdateMetaEvent(
465+
id=uuid.uuid4().hex,
466+
time=datetime.now(),
467+
type="meta",
468+
detail_type="status_update",
469+
sub_type="",
470+
status=await self.get_status(),
471+
).model_dump(),
472+
conn.use_msgpack,
473+
)
474+
)
435475
t1 = create_task(self._ws_send(ws, conn))
436476
t2 = create_task(self._ws_recv(ws))
437477
await t2
438478
t1.cancel()
439479
except WebSocketClosed:
440-
logger.opt(colors=True).warning(
441-
"<y><bg #f8bbd0>WebSocket Closed</bg #f8bbd0></y>"
442-
)
443-
except Exception:
444-
logger.opt(colors=True).exception(
445-
"<r><bg #f8bbd0>Error while process data from websocket"
446-
f"{escape_tag(str(conn.url))}. Trying to reconnect...</bg #f8bbd0></r>",
480+
log("WARNING", "<y>WebSocket Closed</y>")
481+
except Exception as e:
482+
log(
483+
"ERROR",
484+
"<r>Error while process data from websocket"
485+
f"{escape_tag(str(conn.url))}. Trying to reconnect...</r>",
486+
e,
447487
)
448488
except (NotImplementedError, TypeError):
449-
logger.error(
450-
f"Current driver {self.driver.type} does not support websocket server"
489+
log(
490+
"ERROR",
491+
f"Current driver {self.driver.type} "
492+
"does not support websocket server",
451493
)
452494
break
453495
except Exception:
454-
logger.opt(colors=True).warning(
455-
"<y><bg #f8bbd0>Error while setup websocket to "
456-
f"{escape_tag(str(conn.url))}. Trying to reconnect...</bg #f8bbd0></y>",
496+
log(
497+
"WARNING",
498+
"<y>Error while setup websocket to "
499+
f"{escape_tag(str(conn.url))}. Trying to reconnect...</y>",
457500
)
458501
await sleep(conn.reconnect_interval)
459502

@@ -502,7 +545,7 @@ def _register_middlewares(self, middlewares: Optional[set[str]] = None):
502545
if middleware in MIDDLEWARE_MAP:
503546
self.register_middleware(MIDDLEWARE_MAP[middleware])
504547
else:
505-
logger.error(f"Can not find middleware for Adapter {middleware}")
548+
log("ERROR", f"Can not find middleware for Adapter {middleware}")
506549

507550
def setup(self):
508551
@self.driver.on_startup
@@ -512,7 +555,7 @@ async def _():
512555
if isinstance(conn, HTTPConfig):
513556
queue = None
514557
if conn.event_enabled:
515-
queue = Queue(conn.event_buffer_size)
558+
queue = Queue[Event](conn.event_buffer_size)
516559
self.setup_http_server(
517560
HTTPServerSetup(
518561
URL("/all4one/"),

0 commit comments

Comments
 (0)