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 ))
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 message_polling(self, count=10): while True: await asyncio.sleep(0.5) try: result = \ await super().fetchMessage(count) except pydantic.ValidationError: continue last_length = len(result) latest_result = [] while True: if last_length == count: latest_result = await super().fetchMessage(count) last_length = len(latest_result) result += latest_result continue break for message_index in range(len(result)): item = result[message_index] await self.queue.put( InternalEvent( name=self.getEventCurrentName(type(item)), body=item ) )
async def warpper(app: "Mirai"): try: return await func(app) except Exception as e: await self.queue.put( InternalEvent(name="UnexpectedException", body=UnexpectedException(error=e, event=None, session=self)))
async def throw_exception_event(self, event_context, queue, exception): if event_context.name != "UnexpectedException": #print("error: by pre:", event_context.name) await queue.put( InternalEvent(name="UnexpectedException", body=UnexpectedException(error=exception, event=event_context, session=self))) EventLogger.error( f"threw a exception by {event_context.name}, Exception: {exception}" ) traceback.print_exc() else: EventLogger.critical( f"threw a exception by {event_context.name}, Exception: {exception}, it's a exception handler." )
async def put_exception(self, event_context, exception): from mirai.event.builtins import UnexpectedException if event_context.name != "UnexpectedException": if exception.__class__ in self.listening_exceptions: EventLogger.error( f"threw a exception by {event_context.name}, Exception: {exception.__class__.__name__}, and it has been catched.") else: EventLogger.error( f"threw a exception by {event_context.name}, Exception: {exception.__class__.__name__}, and it hasn't been catched!") traceback.print_exc() await self.queue.put(InternalEvent( name="UnexpectedException", body=UnexpectedException( error=exception, event=event_context, application=self ) )) else: EventLogger.critical( f"threw a exception in a exception handler by {event_context.name}, Exception: {exception.__class__.__name__}.")
async def message_polling(self, exit_signal, queue, count=10): while not exit_signal(): await asyncio.sleep(0.5) result = \ await super().fetchMessage(count) last_length = len(result) latest_result = [] while True: if last_length == count: latest_result = await super().fetchMessage(count) last_length = len(latest_result) result += latest_result continue break for message_index in range(len(result)): item = result[message_index] await queue.put( InternalEvent(name=self.getEventCurrentName(type(item)), body=item))
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 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()) loop.run_until_complete( self.queue.put( InternalEvent( name=self.getEventCurrentName("AppInitEvent"), body={}))) 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())