def main(): arg_parser = argparse.ArgumentParser( description='Runs an instance of a Bytestag server.') arg_parser.add_argument('--cache-dir', default=bytestag.basedir.cache_dir, help='directory where temporary files are stored') # arg_parser.add_argument('--config-dir', # default=bytestag.basedir.config_dir, # help='directory where configuration files are stored') # arg_parser.add_argument('--data-dir', default=bytestag.basedir.data_dir, # help='directory where program files and plugins are stored') arg_parser.add_argument('--port', type=int, default=0, help='port number of the listening server') arg_parser.add_argument('--host', default='0.0.0.0', help='hostname or IP address of the listening server') arg_parser.add_argument('--cache-size', type=int, default=2 ** 36, help='maximum size, in bytes, of the cache') # arg_parser.add_argument('--max-disk-ratio', type=float, default=0.75, # help='maximum free disk space that may be used') arg_parser.add_argument('--share-dir', nargs='*', help='directory to share') arg_parser.add_argument('--known-node', help='initial known contact') arg_parser.add_argument('--node-id', help='node id of this server') arg_parser.add_argument('--log-level', help='Python logging level') arg_parser.add_argument('--log-filename', help='Python logging filename') arg_parser.add_argument('--initial-scan', default=False, action='store_true', help='Scan shared directories on startup') arg_parser.add_argument('--port-forwarding', default=False, action='store_true', help='Enable UPnP IGD port forwarding') args = arg_parser.parse_args() if args.log_level: log_conf = dict(level=args.log_level, format='%(levelname)s %(name)s %(module)s:%(lineno)d %(message)s') if args.log_filename: log_conf['filename'] = args.log_filename logging.basicConfig(**log_conf) if args.known_node: known_node_address, known_node_port = args.known_node.split(':', 1) known_node_port = int(known_node_port) known_node_address = (known_node_address, known_node_port) else: known_node_address = None client = Client(args.cache_dir, known_node_address=known_node_address, address=(args.host, args.port), node_id=KeyBytes(args.node_id or True), initial_scan=args.initial_scan, use_port_forwarding=args.port_forwarding ) client.cache_table.max_size = args.cache_size if args.share_dir: share_dirs = map(os.path.abspath, args.share_dir) client.shared_files_table.shared_directories.extend(share_dirs) client.start() client.join()
class DHTClientController(BaseController, metaclass=abc.ABCMeta): '''Provides access to :class:`bytestag.client.Client`''' DISCONNECTED, CONNECTING, CONNECTED = range(3) CONNECTING_MSG = 'Connecting to network…' CONNECTED_MSG = 'Connected to network.' DISCONNECTED_MSG = 'Disconnected from network.' def __init__(self, application): BaseController.__init__(self, application) self._observer = Observer() config = self.application.singletons[ConfigController] host = config.get('network', 'host') port = int(config.get('network', 'port')) node_id = KeyBytes(config.get('network', 'node_id')) use_port_forwarding = config.get('network', 'enable_port_forwarding', as_bool=True) os.makedirs(basedir.cache_dir, mode=0o777, exist_ok=True) self._client = Client(basedir.cache_dir, (host, port), node_id, use_port_forwarding=use_port_forwarding) self._client.start() thread = threading.Timer(1, self.connect) thread.daemon = True thread.start() @property def client(self): return self._client @property def observer(self): return self._observer def connect(self): t = 2 nodes = self._get_known_nodes_from_config() random.shuffle(nodes) nodes = itertools.cycle(nodes) for address in nodes: self.observer(DHTClientController.CONNECTING) join_network_task = self._client.dht_network.join_network(address) result = join_network_task.result() if result: invoke_in_main_thread(self.observer, DHTClientController.CONNECTED) break else: invoke_in_main_thread(self.observer, DHTClientController.DISCONNECTED) t *= 2 t = min(3600, t) time.sleep(t) def stop(self, wait=True): self._client.stop() self._client.network._pool_executor.shutdown(wait) self._client.dht_network._pool_executor.shutdown(wait) self._client.join() def _get_long_lived_nodes(self): l = [] for bucket in self._client.dht_network.routing_table.buckets: if bucket.nodes: l.append(bucket.nodes[-1].address) return l def _get_known_nodes_from_config(self): config = self.application.singletons[ConfigController] config_parser = config.config_parser l = [] l.append((config.get('network', 'default_known_node_host'), int(config.get('network', 'default_known_node_port')))) for key in config_parser['known_nodes'].keys(): if key.startswith('node'): port_key = 'port{}'.format(key[4:]) l.append((config.get('shared_files', key), int(config.get('shared_files', port_key)))) return l def _save_known_nodes_to_config(self, nodes): config = self.application.singletons[ConfigController] config_parser = config.config_parser config_parser['known_nodes'] = {} for i in range(len(nodes)): host, port = nodes[i] config.set('known_nodes', 'host{}'.format(i + 1), host) config.set('known_nodes', 'port{}'.format(i + 1), port) config.save() def _save_long_lived_nodes(self): self._save_known_nodes_to_config(self._get_long_lived_nodes())