def execute(self, context: Context):
        waiter_timeout = asyncio.async(asyncio.sleep(context.const.waiter_timeout))

        with auto_cancellation([waiter_timeout]):
            while True:
                reading = asyncio.async(self._take_message(context))
                done, pending = yield from asyncio.wait([waiter_timeout, reading], return_when=concurrent.futures.FIRST_COMPLETED)
                reading.cancel()

                if waiter_timeout in done:
                    self._logger.info('Token was lost!')
                    context.state = LooserState()
                    return

                if reading in done:
                    message = yield from reading
                    self._logger.debug('Message: {}.'.format(message.type))

                    if message.type == MessageType.TOKEN_IS_HERE:
                        waiter_timeout.cancel()
                        waiter_timeout = asyncio.async(asyncio.sleep(context.const.waiter_timeout))

                    elif message.type == MessageType.TAKE_TOKEN:
                        context.update_token(message.token, message.data)
                        context.state = OwnerState()
                        return

                    elif message.type == MessageType.WHERE_IS_TOKEN:
                        wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_WAS_HERE_RECENTLY)), self._logger)
    def execute(self, context: Context):
        self._logger.info('Token is here... Calculating...')
        yield from context.send_broadcast(MessageType.TOKEN_IS_HERE)

        heart_beat_timeout = asyncio.async(asyncio.sleep(context.const.heartbeat_timeout))
        calculating = asyncio.async(context.calculate())
        transferring_token = None

        with auto_cancellation([heart_beat_timeout, calculating, calculating, transferring_token]):
            while True:
                reading = asyncio.async(self._take_message(context))
                fs = [heart_beat_timeout, reading]
                if transferring_token is None:
                    fs.append(calculating)
                else:
                    fs.append(transferring_token)
                done, pending = yield from asyncio.wait(fs, return_when=concurrent.futures.FIRST_COMPLETED)
                reading.cancel()

                if heart_beat_timeout in done:
                    self._logger.debug('Token is here...')
                    yield from context.send_broadcast(MessageType.TOKEN_IS_HERE)

                    heart_beat_timeout = asyncio.async(asyncio.sleep(context.const.heartbeat_timeout))

                if calculating in done:
                    self._logger.info('Calculation finished!')
                    self._logger.info('Transferring token...')

                    calculating = None
                    transferring_token = wrap_exc(asyncio.async(context.send_message_to_next(MessageType.TAKE_TOKEN)), self._logger)

                if transferring_token in done:
                    success = yield from transferring_token
                    if success:
                        context.state = WaiterState()
                        return
                    else:
                        self._logger.warn('Transferring token failed, transferring token again...')
                        transferring_token = wrap_exc(asyncio.async(context.send_message_to_next(MessageType.TAKE_TOKEN)), self._logger)

                if reading in done:
                    message = yield from reading
                    self._logger.debug('Message: {}.'.format(message.type))

                    if message.type == MessageType.TOKEN_IS_HERE:
                        if message.token.priority() > context.current_token.priority():
                            wrap_exc(asyncio.async(context.send_response(message, MessageType.PING)), self._logger)
                            context.state = WaiterState()
                            return
                        elif message.author_node_id != context.node_id:
                            wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger)
                            context.send_broadcast(MessageType.TOKEN_IS_HERE)

                    elif message.type == MessageType.WHERE_IS_TOKEN:
                        wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger)

                    elif message.type == MessageType.GENERATING_TOKEN:
                        wrap_exc(asyncio.async(context.send_response(message, MessageType.TOKEN_IS_HERE)), self._logger)
                        yield from context.send_broadcast(MessageType.TOKEN_IS_HERE)
 def notify_state_changed(self, old_state, new_state):
     if self._debug_messenger is None:
         return
     message = ChangingStateBroadcast(self.node_id, old_state, new_state)
     logger.debug("Sending debug message: {}".format(message.__getstate__()))
     support.wrap_exc(asyncio.async(self._debug_messenger.send_message(
         serialize_message(message, task2.flow.messenger.ENCODING))), logger)
    def _listen_messages(self):
        while True:
            address, data_bytes = yield from self.listen_message()

            message = deserialize_message(data_bytes, ENCODING)
            self._get_logger().debug('Deserialized message: {}...'.format(message.__getstate__()))
            if self._on_message is not None:
                # noinspection PyCallingNonCallable
                wrap_exc(asyncio.async(self._on_message(message, address)), self._get_logger())
            self._message_queue.put_nowait(message)
 def _taking_messages_loop(self):
     while True:
         takings = []
         for listener in self._listeners.values():
             takings.append(wrap_exc(asyncio.async(listener.take_message()), self._logger))
         with auto_cancellation(takings):
             done, pending = yield from asyncio.wait(takings, return_when=concurrent.futures.FIRST_COMPLETED)
             for f in done:
                 message = yield from f
                 self._message_queue.put_nowait(message)
                 self._logger.debug(
                     'Message {} putted. Queue size: {}.'.format(message.type, self._message_queue.qsize()))
    def _on_message(self, message: Message, address):
        node_id = message.author_node_id
        if node_id in self._lost_nodes:
            self._lost_nodes.remove(node_id)
            self._logger.info('Heard about lost node again! (node_id={}) (so lost nodes: {})'
                              .format(node_id, self._lost_nodes))
        if node_id not in self.nodes:
            host = address[0]
            self._add_node(node_id, host)
            wrap_exc(asyncio.async(self.send_message(node_id, Message(MessageType.PING, self.node_id))), self._logger)
        elif address[0] != self.nodes[node_id]:
            self._logger.error('Unexpected state! My nodes: {}. {} != {} (node_id={})'
                               .format(self.nodes, address[0], self.nodes[node_id], node_id))

        if message.type == MessageType.TAKE_TOKEN:
            assert isinstance(message, TakeTokenMessage)
            for node_id, host in message.nodes.items():
                if node_id not in self.nodes:
                    self._add_node(node_id, host)
                else:
                    if host != self.nodes[node_id]:
                        self._logger.error('Unexpected state! My nodes: {}. Nodes in message: {}. {} != {} (node_id={})'
                                           .format(self.nodes, message.nodes, host, self.nodes[node_id], node_id))
 def start(self):
     self._daemon = wrap_exc(asyncio.async(self._listen_messages()), self._get_logger())
 def start(self):
     self._logger.info('Starting messengers...')
     for messenger in self._listeners.values():
         messenger.start()
     self._logger.info('Messengers started!')
     self._daemon = wrap_exc(asyncio.async(self._taking_messages_loop()), self._logger)