async def ws_message(self): async with aiohttp.ClientSession() as session: async with session.ws_connect( f"{self.baseurl}/message?sessionKey={self.session_key}" ) as ws_connection: while True: try: received_data = await ws_connection.receive_json() except TypeError: continue if received_data: NetworkLogger.debug("received", received_data) try: received_data[ 'messageChain'] = MessageChain.parse_obj( received_data['messageChain']) received_data = MessageTypes[ received_data['type']].parse_obj(received_data) except pydantic.ValidationError: SessionLogger.error( f"parse failed: {received_data}") traceback.print_exc() else: await self.queue.put( InternalEvent(name=self.getEventCurrentName( type(received_data)), body=received_data))
async def ws_event(self): from mirai.event.external.enums import ExternalEvents async with aiohttp.ClientSession() as session: async with session.ws_connect( f"{self.baseurl}/event?sessionKey={self.session_key}" ) as ws_connection: while True: try: received_data = await ws_connection.receive_json() except TypeError: continue if received_data: try: if hasattr(ExternalEvents, received_data['type']): received_data = \ ExternalEvents[received_data['type']] \ .value \ .parse_obj(received_data) else: raise exceptions.UnknownEvent( f"a unknown event has been received, it's '{received_data['type']}'") except pydantic.ValidationError: SessionLogger.error(f"parse failed: {received_data}") traceback.print_exc() else: await self.queue.put(InternalEvent( name=self.getEventCurrentName(type(received_data)), body=received_data ))
def run(self, loop=None, no_polling=False, no_forever=False): self.checkEventBodyAnnotations() self.checkEventDependencies() loop = loop or asyncio.get_event_loop() self.queue = asyncio.Queue(loop=loop) exit_signal = False loop.run_until_complete(self.enable_session()) if not no_polling: # check ws status if self.useWebsocket: SessionLogger.info("event receive method: websocket") else: SessionLogger.info("event receive method: http polling") result = loop.run_until_complete(self.checkWebsocket()) if not result: # we can use http, not ws. # should use http, but we can change it. if self.useWebsocket: SessionLogger.warning("catched wrong config: enableWebsocket=false, we will modify it.") loop.run_until_complete(self.setConfig(enableWebsocket=True)) loop.create_task(self.ws_event()) loop.create_task(self.ws_message()) else: loop.create_task(self.message_polling()) else: # we can use websocket, it's fine if self.useWebsocket: loop.create_task(self.ws_event()) loop.create_task(self.ws_message()) else: SessionLogger.warning("catched wrong config: enableWebsocket=true, we will modify it.") loop.run_until_complete(self.setConfig(enableWebsocket=False)) loop.create_task(self.message_polling()) loop.create_task(self.event_runner()) if not no_forever: for i in self.subroutines: loop.create_task(i(self)) try: for start_callable in self.lifecycle['start']: loop.run_until_complete(self.run_func(start_callable, self)) for around_callable in self.lifecycle['around']: loop.run_until_complete(self.run_func(around_callable, self)) loop.run_forever() except KeyboardInterrupt: SessionLogger.info("catched Ctrl-C, exiting..") except Exception as e: traceback.print_exc() finally: for around_callable in self.lifecycle['around']: loop.run_until_complete(self.run_func(around_callable, self)) for end_callable in self.lifecycle['end']: loop.run_until_complete(self.run_func(end_callable, self)) loop.run_until_complete(self.release())
def run(self, loop=None): self.checkEventBodyAnnotations() self.checkEventDependencies() loop = loop or asyncio.get_event_loop() queue = asyncio.Queue(loop=loop) exit_signal = False loop.run_until_complete(self.enable_session()) loop.create_task(self.message_polling(lambda: exit_signal, queue)) loop.create_task(self.event_runner(lambda: exit_signal, queue)) for i in self.run_forever_target: loop.create_task(i(self)) try: loop.run_forever() except KeyboardInterrupt: SessionLogger.info("catched Ctrl-C, exiting..") finally: loop.run_until_complete(self.release()) loop.run_until_complete(session.close())
async def ws_event_receiver(self, exit_signal, queue): await self.checkWebsocket(force=True) async with aiohttp.ClientSession() as session: async with session.ws_connect( f"{self.baseurl}/all?sessionKey={self.session_key}" ) as ws_connection: while not exit_signal(): try: received_data = await ws_connection.receive_json() except TypeError: if not exit_signal(): continue else: break if received_data: try: if received_data['type'] in MessageTypes: if 'messageChain' in received_data: received_data['messageChain'] = \ MessageChain.parse_obj(received_data['messageChain']) received_data = \ MessageTypes[received_data['type']].parse_obj(received_data) elif hasattr(ExternalEvents, received_data['type']): # 判断当前项是否为 Event received_data = \ ExternalEvents[received_data['type']]\ .value\ .parse_obj(received_data) except pydantic.ValidationError: SessionLogger.error( f"parse failed: {received_data}") traceback.print_exc() else: await queue.put( InternalEvent(name=self.getEventCurrentName( type(received_data)), body=received_data))
def __init__(self, app: Mirai, listen_events: List[str] = [ "FriendMessage", "GroupMessage" ], command_prefix: List[str] = [">"], global_dependencies: List[Depend] = [], global_middlewares: List = [] ): self.application = app self.listen_events = listen_events self.command_prefix = [re.escape(i) for i in command_prefix] self.global_dependencies = global_dependencies self.global_middlewares = global_middlewares if "^/" in self.command_prefix: SessionLogger.warn("you shouldn't use '/' as a prefix, because it's used by mirai-console...") SessionLogger.warn("ok, we will support '/' as a prefix in the future..") if "GroupMessage" in listen_events: app.receiver("GroupMessage")(self.GroupMessageListener) if "FriendMessage" in listen_events: app.receiver("FriendMessage")(self.FriendMessageListener)
def run(self, loop=None, no_polling=False, no_forever=False): self.checkEventBodyAnnotations() self.checkEventDependencies() loop = loop or asyncio.get_event_loop() self.queue = queue = asyncio.Queue(loop=loop) exit_signal = False loop.run_until_complete(self.enable_session()) if not no_polling: if not self.useWebsocket: SessionLogger.warning( "http's fetchMessage is disabled in mirai-api-http 1.2.1(it's a bug :P)." ) SessionLogger.warning("so, you can use WebSocket.") SessionLogger.warning( "if it throw a unexpected error, you should call the httpapi's author." ) loop.create_task( self.message_polling(lambda: exit_signal, queue)) else: SessionLogger.warning( "you are using WebSocket, it's a experimental method.") SessionLogger.warning( "but, websocket is remember way to fetch message and event," ) SessionLogger.warning( "and http's fetchMessage is disabled in mirai-api-http 1.2.1(it's a bug :P)." ) SessionLogger.warning( "if it throw a unexpected error, you can call the httpapi's author." ) loop.create_task( self.ws_event_receiver(lambda: exit_signal, queue)) loop.create_task(self.event_runner(lambda: exit_signal, queue)) if not no_forever: for i in self.subroutines: loop.create_task(i(self)) try: loop.run_forever() except KeyboardInterrupt: SessionLogger.info("catched Ctrl-C, exiting..") finally: loop.run_until_complete(self.release()) loop.run_until_complete(session.close())
async def main_entrance(self, run_body, event_context, queue): if isinstance(run_body, dict): callable_target = run_body['func'] for depend in run_body['dependencies']: if not inspect.isclass(depend.func): depend_func = depend.func elif hasattr(depend.func, "__call__"): depend_func = depend.func.__call__ else: raise TypeError("must be callable.") await self.main_entrance( { "func": depend_func, "middlewares": depend.middlewares, "dependencies": [] }, event_context, queue) else: if inspect.isclass(run_body): if hasattr(run_body, "__call__"): run_body = run_body.__call__ else: raise TypeError("must be callable.") else: callable_target = run_body translated_mapping = { **(await self.argument_compiler(callable_target, event_context)), **(await self.signature_checkout(callable_target, event_context, queue)) } try: if isinstance(run_body, dict): middlewares = run_body.get("middlewares") if middlewares: async_middlewares = [] normal_middlewares = [] for middleware in middlewares: if all([ hasattr(middleware, "__aenter__"), hasattr(middleware, "__aexit__") ]): async_middlewares.append(middleware) elif all([ hasattr(middleware, "__enter__"), hasattr(middleware, "__exit__") ]): normal_middlewares.append(middleware) else: SessionLogger.error( f"threw a exception by {event_context.name}, no currect context error." ) raise AttributeError( "no a currect context object.") async with contextlib.AsyncExitStack() as async_stack: for async_middleware in async_middlewares: SessionLogger.debug( f"a event called {event_context.name}, enter a currect async context." ) await async_stack.enter_async_context( async_middleware) with contextlib.ExitStack() as normal_stack: for normal_middleware in normal_middlewares: SessionLogger.debug( f"a event called {event_context.name}, enter a currect context." ) normal_stack.enter_context(normal_middleware) if inspect.iscoroutinefunction(callable_target): return await callable_target( **translated_mapping) else: return callable_target(**translated_mapping) else: if inspect.iscoroutinefunction(callable_target): return await callable_target(**translated_mapping) else: return callable_target(**translated_mapping) else: if inspect.iscoroutinefunction(callable_target): return await callable_target(**translated_mapping) else: return callable_target(**translated_mapping) except (NameError, TypeError) as e: EventLogger.error( f"threw a exception by {event_context.name}, it's about Annotations Checker, please report to developer." ) traceback.print_exc() except Exception as e: EventLogger.error( f"threw a exception by {event_context.name}, and it's {e}") await self.throw_exception_event(event_context, queue, e)