def decode(cls, message: Msg) -> Optional[Event]: """Buddy Message Decoder. Note: Source: com.tencent.mobileqq.service.message.codec.decoder.buddyMessage.BuddyMessageDecoder """ sub_decoders: Dict[int, Callable[[Msg], Optional[Event]]] = { 11: cls.decode_normal_buddy, # 129: OnlineFileDecoder, # 131: OnlineFileDecoder, # 133: OnlineFileDecoder, # 169: OfflineFileDecoder, 175: cls.decode_normal_buddy, # 241: OfflineFileDecoder, # 242: OfflineFileDecoder, # 243: OfflineFileDecoder, } Decoder = sub_decoders.get(message.head.c2c_cmd, None) if not Decoder: logger.debug( "MessageSvc.PbGetMsg: BuddyMessageDecoder cannot " f"decode message with c2c_cmd {message.head.c2c_cmd}" ) return return Decoder(message)
async def receive(self): """Receive data from connection reader and store it in sequence future. Note: Source: com.tencent.mobileqq.msf.core.auth.n.a """ while self.connected: try: length: int = (struct.unpack( ">i", await self.connection.read_bytes(4))[0] - 4) # FIXME: length < 0 ? data = await self.connection.read_bytes(length) packet = IncomingPacket.parse( data, self._key, self._siginfo.d2key, self._siginfo.wt_session_ticket_key, ) logger.debug( f"<-- {packet.seq} ({packet.ret_code}): {packet.command_name}" ) # do not block receive asyncio.create_task(self._handle_incoming_packet(packet)) except ConnectionAbortedError: logger.debug(f"Client {self.uin} connection closed") except Exception as e: logger.exception(e)
async def handle_config_push_request( client: "Client", packet: IncomingPacket) -> ConfigPushCommand: command = ConfigPushCommand.decode_push_req( packet.uin, packet.seq, packet.ret_code, packet.command_name, packet.data, ) if isinstance(command, SsoServerPushCommand): logger.debug(f"ConfigPush: Got new server addresses.") elif isinstance(command, FileServerPushCommand): client._file_storage_info = command.list if isinstance(command, _ConfigPushCommandBase): resp_packet = encode_config_push_response( client.uin, command.seq, client._session_id, client._siginfo.d2key, command.type, command.jcebuf, command.large_seq, ) await client.send(command.seq, "ConfigPushSvc.PushResp", resp_packet) return command
async def send(self, seq: int, command_name: str, packet: Union[bytes, Packet]) -> None: """Send a packet with the given sequence but not wait for the response. Args: seq (int): Sequence number. command_name (str): Command name of the packet. packet (Union[bytes, Packet]): Packet to send. Returns: None. """ logger.debug(f"--> {seq}: {command_name}") await self.connection.awrite(packet)
async def handle_get_message(client: "Client", packet: IncomingPacket) -> "GetMessageCommand": """Handle Pb Get Message response. Note: Source: c2c 1002 com.tencent.imcore.message.C2CMessageProcessor.b com.tencent.imcore.message.C2CMessageProcessor.a com.tencent.imcore.message.C2CMessageProcessorCallback.a com.tencent.imcore.message.DecodeMsg.a """ resp = GetMessageCommand.decode_response( packet.uin, packet.seq, packet.ret_code, packet.command_name, packet.data, ) if isinstance(resp, GetMessageSuccess): # cache last cookie if resp.response.rsp_type == 0: client._sync_cookie = resp.response.sync_cookie client._pubaccount_cookie = resp.response.sync_cookie elif resp.response.rsp_type == 1: client._sync_cookie = resp.response.sync_cookie elif resp.response.rsp_type == 2: client._pubaccount_cookie = resp.response.pubaccount_cookie delete_msgs: List[PbDeleteMsgReq.MsgItem] = [] for pair_msgs in resp.response.uin_pair_msgs: last_read_time = pair_msgs.last_read_time & 0xFFFFFFFF for message in pair_msgs.msg: delete_msgs.append( PbDeleteMsgReq.MsgItem( from_uin=message.head.from_uin, to_uin=message.head.to_uin, type=message.head.type, seq=message.head.seq, uid=message.head.uid, )) if message.head.to_uin != client.uin: continue if message.head.time < last_read_time: continue key = (f"{message.head.from_uin}" f"{message.head.type}" f"{message.head.time}") if key in client._msg_cache: continue client._msg_cache[key] = None # drop messages when init if client._init_flag: continue msg_type = message.head.type Decoder = MESSAGE_DECODERS.get(msg_type, None) if not Decoder: logger.debug("MessageSvc.PbGetMsg: " f"Received unknown message type {msg_type}.") continue decoded_message = Decoder(message) if decoded_message: client.dispatch_event(decoded_message) if delete_msgs: seq = client.next_seq() del_packet = encode_delete_message( seq, client._session_id, client.uin, client._siginfo.d2key, delete_msgs, ) await client.send(seq, "MessageSvc.PbDeleteMsg", del_packet) if resp.response.sync_flag < SyncFlag.STOP: seq = client.next_seq() continue_packet = encode_get_message( seq, client._session_id, client.uin, client._siginfo.d2key, request_type=resp.response.rsp_type, sync_flag=resp.response.sync_flag, sync_cookie=resp.response.rsp_type != 2 and client._sync_cookie or None, pubaccount_cookie=resp.response.rsp_type == 2 and client._pubaccount_cookie or None, ) await client.send_and_wait(seq, "MessageSvc.PbGetMsg", continue_packet) return resp