Пример #1
0
    def handle_ready_msg(self, channel: Channel, session: FBDPSession,
                         msg: FBDPMessage) -> None:
        """Process READY message received from server.

        Arguments:
            channel: Channel that received the message.
            session: Session instance.
            msg:     Received message.

        Note:
            All exceptions are handled by `handle_exception`.
        """
        if session.transmit is not None:
            # Transmission in progress, READY is out of band
            raise StopError("Out of band READY message",
                            code=ErrorCode.PROTOCOL_VIOLATION)
        if msg.type_data > 0:
            # Server is ready
            batch_size = self.on_server_ready(channel, session, msg.type_data)
            result = max(
                0,
                min(msg.type_data,
                    self.batch_size if batch_size == -1 else batch_size))
            self.send_ready(channel, session, result)
            if result > 0:
                # We are ready to transmit as well
                session.transmit = result
                if session.socket is PipeSocket.INPUT:
                    # Initiate transfer to server (via I/O loop)
                    channel.set_wait_out(True, session)
        else:
            # Server is not ready, but we must send READY(0) back to confirm we've got it!
            self.send_ready(channel, session, 0)
Пример #2
0
    def handle_ready_msg(self, channel: Channel, session: FBDPSession,
                         msg: FBDPMessage) -> None:
        """Process READY message received from client.

        Arguments:
            channel: Channel that received the message.
            session: Session instance.
            msg:     Received message.

        Note:
            All exceptions are handled by `handle_exception`.
        """
        if not session.await_ready:
            # Transmission in progress, READY is out of band
            raise StopError("Out of band READY message",
                            code=ErrorCode.PROTOCOL_VIOLATION)
        session.await_ready = False
        if msg.type_data == 0:
            # Client either confirmed our zero, or is not ready yet.
            self.on_schedule_ready(channel, session)
        else:
            # All green to transmit DATA
            session.transmit = msg.type_data
            if session.socket is PipeSocket.OUTPUT:
                # Initiate transfer to output (via I/O loop)
                channel.set_wait_out(True, session)
Пример #3
0
    def handle_data_msg(self, channel: Channel, session: FBDPSession,
                        msg: FBDPMessage) -> None:
        """Process DATA message received from client.

        Arguments:
            channel: Channel that received the message.
            session: Session instance.
            msg:     Received message.

        Note:
            All exceptions are handled by `handle_exception`.
        """
        if session.socket is self._flow_in_socket:
            # DATA flow to us (INPUT for server context, OUTPUT for client context)
            if session.transmit is None:
                # Transmission not started, DATA out of band
                raise StopError("Out of band DATA message",
                                code=ErrorCode.PROTOCOL_VIOLATION)
            # ACK before processing?
            if msg.has_ack_req() and not self.confirm_processing:
                # We must create reply message directly to keep received message
                reply = FBDPMessage()
                reply.msg_type = msg.msg_type
                reply.type_data = msg.type_data
                reply.set_flag(MsgFlag.ACK_REPLY)
                if channel.send(msg, session) != 0:
                    raise StopError("ACK-REPLY send failed",
                                    code=ErrorCode.ERROR)
            # Process incoming data
            self.on_accept_data(channel, session, msg.data_frame)
            # ACK after processing?
            if msg.has_ack_req() and self.confirm_processing:
                if channel.send(self.create_ack_reply(msg), session) != 0:
                    raise StopError("ACK-REPLY send failed",
                                    code=ErrorCode.ERROR)
            session.transmit -= 1
            if session.transmit == 0:
                self._init_new_batch(channel, session)
        else:
            # DATA flow from us (OUTPUT for server context, INPUT for client context)
            if msg.has_ack_reply():
                if (session.transmit > 0) and self.send_after_confirmed:
                    # Re-Initiate transfer to output (via I/O loop) if data are available
                    if not self.on_get_data.is_set() or self.on_get_data(
                            channel, session):
                        channel.set_wait_out(True, session)
                self.on_data_confirmed(channel, session, msg.type_data)
            else:
                # Only client attached to PIPE_INPUT can send DATA messages
                socket: PipeSocket = PipeSocket.OUTPUT \
                    if self._flow_in_socket is PipeSocket.INPUT else PipeSocket.INPUT
                raise StopError(f"DATA message sent to {socket.name} socket",
                                code=ErrorCode.PROTOCOL_VIOLATION)
Пример #4
0
 def _send_data(self, channel: Channel, session: FBDPSession,
                msg: FBDPMessage) -> None:
     """Sends next DATA message to the client attached to PIPE_OUTPUT.
     """
     error_code = None
     exc = None
     try:
         self.on_produce_data(channel, session, msg)
         channel.send(msg, session)
         session.transmit -= 1
         if session.transmit > 0:
             if msg.has_ack_req() and self.send_after_confirmed:
                 channel.set_wait_out(False, session)
             elif self.on_get_data.is_set():
                 if not self.on_get_data(channel, session):
                     channel.set_wait_out(False, session)
         else:
             channel.set_wait_out(False, session)
             self._init_new_batch(channel, session)
     except StopError as err:
         error_code = getattr(err, 'code', ErrorCode.ERROR)
         if error_code is not ErrorCode.OK:
             exc = err
     except Exception as err:
         error_code = ErrorCode.INTERNAL_ERROR
         exc = err
     if error_code is not None:
         self.send_close(channel, session, error_code, exc)