예제 #1
0
    async def _send(self,
                    data: TLObject,
                    wait_response: bool = True,
                    timeout: float = WAIT_TIMEOUT):
        message = self.msg_factory(data)
        msg_id = message.msg_id

        if wait_response:
            self.results[msg_id] = Result()

        log.debug("Sent:\n{}".format(message))

        payload = MTProto.pack(message, self.current_salt.salt,
                               self.session_id, self.auth_key,
                               self.auth_key_id)

        try:
            await self.connection.send(payload)
        except OSError as e:
            self.results.pop(msg_id, None)
            raise e

        if wait_response:
            try:
                await asyncio.wait_for(self.results[msg_id].event.wait(),
                                       timeout)
            except asyncio.TimeoutError:
                pass
            finally:
                result = self.results.pop(msg_id).value

            if result is None:
                raise TimeoutError
            elif isinstance(result, types.RpcError):
                if isinstance(data, (functions.InvokeWithoutUpdates,
                                     functions.InvokeWithTakeout)):
                    data = data.query

                RPCError.raise_it(result, type(data))
            elif isinstance(result, types.BadMsgNotification):
                raise Exception(
                    self.BAD_MSG_DESCRIPTION.get(
                        result.error_code,
                        "Error code {}".format(result.error_code)))
            else:
                return result
예제 #2
0
    async def net_worker(self):
        logging.info("NetWorkerTask started")

        while True:
            packet = await self.recv_queue.get()

            if packet is None:
                break

            try:
                data = MTProto.unpack(BytesIO(packet), self.session_id,
                                      self.auth_key, self.auth_key_id)

                messages = (data.body.messages if isinstance(
                    data.body, MsgContainer) else [data])

                log.debug(data)

                for msg in messages:
                    if msg.seq_no % 2 != 0:
                        if msg.msg_id in self.pending_acks:
                            continue
                        else:
                            self.pending_acks.add(msg.msg_id)

                    if isinstance(
                            msg.body,
                        (types.MsgDetailedInfo, types.MsgNewDetailedInfo)):
                        self.pending_acks.add(msg.body.answer_msg_id)
                        continue

                    if isinstance(msg.body, types.NewSessionCreated):
                        continue

                    msg_id = None

                    if isinstance(
                            msg.body,
                        (types.BadMsgNotification, types.BadServerSalt)):
                        msg_id = msg.body.bad_msg_id
                    elif isinstance(msg.body, (FutureSalts, types.RpcResult)):
                        msg_id = msg.body.req_msg_id
                    elif isinstance(msg.body, types.Pong):
                        msg_id = msg.body.msg_id
                    else:
                        if self.client is not None:
                            self.client.updates_queue.put_nowait(msg.body)

                    if msg_id in self.results:
                        self.results[msg_id].value = getattr(
                            msg.body, "result", msg.body)
                        self.results[msg_id].event.set()

                if len(self.pending_acks) >= self.ACKS_THRESHOLD:
                    log.info("Send {} acks".format(len(self.pending_acks)))

                    try:
                        await self._send(
                            types.MsgsAck(msg_ids=list(self.pending_acks)),
                            False)
                    except (OSError, TimeoutError):
                        pass
                    else:
                        self.pending_acks.clear()
            except Exception as e:
                log.error(e, exc_info=True)

        log.info("NetWorkerTask stopped")