Example #1
0
    def test_udp(self):
        '''It should be able to send itself a udp packet through events'''

        event_reactor = EventReactor()
        server = UDPServer(event_reactor)
        client = UDPClient()

        server.start()
        reactor_thread = threading.Thread(target=event_reactor.start)
        reactor_thread.daemon = True
        reactor_thread.start()

        data = None

        def my_callback(event_id, address, data_):
            nonlocal data

            data = data_  # @UnusedVariable

            event_reactor.put(EventReactor.STOP_ID)

        event_reactor.register_handler(
            bytestag.network.UDP_INBOUND_EVENT, my_callback)

        client.send(server.server_address, b'hello')

        reactor_thread.join(1)
        event_reactor.put(EventReactor.STOP_ID)

        self.assertEqual(data, b'hello')
Example #2
0
    def __init__(self, cache_dir, address=('0.0.0.0', 0), node_id=None,
    known_node_address=None, initial_scan=False, config_dir=None,
    use_port_forwarding=False):
        threading.Thread.__init__(self)
        self.daemon = True
        self.name = '{}.{}'.format(__name__, Client.__name__)
        self._event_reactor = EventReactor()
        self._node_id = node_id or KeyBytes()
        self._network = Network(self._event_reactor, address=address)
        self._cache_table = DatabaseKVPTable(
            os.path.join(cache_dir, 'cache.db'))
        self._shared_files_table = SharedFilesKVPTable(
            os.path.join(cache_dir, 'shared_files.db'))
        self._aggregated_kvp_table = AggregatedKVPTable(self._cache_table,
            [self._cache_table, self._shared_files_table])
        self._known_node_address = known_node_address
        self._upload_slot = FnTaskSlot()
        self._download_slot = FnTaskSlot()
        self._initial_scan = initial_scan
        self._config_dir = config_dir or basedir.config_dir
        self._upnp_client = None
        
        if use_port_forwarding:
            if not miniupnpc:
                warnings.warn(
                    'miniupnpc not found. Port forwarding is unavailable!')
            else:
                self._init_port_forwarding()
                self._hook_port_forwarding_cleanup()

        self._init()
Example #3
0
    def test_reactor(self):
        '''It should process 1 event and then stop'''

        my_id = EventID('my_id')
        self.test_value = False

        def my_callback(event_id):
            self.assertEqual(my_id, event_id)
            self.test_value = True

        event_reactor = EventReactor()
        event_reactor.register_handler(my_id, my_callback)
        event_reactor.put(my_id)
        event_reactor.put(EventReactor.STOP_ID)
        event_reactor.start()
        self.assertTrue(self.test_value)
Example #4
0
class Client(threading.Thread):
    '''Client interface.

    :warning: this class is under development.
    '''

    def __init__(self, cache_dir, address=('0.0.0.0', 0), node_id=None,
    known_node_address=None, initial_scan=False, config_dir=None,
    use_port_forwarding=False):
        threading.Thread.__init__(self)
        self.daemon = True
        self.name = '{}.{}'.format(__name__, Client.__name__)
        self._event_reactor = EventReactor()
        self._node_id = node_id or KeyBytes()
        self._network = Network(self._event_reactor, address=address)
        self._cache_table = DatabaseKVPTable(
            os.path.join(cache_dir, 'cache.db'))
        self._shared_files_table = SharedFilesKVPTable(
            os.path.join(cache_dir, 'shared_files.db'))
        self._aggregated_kvp_table = AggregatedKVPTable(self._cache_table,
            [self._cache_table, self._shared_files_table])
        self._known_node_address = known_node_address
        self._upload_slot = FnTaskSlot()
        self._download_slot = FnTaskSlot()
        self._initial_scan = initial_scan
        self._config_dir = config_dir or basedir.config_dir
        self._upnp_client = None
        
        if use_port_forwarding:
            if not miniupnpc:
                warnings.warn(
                    'miniupnpc not found. Port forwarding is unavailable!')
            else:
                self._init_port_forwarding()
                self._hook_port_forwarding_cleanup()

        self._init()

    @property
    def cache_table(self):
        '''The :class:`DatabaseKVPTable`'''
        return self._cache_table

    @property
    def shared_files_table(self):
        '''The :class:`SharedFilesKVPTable`'''

        return self._shared_files_table

    @property
    def upload_slot(self):
        '''The :class:`.FnTaskSlot` which holds :class:`.StoreValueTask`.'''

        return self._upload_slot

    @property
    def download_slot(self):
        '''Download slot.

        :see: :func:`.DHTNetwork.download_slot`
        '''

        return self._download_slot

    @property
    def dht_network(self):
        return self._dht_network

    @property
    def network(self):
        return self._network

    def _init_port_forwarding(self):
        upnp_client = miniupnpc.UPnP()
        self._upnp_client = upnp_client
        upnp_client.discoverdelay = 200

        num_devices = upnp_client.discover()

        _logger.debug('UPnP IGD count=%s', num_devices)

        if not num_devices:
            return

        upnp_client.selectigd()

        port = self._network.server_address[1]

        result = upnp_client.addportmapping(port, 'UDP', upnp_client.lanaddr,
            port, 'Bytestag', '')

        if result:
            _logger.info('UPnP port forwarded %s:%s', upnp_client.lanaddr,
                port)
        else:
            _logger.warning('UPnP port forward failed %s:%s',
                upnp_client.lanaddr, port)

    def _init(self):
        self._dht_network = DHTNetwork(self._event_reactor,
            self._aggregated_kvp_table, self._node_id, self._network,
            self._download_slot)
        self._publisher = Publisher(self._event_reactor, self._dht_network,
            self._aggregated_kvp_table, self._upload_slot)
        self._replicator = Replicator(self._event_reactor, self._dht_network,
            self._aggregated_kvp_table, self._upload_slot)
        self._downloader = Downloader(self._event_reactor, self._config_dir,
            self._dht_network, self._download_slot)

    def _hook_port_forwarding_cleanup(self):
        atexit.register(self._cleanup_port_forwarding)

    def run(self):
        if self._known_node_address:
            self._dht_network.join_network(self._known_node_address)
            # TODO: put warning if join fails, but don't check on
            # the same thread as the event_reactor

        if self._initial_scan:
            self._shared_files_table.hash_directories()

        self._event_reactor.start()

    def stop(self):
        self._event_reactor.put(EventReactor.STOP_ID)

        if self._upnp_client:
            self._cleanup_port_forwarding()

    def _cleanup_port_forwarding(self, *args):
        if self._upnp_client:
            upnp_client = self._upnp_client

            self._upnp_client = None

            upnp_client.deleteportmapping(self._network.server_address[1],
                'UDP')