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