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)
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)
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)
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)