Example #1
0
class MultiTorrent(Feedback):
    """A MultiTorrent object represents a set of BitTorrent file transfers.
       It acts as a factory for Torrent objects, and it acts as
       the interface through which communication is performed to and from
       torrent file transfers.

       If you wish to instantiate MultiTorrent to download only a single
       torrent then pass is_single_torrent=True.

       If you want to avoid resuming from prior torrent config state then
       pass resume_from_torrent_config = False.
       It will still use fast resume if available.

       """
    def __init__(self,
                 config,
                 rawserver,
                 data_dir,
                 listen_fail_ok=False,
                 init_torrents=True,
                 is_single_torrent=False,
                 resume_from_torrent_config=True,
                 bitstring=None):
        """
         @param config: program-wide configuration object.
         @param rawserver: object that manages main event loop and event
           scheduling.
         @param data_dir: where variable data such as fastresume information
           and GUI state is saved.
         @param listen_fail_ok: if false, a BTFailure is raised if
           a server socket cannot be opened to accept incoming peer
           connections.
         @param init_torrents: restore fast resume state from prior
           instantiations of MultiTorrent.
         @param is_single_torrent: if true then allow only one torrent
           at a time in this MultiTorrent.
         @param resume_from_torrent_config: resume from ui_state files.
        """
        # is_single_torrent will go away when we move MultiTorrent into
        # a separate process, in which case, single torrent applications like
        # curses and console will act as a client to the MultiTorrent daemon.
        #   --Dave

        # init_torrents refers to fast resume rather than torrent config.
        # If init_torrents is set to False, the UI state file is still
        # read and the paths to existing downloads still used. This is
        # not what we want for launchmany.
        #
        # resume_from_torrent_config is separate from
        # is_single_torrent because launchmany must be able to have
        # multiple torrents while not resuming from torrent config
        # state.  If launchmany resumes from torrent config then it
        # saves or seeds from the path in the torrent config even if
        # the file has moved in the directory tree.  Because
        # launchmany has no mechanism for removing torrents other than
        # to change the directory tree, the only way for the user to
        # eliminate the old state is to wipe out the files in the
        # .bittorrent/launchmany-*/ui_state directory.  This is highly
        # counterintuitive.  Best to simply ignore the ui_state
        # directory altogether.  --Dave

        assert isinstance(config, Preferences)
        #assert isinstance(data_dir, unicode)  # temporarily commented -Dave
        assert isinstance(listen_fail_ok, bool)
        assert not (is_single_torrent and resume_from_torrent_config)

        self.config = config
        self.data_dir = data_dir
        self.last_save_time = 0
        self.policies = []
        self.torrents = {}
        self.running = {}
        self.log_root = "core.MultiTorrent"
        self.logger = logging.getLogger(self.log_root)
        self.is_single_torrent = is_single_torrent
        self.resume_from_torrent_config = resume_from_torrent_config
        self.auto_update_policy_index = None
        self.dht = None
        self.rawserver = rawserver
        nattraverser = NatTraverser(self.rawserver)
        self.internet_watcher = get_internet_watcher(self.rawserver)
        self.singleport_listener = SingleportListener(
            self.rawserver,
            nattraverser,
            self.log_root,
            # config['use_local_discovery']
            False)
        self.choker = Choker(self.config, self.rawserver.add_task)
        self.up_ratelimiter = RateLimiter(self.rawserver.add_task)
        self.up_ratelimiter.set_parameters(config['max_upload_rate'],
                                           config['upload_unit_size'])
        self.down_ratelimiter = DownloadRateLimiter(
            config['download_rate_limiter_interval'],
            self.config['max_download_rate'])
        self.total_downmeasure = Measure(config['max_rate_period'])

        self._find_port(listen_fail_ok)

        self.filepool_doneflag = DeferredEvent()
        self.filepool = FilePool(self.filepool_doneflag,
                                 self.rawserver.add_task,
                                 self.rawserver.external_add_task,
                                 config['max_files_open'],
                                 config['num_disk_threads'])
        self.bitstring = bitstring

        if self.resume_from_torrent_config:
            try:
                self._restore_state(init_torrents)
            except BTFailure:
                # don't be retarted.
                self.logger.exception("_restore_state failed")

        def no_dump_set_option(option, value):
            self.set_option(option, value, dump=False)

        self.bandwidth_manager = BandwidthManager(
            self.rawserver.external_add_task,
            config,
            no_dump_set_option,
            self.rawserver.get_remote_endpoints,
            get_rates=self.get_total_rates)

        self.rawserver.add_task(0, self.butle)

    def butle(self):
        policy = None
        try:
            for policy in self.policies:
                policy.butle()
        except:
            # You had something to hide, should have hidden it shouldn't you?
            self.logger.error("Butler error", exc_info=sys.exc_info())
            # Should we remove policies?
            #if policy:
            #    self.policies.remove(policy)
        self.rawserver.add_task(BUTLE_INTERVAL, self.butle)

    def _find_port(self, listen_fail_ok=True):
        """Run BitTorrent on the first available port found starting
           from minport in the range [minport, maxport]."""

        exc_info = None

        self.config['minport'] = max(1024, self.config['minport'])

        self.config['maxport'] = max(self.config['minport'],
                                     self.config['maxport'])

        e = (_("maxport less than minport - no ports to check") +
             (": %s %s" % (self.config['minport'], self.config['maxport'])))

        for port in xrange(self.config['minport'], self.config['maxport'] + 1):
            try:
                self.singleport_listener.open_port(port, self.config)
                ''' ** create ukhashmir  **'''
                '''
                if self.config['start_trackerless_client']:
                    self.dht = UTKhashmir(self.config['bind'],
                                   self.singleport_listener.get_port(),
                                   self.data_dir, self.rawserver,
                                   int(self.config['max_upload_rate'] * 0.01),
                                   rlcount=self.up_ratelimiter.increase_offset,
                                   config=self.config)
                '''
                break
            except socket.error, e:
                exc_info = sys.exc_info()
        else:
    def __init__(self, config, rawserver,
                 data_dir, listen_fail_ok=False, init_torrents=True,
                 is_single_torrent=False, resume_from_torrent_config=True):
        """
         @param config: program-wide configuration object.
         @param rawserver: object that manages main event loop and event
           scheduling.
         @param data_dir: where variable data such as fastresume information
           and GUI state is saved.
         @param listen_fail_ok: if false, a BTFailure is raised if
           a server socket cannot be opened to accept incoming peer
           connections.
         @param init_torrents: restore fast resume state from prior
           instantiations of MultiTorrent.
         @param is_single_torrent: if true then allow only one torrent
           at a time in this MultiTorrent.
         @param resume_from_torrent_config: resume from ui_state files.
        """
        # is_single_torrent will go away when we move MultiTorrent into
        # a separate process, in which case, single torrent applications like
        # curses and console will act as a client to the MultiTorrent daemon.
        #   --Dave

        # init_torrents refers to fast resume rather than torrent config.
        # If init_torrents is set to False, the UI state file is still
        # read and the paths to existing downloads still used. This is
        # not what we want for launchmany.
        #
        # resume_from_torrent_config is separate from
        # is_single_torrent because launchmany must be able to have
        # multiple torrents while not resuming from torrent config
        # state.  If launchmany resumes from torrent config then it
        # saves or seeds from the path in the torrent config even if
        # the file has moved in the directory tree.  Because
        # launchmany has no mechanism for removing torrents other than
        # to change the directory tree, the only way for the user to
        # eliminate the old state is to wipe out the files in the
        # .bittorrent/launchmany-*/ui_state directory.  This is highly
        # counterintuitive.  Best to simply ignore the ui_state
        # directory altogether.  --Dave

        assert isinstance(config, Preferences)
        #assert isinstance(data_dir, unicode)  # temporarily commented -Dave
        assert isinstance(listen_fail_ok, bool)
        assert not (is_single_torrent and resume_from_torrent_config)

        self.config = config
        self.data_dir = data_dir
        self.last_save_time = 0
        self.policies = []
        self.torrents = {}
        self.running = {}
        self.log_root = "core.MultiTorrent"
        self.logger = logging.getLogger(self.log_root)
        self.is_single_torrent = is_single_torrent
        self.resume_from_torrent_config = resume_from_torrent_config
        self.auto_update_policy_index = None
        self.dht = None
        self.rawserver = rawserver
        nattraverser = NatTraverser(self.rawserver)
        self.internet_watcher = get_internet_watcher(self.rawserver)
        self.singleport_listener = SingleportListener(self.rawserver,
                                                      nattraverser,
                                                      self.log_root,
                                                      config['use_local_discovery'])
        self.choker = Choker(self.config, self.rawserver.add_task)
        self.up_ratelimiter = RateLimiter(self.rawserver.add_task)
        self.up_ratelimiter.set_parameters(config['max_upload_rate'],
                                           config['upload_unit_size'])
        self.down_ratelimiter = DownloadRateLimiter(
                                           config['download_rate_limiter_interval'],
                                           self.config['max_download_rate'])
        self.total_downmeasure = Measure(config['max_rate_period'])

        self._find_port(listen_fail_ok)

        self.filepool_doneflag = DeferredEvent()
        self.filepool = FilePool(self.filepool_doneflag,
                                 self.rawserver.add_task,
                                 self.rawserver.external_add_task,
                                 config['max_files_open'],
                                 config['num_disk_threads'])

        if self.resume_from_torrent_config:
            try:
                self._restore_state(init_torrents)
            except BTFailure:
                # don't be retarted.
                self.logger.exception("_restore_state failed")

        def no_dump_set_option(option, value):
            self.set_option(option, value, dump=False)

        self.bandwidth_manager = BandwidthManager(
            self.rawserver.external_add_task, config,
            no_dump_set_option, self.rawserver.get_remote_endpoints,
            get_rates=self.get_total_rates )

        self.rawserver.add_task(0, self.butle)
Example #3
0
    def __init__(self,
                 config,
                 rawserver,
                 data_dir,
                 listen_fail_ok=False,
                 init_torrents=True,
                 is_single_torrent=False,
                 resume_from_torrent_config=True,
                 bitstring=None):
        """
         @param config: program-wide configuration object.
         @param rawserver: object that manages main event loop and event
           scheduling.
         @param data_dir: where variable data such as fastresume information
           and GUI state is saved.
         @param listen_fail_ok: if false, a BTFailure is raised if
           a server socket cannot be opened to accept incoming peer
           connections.
         @param init_torrents: restore fast resume state from prior
           instantiations of MultiTorrent.
         @param is_single_torrent: if true then allow only one torrent
           at a time in this MultiTorrent.
         @param resume_from_torrent_config: resume from ui_state files.
        """
        # is_single_torrent will go away when we move MultiTorrent into
        # a separate process, in which case, single torrent applications like
        # curses and console will act as a client to the MultiTorrent daemon.
        #   --Dave

        # init_torrents refers to fast resume rather than torrent config.
        # If init_torrents is set to False, the UI state file is still
        # read and the paths to existing downloads still used. This is
        # not what we want for launchmany.
        #
        # resume_from_torrent_config is separate from
        # is_single_torrent because launchmany must be able to have
        # multiple torrents while not resuming from torrent config
        # state.  If launchmany resumes from torrent config then it
        # saves or seeds from the path in the torrent config even if
        # the file has moved in the directory tree.  Because
        # launchmany has no mechanism for removing torrents other than
        # to change the directory tree, the only way for the user to
        # eliminate the old state is to wipe out the files in the
        # .bittorrent/launchmany-*/ui_state directory.  This is highly
        # counterintuitive.  Best to simply ignore the ui_state
        # directory altogether.  --Dave

        assert isinstance(config, Preferences)
        #assert isinstance(data_dir, unicode)  # temporarily commented -Dave
        assert isinstance(listen_fail_ok, bool)
        assert not (is_single_torrent and resume_from_torrent_config)

        self.config = config
        self.data_dir = data_dir
        self.last_save_time = 0
        self.policies = []
        self.torrents = {}
        self.running = {}
        self.log_root = "core.MultiTorrent"
        self.logger = logging.getLogger(self.log_root)
        self.is_single_torrent = is_single_torrent
        self.resume_from_torrent_config = resume_from_torrent_config
        self.auto_update_policy_index = None
        self.dht = None
        self.rawserver = rawserver
        nattraverser = NatTraverser(self.rawserver)
        self.internet_watcher = get_internet_watcher(self.rawserver)
        self.singleport_listener = SingleportListener(
            self.rawserver,
            nattraverser,
            self.log_root,
            # config['use_local_discovery']
            False)
        self.choker = Choker(self.config, self.rawserver.add_task)
        self.up_ratelimiter = RateLimiter(self.rawserver.add_task)
        self.up_ratelimiter.set_parameters(config['max_upload_rate'],
                                           config['upload_unit_size'])
        self.down_ratelimiter = DownloadRateLimiter(
            config['download_rate_limiter_interval'],
            self.config['max_download_rate'])
        self.total_downmeasure = Measure(config['max_rate_period'])

        self._find_port(listen_fail_ok)

        self.filepool_doneflag = DeferredEvent()
        self.filepool = FilePool(self.filepool_doneflag,
                                 self.rawserver.add_task,
                                 self.rawserver.external_add_task,
                                 config['max_files_open'],
                                 config['num_disk_threads'])
        self.bitstring = bitstring

        if self.resume_from_torrent_config:
            try:
                self._restore_state(init_torrents)
            except BTFailure:
                # don't be retarted.
                self.logger.exception("_restore_state failed")

        def no_dump_set_option(option, value):
            self.set_option(option, value, dump=False)

        self.bandwidth_manager = BandwidthManager(
            self.rawserver.external_add_task,
            config,
            no_dump_set_option,
            self.rawserver.get_remote_endpoints,
            get_rates=self.get_total_rates)

        self.rawserver.add_task(0, self.butle)
class MultiTorrent(Feedback):
    """A MultiTorrent object represents a set of BitTorrent file transfers.
       It acts as a factory for Torrent objects, and it acts as
       the interface through which communication is performed to and from
       torrent file transfers.

       If you wish to instantiate MultiTorrent to download only a single
       torrent then pass is_single_torrent=True.

       If you want to avoid resuming from prior torrent config state then
       pass resume_from_torrent_config = False.
       It will still use fast resume if available.

       """

    def __init__(self, config, rawserver,
                 data_dir, listen_fail_ok=False, init_torrents=True,
                 is_single_torrent=False, resume_from_torrent_config=True):
        """
         @param config: program-wide configuration object.
         @param rawserver: object that manages main event loop and event
           scheduling.
         @param data_dir: where variable data such as fastresume information
           and GUI state is saved.
         @param listen_fail_ok: if false, a BTFailure is raised if
           a server socket cannot be opened to accept incoming peer
           connections.
         @param init_torrents: restore fast resume state from prior
           instantiations of MultiTorrent.
         @param is_single_torrent: if true then allow only one torrent
           at a time in this MultiTorrent.
         @param resume_from_torrent_config: resume from ui_state files.
        """
        # is_single_torrent will go away when we move MultiTorrent into
        # a separate process, in which case, single torrent applications like
        # curses and console will act as a client to the MultiTorrent daemon.
        #   --Dave

        # init_torrents refers to fast resume rather than torrent config.
        # If init_torrents is set to False, the UI state file is still
        # read and the paths to existing downloads still used. This is
        # not what we want for launchmany.
        #
        # resume_from_torrent_config is separate from
        # is_single_torrent because launchmany must be able to have
        # multiple torrents while not resuming from torrent config
        # state.  If launchmany resumes from torrent config then it
        # saves or seeds from the path in the torrent config even if
        # the file has moved in the directory tree.  Because
        # launchmany has no mechanism for removing torrents other than
        # to change the directory tree, the only way for the user to
        # eliminate the old state is to wipe out the files in the
        # .bittorrent/launchmany-*/ui_state directory.  This is highly
        # counterintuitive.  Best to simply ignore the ui_state
        # directory altogether.  --Dave

        assert isinstance(config, Preferences)
        #assert isinstance(data_dir, unicode)  # temporarily commented -Dave
        assert isinstance(listen_fail_ok, bool)
        assert not (is_single_torrent and resume_from_torrent_config)

        self.config = config
        self.data_dir = data_dir
        self.last_save_time = 0
        self.policies = []
        self.torrents = {}
        self.running = {}
        self.log_root = "core.MultiTorrent"
        self.logger = logging.getLogger(self.log_root)
        self.is_single_torrent = is_single_torrent
        self.resume_from_torrent_config = resume_from_torrent_config
        self.auto_update_policy_index = None
        self.dht = None
        self.rawserver = rawserver
        nattraverser = NatTraverser(self.rawserver)
        self.internet_watcher = get_internet_watcher(self.rawserver)
        self.singleport_listener = SingleportListener(self.rawserver,
                                                      nattraverser,
                                                      self.log_root,
                                                      config['use_local_discovery'])
        self.choker = Choker(self.config, self.rawserver.add_task)
        self.up_ratelimiter = RateLimiter(self.rawserver.add_task)
        self.up_ratelimiter.set_parameters(config['max_upload_rate'],
                                           config['upload_unit_size'])
        self.down_ratelimiter = DownloadRateLimiter(
                                           config['download_rate_limiter_interval'],
                                           self.config['max_download_rate'])
        self.total_downmeasure = Measure(config['max_rate_period'])

        self._find_port(listen_fail_ok)

        self.filepool_doneflag = DeferredEvent()
        self.filepool = FilePool(self.filepool_doneflag,
                                 self.rawserver.add_task,
                                 self.rawserver.external_add_task,
                                 config['max_files_open'],
                                 config['num_disk_threads'])

        if self.resume_from_torrent_config:
            try:
                self._restore_state(init_torrents)
            except BTFailure:
                # don't be retarted.
                self.logger.exception("_restore_state failed")

        def no_dump_set_option(option, value):
            self.set_option(option, value, dump=False)

        self.bandwidth_manager = BandwidthManager(
            self.rawserver.external_add_task, config,
            no_dump_set_option, self.rawserver.get_remote_endpoints,
            get_rates=self.get_total_rates )

        self.rawserver.add_task(0, self.butle)


    def butle(self):
        policy = None
        try:
            for policy in self.policies:
                policy.butle()
        except:
            # You had something to hide, should have hidden it shouldn't you?
            self.logger.error("Butler error", exc_info=sys.exc_info())
            # Should we remove policies?
            #if policy:
            #    self.policies.remove(policy)
        self.rawserver.add_task(BUTLE_INTERVAL, self.butle)


    def _find_port(self, listen_fail_ok=True):
        """Run BitTorrent on the first available port found starting
           from minport in the range [minport, maxport]."""

        exc_info = None

        self.config['minport'] = max(1024, self.config['minport'])

        self.config['maxport'] = max(self.config['minport'],
                                     self.config['maxport'])

        e = (_("maxport less than minport - no ports to check") +
             (": %s %s" % (self.config['minport'], self.config['maxport'])))

        for port in xrange(self.config['minport'], self.config['maxport'] + 1):
            try:
                self.singleport_listener.open_port(port, self.config)
                if self.config['start_trackerless_client']:
                    self.dht = UTKhashmir(self.config['bind'],
                                   self.singleport_listener.get_port(),
                                   self.data_dir, self.rawserver,
                                   int(self.config['max_upload_rate'] * 0.01),
                                   rlcount=self.up_ratelimiter.increase_offset,
                                   config=self.config)
                break
            except socket.error, e:
                exc_info = sys.exc_info()
        else: