44from functools import partial
55from collections .abc import AsyncGenerator
66from contextlib import asynccontextmanager
7- from typing import Any , Union , Literal , Optional , cast
7+ from typing import Any , Union , Literal , ClassVar , Optional , cast
88from asyncio import Task , Queue , sleep , gather , wait_for , create_task
99
1010import msgpack
11- from nonebot .log import logger
1211from nonebot .adapters import Bot
1312from nonebot .utils import escape_tag
1413from nonebot .exception import WebSocketClosed
3837 WebSocketServerSetup ,
3938)
4039
40+ from ..logger import log
4141from .utils import encode_data
42+ from ..__version__ import __version__
4243from ..middlewares import MIDDLEWARE_MAP , Middleware
4344from .config import (
4445 Config ,
5051
5152
5253class 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