# -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 from threading import Thread from queue import Queue from tornado.ioloop import PeriodicCallback from . import directory from .localnodes import LocalNodes from .link import can_connect, node_url import logging logger = logging.getLogger('lookup') class Nodes(Thread): _active = True _local = None _nodes = {} def __init__(self): self._local = LocalNodes() Thread.__init__(self) self._q = Queue() self.daemon = True self._cleanup = PeriodicCallback(lambda: self._q.put(''), 120000) self._cleanup.start() self.start() def cleanup(self): if self._active: self._local.cleanup() for id in list(self._nodes.keys()): if id in self._local._nodes: del self._nodes[id] if not can_connect(self._nodes[id]): del self._nodes[id] if not self._active: break def fingerprint(self, id): node = self.get(id) if node: return node['cert'] return None def get(self, id): # check local nodes node = self._local.get(id) if not node: # check local cache node = self._nodes.get(id) # lookup directory if not node: try: node = directory.get(id) except: logger.debug('directory failed', exc_info=1) node = None if node: self._nodes[id] = node if node: node['url'] = node_url(node) return node def info(self): l = self._local.info() return { 'local': l, 'nodes': sorted(set(list(self._nodes.keys()) + l)) } def join(self): self._active = False self._q.put('') self._local.join() return Thread.join(self) def run(self): while self._active: self._q.get() if self._active: self.cleanup() def url(self, user_id): node = self.get(user_id) if node: url = node['url'] else: url = None logger.debug('resolved %s -> %s', user_id, url) return url