def __init__(self, mac, broadcast_address, broadcast_port, tcp_port, node_id=None, loop=None):
        self._mac = mac
        self._node_id = node_id
        self._nodes = {}
        self._lost_nodes = set()

        self._loop = loop or asyncio.get_event_loop()
        self._io_executor = AsyncExecutor(5, self._loop)
        self._logger = logging.getLogger('Messenger')

        self._logger.info('Creating messengers...')
        if tcp_port != 0:
            self._tcp_messenger = TCPMessenger(tcp_port, self._io_executor, loop=self._loop)
        if broadcast_port != 0:
            self._udp_messenger = UDPMessenger(broadcast_address, broadcast_port, self._io_executor, True, self._loop)

        self._listeners = {
            'tcp': self._tcp_messenger,
            'udp': self._udp_messenger,
        }

        for messenger in self._listeners.values():
            messenger.set_on_message(self._on_message)

        self._daemon = None
        self._message_queue = asyncio.Queue()
def run_visualization_server(mac, broadcast_address, configuration):
    app = web.Application()
    app.router.add_route('GET', '/', get_last_state)
    loop = asyncio.get_event_loop()
    handler = app.make_handler()
    f = loop.create_server(handler, '0.0.0.0', 8888)
    srv = loop.run_until_complete(f)
    print('serving on', srv.sockets[0].getsockname())
    global logger
    logger = logging.getLogger('Node')
    cfg_node = configuration['node']
    io_executor = AsyncExecutor(5, loop)
    global udp_messenger
    debug_cfg = cfg_node['debug']
    if not debug_cfg['enabled']:
        logger.error('Check config! Debug disabled!')
        return
    logger.info("Debug port: {}".format(debug_cfg['broadcasting_port']))
    udp_messenger = UDPMessenger(broadcast_address,
                                 debug_cfg['broadcasting_port'], io_executor,
                                 True, loop)
    udp_messenger.start()

    asyncio. async (update_nodes())
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    finally:
        loop.run_until_complete(handler.finish_connections(1.0))
        srv.close()
        udp_messenger.stop()
        loop.run_until_complete(srv.wait_closed())
        loop.run_until_complete(app.finish())
    loop.close()
Exemple #3
0
def run_node(mac, broadcast_address, cfg):
    logger = logging.getLogger('Node')
    consts = Const()

    cfg_node = cfg['node']
    hostname = cfg_node['hostname'] or mac
    messenger = Messenger(mac,
                          broadcast_address,
                          cfg_node['broadcasting_port'],
                          cfg_node['tcp_port'],
                          node_id=hostname)
    messenger.start()
    debug_cfg = cfg_node['debug']
    if debug_cfg['enabled']:
        debug_messenger = UDPMessenger(broadcast_address,
                                       debug_cfg['broadcasting_port'],
                                       AsyncExecutor(2), False)
    else:
        debug_messenger = None

    context = Context(None, consts, messenger, debug_messenger)

    logger.debug('Running...')

    context.state = LooserState()
    try:
        asyncio.get_event_loop().set_debug(True)
        while True:
            asyncio.get_event_loop().run_until_complete(
                context.state.execute(context))
    except KeyboardInterrupt:
        logger.info('Stopped by user.')
        messenger.stop()
        debug_messenger.stop()
    def __init__(self,
                 mac,
                 broadcast_address,
                 broadcast_port,
                 tcp_port,
                 node_id=None,
                 loop=None):
        self._mac = mac
        self._node_id = node_id
        self._nodes = {}
        self._lost_nodes = set()

        self._loop = loop or asyncio.get_event_loop()
        self._io_executor = AsyncExecutor(5, self._loop)
        self._logger = logging.getLogger('Messenger')

        self._logger.info('Creating messengers...')
        if tcp_port != 0:
            self._tcp_messenger = TCPMessenger(tcp_port,
                                               self._io_executor,
                                               loop=self._loop)
        if broadcast_port != 0:
            self._udp_messenger = UDPMessenger(broadcast_address,
                                               broadcast_port,
                                               self._io_executor, True,
                                               self._loop)

        self._listeners = {
            'tcp': self._tcp_messenger,
            'udp': self._udp_messenger,
        }

        for messenger in self._listeners.values():
            messenger.set_on_message(self._on_message)

        self._daemon = None
        self._message_queue = asyncio.Queue()
class Messenger:
    def __init__(self, mac, broadcast_address, broadcast_port, tcp_port, node_id=None, loop=None):
        self._mac = mac
        self._node_id = node_id
        self._nodes = {}
        self._lost_nodes = set()

        self._loop = loop or asyncio.get_event_loop()
        self._io_executor = AsyncExecutor(5, self._loop)
        self._logger = logging.getLogger('Messenger')

        self._logger.info('Creating messengers...')
        if tcp_port != 0:
            self._tcp_messenger = TCPMessenger(tcp_port, self._io_executor, loop=self._loop)
        if broadcast_port != 0:
            self._udp_messenger = UDPMessenger(broadcast_address, broadcast_port, self._io_executor, True, self._loop)

        self._listeners = {
            'tcp': self._tcp_messenger,
            'udp': self._udp_messenger,
        }

        for messenger in self._listeners.values():
            messenger.set_on_message(self._on_message)

        self._daemon = None
        self._message_queue = asyncio.Queue()

    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)

    def stop(self):
        if self._daemon is not None:
            self._daemon.cancel()
            self._daemon = None
        self._tcp_messenger.stop()
        self._udp_messenger.stop()
        self._io_executor.shutdown(wait=False)

    def _serialize(self, message: Message):
        self._logger.debug('Serialized message: {}...'.format(message.__getstate__()))
        return serialize_message(message, ENCODING)

    @asyncio.coroutine
    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 _add_node(self, node_id, host):
        for old_node_id, old_host in self.nodes.items():
            if old_host == host:
                self._logger.error('IP collision! (new node id={}, new host={}, old node id={}, old ip={})'
                                   .format(node_id, host, old_node_id, old_host))
        self.nodes[node_id] = host
        self._logger.info('New node: {} at {}! (total number: {})'.format(node_id, host, len(self.nodes)))

        def format_node_id(node_id):
            return '{}{}'.format(node_id, '' if self.node_id != node_id else ' (me)')
        self._logger.info('Nodes order: {}'.format([(format_node_id(node_id), self.nodes[node_id]) for node_id in sorted(self.nodes.keys())]))

    @asyncio.coroutine
    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()))

    @asyncio.coroutine
    def take_message(self):
        message = yield from self._message_queue.get()
        self._logger.debug('Taking message: {}...'.format(message.type))
        return message

    @asyncio.coroutine
    def send_broadcast(self, message):
        message_bytes = self._serialize(message)
        yield from self._udp_messenger.send_message(message_bytes)

    @asyncio.coroutine
    def send_message(self, node_id, message):
        if node_id in self._lost_nodes:
            self._logger.error('Sending message to node, that seems to be lost! (node id={}, message type={})'
                               .format(node_id, message.type))
        self._logger.debug('Sending "{}" message to node {}...'.format(message.type, node_id))
        host = self.nodes[node_id]
        success = yield from self._tcp_messenger.send_message(host, self._serialize(message))
        if not success:
            self._lost_nodes.add(node_id)
            self._logger.warn('Node seems to be lost! (node_id={})'.format(node_id))
            if self.node_id == node_id:
                self._logger.error('We can not connect with our-self?! ')
        return success

    def get_next_available_node_id(self):
        nodes = sorted(self.nodes.keys())
        next_index = (nodes.index(self.node_id) + 1)
        for candidate_id in nodes[next_index:] + nodes[:next_index]:
            if candidate_id not in self._lost_nodes:
                return candidate_id

    @property
    def node_id(self):
        return str(self._node_id or self._mac)

    @property
    def nodes(self):
        return self._nodes
class Messenger:
    def __init__(self,
                 mac,
                 broadcast_address,
                 broadcast_port,
                 tcp_port,
                 node_id=None,
                 loop=None):
        self._mac = mac
        self._node_id = node_id
        self._nodes = {}
        self._lost_nodes = set()

        self._loop = loop or asyncio.get_event_loop()
        self._io_executor = AsyncExecutor(5, self._loop)
        self._logger = logging.getLogger('Messenger')

        self._logger.info('Creating messengers...')
        if tcp_port != 0:
            self._tcp_messenger = TCPMessenger(tcp_port,
                                               self._io_executor,
                                               loop=self._loop)
        if broadcast_port != 0:
            self._udp_messenger = UDPMessenger(broadcast_address,
                                               broadcast_port,
                                               self._io_executor, True,
                                               self._loop)

        self._listeners = {
            'tcp': self._tcp_messenger,
            'udp': self._udp_messenger,
        }

        for messenger in self._listeners.values():
            messenger.set_on_message(self._on_message)

        self._daemon = None
        self._message_queue = asyncio.Queue()

    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)

    def stop(self):
        if self._daemon is not None:
            self._daemon.cancel()
            self._daemon = None
        self._tcp_messenger.stop()
        self._udp_messenger.stop()
        self._io_executor.shutdown(wait=False)

    def _serialize(self, message: Message):
        self._logger.debug('Serialized message: {}...'.format(
            message.__getstate__()))
        return serialize_message(message, ENCODING)

    @asyncio.coroutine
    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 _add_node(self, node_id, host):
        for old_node_id, old_host in self.nodes.items():
            if old_host == host:
                self._logger.error(
                    'IP collision! (new node id={}, new host={}, old node id={}, old ip={})'
                    .format(node_id, host, old_node_id, old_host))
        self.nodes[node_id] = host
        self._logger.info('New node: {} at {}! (total number: {})'.format(
            node_id, host, len(self.nodes)))

        def format_node_id(node_id):
            return '{}{}'.format(node_id,
                                 '' if self.node_id != node_id else ' (me)')

        self._logger.info('Nodes order: {}'.format([
            (format_node_id(node_id), self.nodes[node_id])
            for node_id in sorted(self.nodes.keys())
        ]))

    @asyncio.coroutine
    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()))

    @asyncio.coroutine
    def take_message(self):
        message = yield from self._message_queue.get()
        self._logger.debug('Taking message: {}...'.format(message.type))
        return message

    @asyncio.coroutine
    def send_broadcast(self, message):
        message_bytes = self._serialize(message)
        yield from self._udp_messenger.send_message(message_bytes)

    @asyncio.coroutine
    def send_message(self, node_id, message):
        if node_id in self._lost_nodes:
            self._logger.error(
                'Sending message to node, that seems to be lost! (node id={}, message type={})'
                .format(node_id, message.type))
        self._logger.debug('Sending "{}" message to node {}...'.format(
            message.type, node_id))
        host = self.nodes[node_id]
        success = yield from self._tcp_messenger.send_message(
            host, self._serialize(message))
        if not success:
            self._lost_nodes.add(node_id)
            self._logger.warn(
                'Node seems to be lost! (node_id={})'.format(node_id))
            if self.node_id == node_id:
                self._logger.error('We can not connect with our-self?! ')
        return success

    def get_next_available_node_id(self):
        nodes = sorted(self.nodes.keys())
        next_index = (nodes.index(self.node_id) + 1)
        for candidate_id in nodes[next_index:] + nodes[:next_index]:
            if candidate_id not in self._lost_nodes:
                return candidate_id

    @property
    def node_id(self):
        return str(self._node_id or self._mac)

    @property
    def nodes(self):
        return self._nodes