def send(self, msg: HorseMessage, additional_headers: List[MessageHeader] = None) -> HorseResult: """ Sends a raw message to server. Returns true if all data sent over network. :param msg: Sending message :param additional_headers: Additional message headers :return: Successful if the message sent over network. Otherwise returns failed. """ try: writer = ProtocolWriter() if msg.source_len == 0: msg.source = self.id if not msg.message_id: msg.message_id = unique_generator.create() bytes = writer.write(msg, additional_headers) self.__socket.sendall(bytes.getbuffer()) result = HorseResult() result.code = ResultCode.Ok return result except: self.disconnect() result = HorseResult() result.code = ResultCode.Failed return result
async def leave(self, channel: str, wait_ack: bool = False) -> HorseResult: """ Leavess from a channel :param channel: Channel name :param wait_ack: If true, waits for acknowledge from server :return: If waits for ack, ack result. Otherview Ok if message is sent successfuly """ msg = HorseMessage() msg.type = MessageType.Server msg.content_type = KnownContentTypes.LEAVE.value msg.target = channel msg.pending_response = wait_ack result: HorseResult if wait_ack: msg.message_id = unique_generator.create() result = await self.request(msg) else: result = self.send(msg) # remove channel from joined channel list if result.code == ResultCode.Ok: self.__joined_channels.remove(channel) return result
async def join(self, channel: str, wait_ack: bool = False) -> HorseResult: """ Joins to a channel :param channel: Channel name :param wait_ack: If true, waits for acknowledge from server :return: If waits for ack, ack result. Otherview Ok if message is sent successfuly """ msg = HorseMessage() msg.type = MessageType.Server msg.content_type = KnownContentTypes.JOIN.value msg.target = channel msg.pending_response = wait_ack result: HorseResult if wait_ack: msg.message_id = unique_generator.create() result = await self.request(msg) else: result = self.send(msg) # add channel to joined list (if not already added) if result.code == ResultCode.Ok: has = next((x for x in self.__joined_channels if x == channel), None) if not has: self.__joined_channels.append(channel) return result
async def send_get_ack( self, msg: HorseMessage, additional_headers: List[MessageHeader] = None ) -> HorseResult: # Awaitable[HorseResult]: """ Sends a message and waits for acknowledge :param msg: Sending message :param additional_headers: Additional message headers :return: Returns a result after acknowledge received or timed out """ future: asyncio.Future = None try: writer = ProtocolWriter() if msg.source_len == 0: msg.source = self.id if not msg.message_id: msg.message_id = unique_generator.create() msg.pending_response = False if not msg.pending_acknowledge: msg.pending_acknowledge = True tracking = await self.__tracker.track(msg, self.ack_timeout) bytes = writer.write(msg, additional_headers) self.__socket.sendall(bytes.getbuffer()) while not tracking.future.done(): time.sleep(0.001) resp: HorseMessage = await tracking.future result = HorseResult() if resp is None: result.code = ResultCode.RequestTimeout result.reason = "timeout" else: nack_value = resp.get_header( HorseHeaders.NEGATIVE_ACKNOWLEDGE_REASON) if nack_value is None: result.code = ResultCode.Ok result.reason = "" else: result.code = ResultCode.Failed result.reason = nack_value return result except: self.disconnect() if future is not None: await self.__tracker.forget(msg) result = HorseResult() result.code = ResultCode.SendError result.reason = "" return result
async def pull( self, request: PullRequest, each_msg_func: Callable[[int, HorseMessage], None]) -> PullContainer: msg = HorseMessage() msg.type = MessageType.QueuePullRequest msg.message_id = unique_generator.create() msg.target = request.channel msg.content_type = request.queue_id msg.add_header(HorseHeaders.COUNT, str(request.count)) if request.clear_after == ClearDecision.AllMessages.value: msg.add_header(HorseHeaders.CLEAR, "all") elif request.clear_after == ClearDecision.PriorityMessages.value: msg.add_header(HorseHeaders.CLEAR, "High-Priority") elif request.clear_after == ClearDecision.Messages.value: msg.add_header(HorseHeaders.CLEAR, "Default-Priority") if request.get_counts: msg.add_header(HorseHeaders.INFO, "yes") if request.order == MessageOrder.LIFO.value: msg.add_header(HorseHeaders.ORDER, HorseHeaders.LIFO) if request.request_headers: for header in request.request_headers: msg.add_header(header.key, header.value) container = PullContainer() container.request_id = msg.message_id container.request_count = request.count container.received_count = 0 container.status = PullProcess.Receiving container.messages = [] container.each_msg_func = each_msg_func container.last_received = datetime.utcnow() container.future = asyncio.Future() self.__pull_containers[msg.message_id] = container send_result = self.send(msg) if send_result.code != ResultCode.Ok: self.__pull_containers.pop(msg.message_id) return container while not container.future.done(): time.sleep(0.001) diff = datetime.utcnow() - container.last_received if diff > self.request_timeout: self.__pull_containers.pop(msg.message_id) container.future.set_result(None) break await container.future return container
def __init__(self): self.id = unique_generator.create() self.__tracker = MessageTracker() self.__tracker.run()