Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- # # Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me> # # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. #
AUTH_LEVELS_MAPPING_REVERSE, AuthManager)
# Create the client fingerprint
# Start the libtorrent session
# Load the session state if available
# --- Set session settings --- 'deluge_version': deluge.common.get_version(), 'lt_version': self.get_libtorrent_version().rpartition(".")[0] } # No SSL torrent support in code so disable the listen port. # On Windows OS set the disk I/O read/write to bypass OS cache settings["disk_io_write_mode"] = lt.io_buffer_mode_t.disable_os_cache settings["disk_io_read_mode"] = lt.io_buffer_mode_t.disable_os_cache
# --- libtorrent plugins --- # Allows peers to download the metadata from the swarm directly # Ban peers that sends bad data
# Create the components
# New release check information
# Get the core config
# If there was an interface value from the command line, use it, but # store the one in the config so we can restore it on shutdown if deluge.common.is_ip(listen_interface): self.__old_interface = self.config["listen_interface"] self.config["listen_interface"] = listen_interface else: log.error("Invalid listen interface (must be IP Address): %s", listen_interface)
"""Starts the core""" # New release check information
# Save the libtorrent session state
# We stored a copy of the old interface value self.config["listen_interface"] = self.__old_interface
# Make sure the config file has been saved
"""Saves the libtorrent session state"""
log.debug("Creating backup of %s at: %s", filename, filepath_bak) shutil.copy2(filepath, filepath_bak) except IOError as ex: log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) else: except (IOError, EOFError) as ex: log.error("Unable to save %s: %s", filename, ex) if os.path.isfile(filepath_bak): log.info("Restoring backup of %s from: %s", filename, filepath_bak) shutil.move(filepath_bak, filepath)
"""Loads the libtorrent session state"""
state = lt.bdecode(_file.read()) else: log.info("Successfully loaded %s: %s", filename, _filepath) self.session.load_state(state) return
log.debug("get_new_release") from urllib2 import urlopen, URLError try: self.new_release = urlopen("http://download.deluge-torrent.org/version-1.0").read().strip() except URLError as ex: log.debug("Unable to get release info from website: %s", ex) return self.check_new_release()
if self.new_release: log.debug("new_release: %s", self.new_release) if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()): component.get("EventManager").emit(NewVersionAvailableEvent(self.new_release)) return self.new_release return False
# Exported Methods def add_torrent_file(self, filename, filedump, options): """Adds a torrent file to the session.
Args: filename (str): the filename of the torrent filedump (str): A base64 encoded string of the torrent file contents options (dict): The options to apply to the torrent on add
Returns: str: The torrent_id or None
""" except Exception as ex: log.error("There was an error decoding the filedump string!") log.exception(ex)
filedump=filedump, options=options, filename=filename ) except Exception as ex: log.error("There was an error adding the torrent file %s", filename) log.exception(ex) torrent_id = None
""" Adds a torrent from a url. Deluge will attempt to fetch the torrent from url prior to adding it to the session.
:param url: the url pointing to the torrent file :type url: string :param options: the options to apply to the torrent on add :type options: dict :param headers: any optional headers to send :type headers: dict
:returns: a Deferred which returns the torrent_id as a str or None """
# We got the file, so add it to the session except OSError as ex: log.warning("Couldn't remove temp file: %s", ex)
new_url, tempfile.mkstemp()[1], headers=headers, force_filename=True ) result = download_file( url, tempfile.mkstemp()[1], headers=headers, force_filename=True, allow_compression=False ) result.addCallbacks(on_download_success, on_download_fail) else: # Log the error and pass the failure onto the client
url, tempfile.mkstemp()[1], headers=headers, force_filename=True )
def add_torrent_magnet(self, uri, options): """ Adds a torrent from a magnet link.
:param uri: the magnet link :type uri: string :param options: the options to apply to the torrent on add :type options: dict
:returns: the torrent_id :rtype: string
"""
def remove_torrent(self, torrent_id, remove_data): """Removes a torrent from the session.
Args: torrent_id (str): The torrent ID to remove remove_data (bool): If True, remove the downloaded data.
Returns: bool: True if removed successfully
Raises: InvalidTorrentError: if the torrent_id does not exist in the session
"""
def remove_torrents(self, torrent_ids, remove_data): """Remove torrents from the session.
Args: torrent_ids (list): The torrent IDs to remove remove_data (bool, optional): If True, remove the downloaded data, defaults to False. defer (bool): if True, do task.deferLater on the function that removes the torrents.
Returns: list: a list containing all the errors, empty list if no errors occured
"""
# Save the session state
def get_session_status(self, keys): """ Gets the session status values for 'keys', these keys are taking from libtorrent's session status.
See: http://www.rasterbar.com/products/libtorrent/manual.html#status
:param keys: the keys for which we want values :type keys: list :returns: a dictionary of {key: value, ...} :rtype: dict
"""
def get_cache_status(self): """ Returns a dictionary of the session's cache status.
:returns: the cache status :rtype: dict
"""
# Add in a couple ratios cache["writes"])) / float(cache["blocks_written"])
def force_reannounce(self, torrent_ids): log.debug("Forcing reannouncment to: %s", torrent_ids) for torrent_id in torrent_ids: self.torrentmanager[torrent_id].force_reannounce()
def pause_torrent(self, torrent_ids): log.debug("Pausing: %s", torrent_ids) for torrent_id in torrent_ids: if not self.torrentmanager[torrent_id].pause(): log.warning("Error pausing torrent %s", torrent_id)
def connect_peer(self, torrent_id, ip, port): log.debug("adding peer %s to %s", ip, torrent_id) if not self.torrentmanager[torrent_id].connect_peer(ip, port): log.warning("Error adding peer %s:%s to %s", ip, port, torrent_id)
def move_storage(self, torrent_ids, dest): log.debug("Moving storage %s to %s", torrent_ids, dest) for torrent_id in torrent_ids: if not self.torrentmanager[torrent_id].move_storage(dest): log.warning("Error moving torrent %s to %s", torrent_id, dest)
def pause_session(self): """Pause all torrents in the session""" if not self.session.is_paused(): self.session.pause() component.get("EventManager").emit(SessionPausedEvent())
def resume_session(self): """Resume all torrents in the session""" if self.session.is_paused(): self.session.resume() component.get("EventManager").emit(SessionResumedEvent())
def resume_torrent(self, torrent_ids): log.debug("Resuming: %s", torrent_ids) for torrent_id in torrent_ids: self.torrentmanager[torrent_id].resume()
try: status = self.torrentmanager[torrent_id].get_status(torrent_keys, diff, update=update, all_keys=all_keys) except KeyError: import traceback traceback.print_exc() # Torrent was probaly removed meanwhile return {}
# Ask the plugin manager to fill in the plugin keys if len(plugin_keys) > 0: status.update(self.pluginmanager.get_status(torrent_id, plugin_keys)) return status
torrent_keys, plugin_keys = self.torrentmanager.separate_keys(keys, [torrent_id]) return self.create_torrent_status(torrent_id, torrent_keys, plugin_keys, diff=diff, update=True, all_keys=not keys)
""" returns all torrents , optionally filtered by filter_dict. """ torrent_ids = self.filtermanager.filter_torrent_ids(filter_dict) d = self.torrentmanager.torrents_status_update(torrent_ids, keys, diff=diff)
def add_plugin_fields(args): status_dict, plugin_keys = args # Ask the plugin manager to fill in the plugin keys if len(plugin_keys) > 0: for key in status_dict.keys(): status_dict[key].update(self.pluginmanager.get_status(key, plugin_keys)) return status_dict d.addCallback(add_plugin_fields) return d
""" returns {field: [(value,count)] } for use in sidebar(s) """ return self.filtermanager.get_filter_tree(show_zero_hits, hide_cat)
def get_session_state(self): """Returns a list of torrent_ids in the session.""" # Get the torrent list from the TorrentManager
def get_config(self): """Get all the preferences as a dictionary""" return self.config.config
def get_config_value(self, key): """Get the config value for key"""
def get_config_values(self, keys): """Get the config values for the entered keys"""
def set_config(self, config): """Set the config with values from dictionary""" # Load all the values into the configuration
def get_listen_port(self): """Returns the active listen port"""
def get_i2p_proxy(self): """Returns the active listen port""" i2p_settings = self.session.i2p_proxy() i2p_dict = {"hostname": i2p_settings.hostname, "port": i2p_settings.port} return i2p_dict
def get_proxy(self): """Returns the active listen port""" proxy_settings = self.session.proxy() proxy_dict = { "type": int(proxy_settings.type), "hostname": proxy_settings.hostname, "username": proxy_settings.username, "password": proxy_settings.password, "port": proxy_settings.port, "proxy_hostnames": proxy_settings.proxy_hostnames, "proxy_peer_connections": proxy_settings.proxy_peer_connections } return proxy_dict
def get_available_plugins(self): """Returns a list of plugins available in the core""" return self.pluginmanager.get_available_plugins()
def get_enabled_plugins(self): """Returns a list of enabled plugins in the core""" return self.pluginmanager.get_enabled_plugins()
def enable_plugin(self, plugin): self.pluginmanager.enable_plugin(plugin) return None
def disable_plugin(self, plugin): self.pluginmanager.disable_plugin(plugin) return None
def force_recheck(self, torrent_ids): """Forces a data recheck on torrent_ids""" for torrent_id in torrent_ids: self.torrentmanager[torrent_id].force_recheck()
def set_torrent_options(self, torrent_ids, options): """Sets the torrent options for torrent_ids""" for torrent_id in torrent_ids: self.torrentmanager[torrent_id].set_options(options)
def set_torrent_trackers(self, torrent_id, trackers): """Sets a torrents tracker list. trackers will be [{"url", "tier"}]""" return self.torrentmanager[torrent_id].set_trackers(trackers)
def set_torrent_max_connections(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets a torrents max number of connections""" return self.torrentmanager[torrent_id].set_max_connections(value)
def set_torrent_max_upload_slots(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets a torrents max number of upload slots""" return self.torrentmanager[torrent_id].set_max_upload_slots(value)
def set_torrent_max_upload_speed(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets a torrents max upload speed""" return self.torrentmanager[torrent_id].set_max_upload_speed(value)
def set_torrent_max_download_speed(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets a torrents max download speed""" return self.torrentmanager[torrent_id].set_max_download_speed(value)
def set_torrent_file_priorities(self, torrent_id, priorities): # Deprecated method, use set_torrent_options instead # Used by at least one 3rd party plugin: """Sets a torrents file priorities""" return self.torrentmanager[torrent_id].set_file_priorities(priorities)
def set_torrent_prioritize_first_last(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets a higher priority to the first and last pieces""" return self.torrentmanager[torrent_id].set_prioritize_first_last_pieces(value)
def set_torrent_auto_managed(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the auto managed flag for queueing purposes""" return self.torrentmanager[torrent_id].set_auto_managed(value)
def set_torrent_stop_at_ratio(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the torrent to stop at 'stop_ratio'""" return self.torrentmanager[torrent_id].set_stop_at_ratio(value)
def set_torrent_stop_ratio(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the ratio when to stop a torrent if 'stop_at_ratio' is set""" return self.torrentmanager[torrent_id].set_stop_ratio(value)
def set_torrent_remove_at_ratio(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the torrent to be removed at 'stop_ratio'""" return self.torrentmanager[torrent_id].set_remove_at_ratio(value)
def set_torrent_move_completed(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the torrent to be moved when completed""" return self.torrentmanager[torrent_id].set_move_completed(value)
def set_torrent_move_completed_path(self, torrent_id, value): # Deprecated method, use set_torrent_options instead """Sets the path for the torrent to be moved when completed""" return self.torrentmanager[torrent_id].set_move_completed_path(value)
def set_owner(self, torrent_ids, username): """Set's the torrent owner.
:param torrent_id: the torrent_id of the torrent to remove :type torrent_id: string :param username: the new owner username :type username: string
:raises DelugeError: if the username is not known """ if not self.authmanager.has_account(username): raise DelugeError("Username \"%s\" is not known." % username) if isinstance(torrent_ids, basestring): torrent_ids = [torrent_ids] for torrent_id in torrent_ids: self.torrentmanager[torrent_id].set_owner(username) return None
def get_path_size(self, path): """Returns the size of the file or folder 'path' and -1 if the path is unaccessible (non-existent or insufficient privs)""" return deluge.common.get_path_size(path)
def create_torrent(self, path, tracker, piece_length, comment, target, webseeds, private, created_by, trackers, add_to_session):
log.debug("creating torrent..") threading.Thread(target=self._create_torrent_thread, args=( path, tracker, piece_length, comment, target, webseeds, private, created_by, trackers, add_to_session)).start()
webseeds, private, created_by, trackers, add_to_session): import deluge.metafile deluge.metafile.make_meta_file( path, tracker, piece_length, comment=comment, target=target, webseeds=webseeds, private=private, created_by=created_by, trackers=trackers) log.debug("torrent created!") if add_to_session: options = {} options["download_location"] = os.path.split(path)[0] self.add_torrent_file(os.path.split(target)[1], open(target, "rb").read(), options)
def upload_plugin(self, filename, filedump): """This method is used to upload new plugins to the daemon. It is used when connecting to the daemon remotely and installing a new plugin on the client side. 'plugin_data' is a xmlrpc.Binary object of the file data, ie, plugin_file.read()"""
try: filedump = base64.decodestring(filedump) except Exception as ex: log.error("There was an error decoding the filedump string!") log.exception(ex) return
f = open(os.path.join(get_config_dir(), "plugins", filename), "wb") f.write(filedump) f.close() component.get("CorePluginManager").scan_for_plugins()
def rescan_plugins(self): """ Rescans the plugin folders for new plugins """ component.get("CorePluginManager").scan_for_plugins()
def rename_files(self, torrent_id, filenames): """ Rename files in torrent_id. Since this is an asynchronous operation by libtorrent, watch for the TorrentFileRenamedEvent to know when the files have been renamed.
:param torrent_id: the torrent_id to rename files :type torrent_id: string :param filenames: a list of index, filename pairs :type filenames: ((index, filename), ...)
:raises InvalidTorrentError: if torrent_id is invalid
""" if torrent_id not in self.torrentmanager.torrents: raise InvalidTorrentError("torrent_id is not in session")
self.torrentmanager[torrent_id].rename_files(filenames)
def rename_folder(self, torrent_id, folder, new_folder): """ Renames the 'folder' to 'new_folder' in 'torrent_id'. Watch for the TorrentFolderRenamedEvent which is emitted when the folder has been renamed successfully.
:param torrent_id: the torrent to rename folder in :type torrent_id: string :param folder: the folder to rename :type folder: string :param new_folder: the new folder name :type new_folder: string
:raises InvalidTorrentError: if the torrent_id is invalid
""" if torrent_id not in self.torrentmanager.torrents: raise InvalidTorrentError("torrent_id is not in session")
self.torrentmanager[torrent_id].rename_folder(folder, new_folder)
def queue_top(self, torrent_ids): log.debug("Attempting to queue %s to top", torrent_ids) # torrent_ids must be sorted in reverse before moving to preserve order for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position, reverse=True): try: # If the queue method returns True, then we should emit a signal if self.torrentmanager.queue_top(torrent_id): component.get("EventManager").emit(TorrentQueueChangedEvent()) except KeyError: log.warning("torrent_id: %s does not exist in the queue", torrent_id)
def queue_up(self, torrent_ids): log.debug("Attempting to queue %s to up", torrent_ids) torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids) torrent_moved = True prev_queue_position = None # torrent_ids must be sorted before moving. for queue_position, torrent_id in sorted(torrents): # Move the torrent if and only if there is space (by not moving it we preserve the order) if torrent_moved or queue_position - prev_queue_position > 1: try: torrent_moved = self.torrentmanager.queue_up(torrent_id) except KeyError: log.warning("torrent_id: %s does not exist in the queue", torrent_id) # If the torrent moved, then we should emit a signal if torrent_moved: component.get("EventManager").emit(TorrentQueueChangedEvent()) else: prev_queue_position = queue_position
def queue_down(self, torrent_ids): log.debug("Attempting to queue %s to down", torrent_ids) torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids) torrent_moved = True prev_queue_position = None # torrent_ids must be sorted before moving. for queue_position, torrent_id in sorted(torrents, reverse=True): # Move the torrent if and only if there is space (by not moving it we preserve the order) if torrent_moved or prev_queue_position - queue_position > 1: try: torrent_moved = self.torrentmanager.queue_down(torrent_id) except KeyError: log.warning("torrent_id: %s does not exist in the queue", torrent_id) # If the torrent moved, then we should emit a signal if torrent_moved: component.get("EventManager").emit(TorrentQueueChangedEvent()) else: prev_queue_position = queue_position
def queue_bottom(self, torrent_ids): log.debug("Attempting to queue %s to bottom", torrent_ids) # torrent_ids must be sorted before moving to preserve order for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position): try: # If the queue method returns True, then we should emit a signal if self.torrentmanager.queue_bottom(torrent_id): component.get("EventManager").emit(TorrentQueueChangedEvent()) except KeyError: log.warning("torrent_id: %s does not exist in the queue", torrent_id)
def glob(self, path): return glob.glob(path)
def test_listen_port(self): """ Checks if the active port is open
:returns: True if the port is open, False if not :rtype: bool
"""
self.get_listen_port(), timeout=30)
log.warning("Error testing listen port: %s", failure)
""" Returns the number of free bytes at path
:param path: the path to check free space at, if None, use the default download location :type path: string
:returns: the number of free bytes at path :rtype: int
:raises InvalidPathError: if the path is invalid
""" path = self.config["download_location"]
def get_libtorrent_version(self): """ Returns the libtorrent version.
:returns: the version :rtype: string
"""
def get_completion_paths(self, args): """ Returns the available path completions for the input value. """ return path_chooser_common.get_completion_paths(args)
def get_known_accounts(self): return self.authmanager.get_known_accounts()
def get_auth_levels_mappings(self): return (AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE)
def create_account(self, username, password, authlevel): return self.authmanager.create_account(username, password, authlevel)
def update_account(self, username, password, authlevel): return self.authmanager.update_account(username, password, authlevel)
def remove_account(self, username): return self.authmanager.remove_account(username) |