Exemple #1
0
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()
Exemple #2
0
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())