Big code clean-up in torrentmanager and torrent. This breaks

torrent.state.  Sorry.
This commit is contained in:
Andrew Resch 2008-06-07 00:20:36 +00:00
commit bf00795050
4 changed files with 254 additions and 267 deletions

View file

@ -65,6 +65,7 @@ DEFAULT_PREFS = {
"listen_ports": [6881, 6891], "listen_ports": [6881, 6891],
"torrentfiles_location": os.path.join(deluge.configmanager.get_config_dir(), "torrentfiles"), "torrentfiles_location": os.path.join(deluge.configmanager.get_config_dir(), "torrentfiles"),
"plugins_location": os.path.join(deluge.configmanager.get_config_dir(), "plugins"), "plugins_location": os.path.join(deluge.configmanager.get_config_dir(), "plugins"),
"state_location": os.path.join(deluge.configmanager.get_config_dir(), "state"),
"prioritize_first_last_pieces": False, "prioritize_first_last_pieces": False,
"random_port": True, "random_port": True,
"dht": False, "dht": False,
@ -88,7 +89,6 @@ DEFAULT_PREFS = {
"autoadd_location": "", "autoadd_location": "",
"autoadd_enable": False, "autoadd_enable": False,
"add_paused": False, "add_paused": False,
"default_private": False,
"max_active_seeding": -1, "max_active_seeding": -1,
"max_active_downloading": -1, "max_active_downloading": -1,
"queue_new_to_top": False, "queue_new_to_top": False,
@ -207,6 +207,8 @@ class Core(
# Register set functions in the Config # Register set functions in the Config
self.config.register_set_function("torrentfiles_location", self.config.register_set_function("torrentfiles_location",
self._on_set_torrentfiles_location) self._on_set_torrentfiles_location)
self.config.register_set_function("state_location",
self._on_set_state_location)
self.config.register_set_function("listen_ports", self.config.register_set_function("listen_ports",
self._on_set_listen_ports) self._on_set_listen_ports)
self.config.register_set_function("random_port", self.config.register_set_function("random_port",
@ -300,12 +302,31 @@ class Core(
"""Adds a torrent file to the libtorrent session """Adds a torrent file to the libtorrent session
This requires the torrents filename and a dump of it's content This requires the torrents filename and a dump of it's content
""" """
# Make sure we are sending a string to add() # Turn the filedump into a torrent_info
if not isinstance(filedump, str): if not isinstance(filedump, str):
filedump = filedump.data filedump = filedump.data
# filedump = "".join(chr(b) for b in filedump)
try:
torrent_info = lt.torrent_info(lt.bdecode(filedump))
except RuntimeError, e:
log.warn("Unable to decode torrent file: %s", e)
return None
torrent_id = self.torrents.add(torrent_info=torrent_info, options=options)
torrent_id = self.torrents.add(filename, filedump=filedump, options=options) # Here we need to save a copy of the filedump for state purposes
# and also if the user wishes to save a copy of the torrent elsewhere.
if torrent_id:
# Write the .torrent file to the state directory
try:
save_file = open(os.path.join(self.config["state_location"],
torrent_id + ".torrent"),
"wb")
save_file.write(filedump)
save_file.close()
except IOError, e:
log.warning("Unable to save torrent file: %s", e)
# Run the plugin hooks for 'post_torrent_add' # Run the plugin hooks for 'post_torrent_add'
self.plugins.run_post_torrent_add(torrent_id) self.plugins.run_post_torrent_add(torrent_id)
@ -497,11 +518,7 @@ class Core(
def export_set_torrent_max_download_speed(self, torrent_id, value): def export_set_torrent_max_download_speed(self, torrent_id, value):
"""Sets a torrents max download speed""" """Sets a torrents max download speed"""
return self.torrents[torrent_id].set_max_download_speed(value) return self.torrents[torrent_id].set_max_download_speed(value)
def export_set_torrent_private_flag(self, torrent_id, value):
"""Sets a torrents private flag"""
return self.torrents[torrent_id].set_private_flag(value)
def export_set_torrent_file_priorities(self, torrent_id, priorities): def export_set_torrent_file_priorities(self, torrent_id, priorities):
"""Sets a torrents file priorities""" """Sets a torrents file priorities"""
return self.torrents[torrent_id].set_file_priorities(priorities) return self.torrents[torrent_id].set_file_priorities(priorities)
@ -636,7 +653,14 @@ class Core(
shutil.copy2(os.path.join(root, file), value) shutil.copy2(os.path.join(root, file), value)
except Exception, e: except Exception, e:
log.debug("Unable to copy file to %s: %s", value, e) log.debug("Unable to copy file to %s: %s", value, e)
def _on_set_state_location(self, key, value):
if not os.access(value, os.F_OK):
try:
os.makedirs(value)
except Exception, e:
log.debug("Unable to make directory: %s", e)
def _on_set_listen_ports(self, key, value): def _on_set_listen_ports(self, key, value):
# Only set the listen ports if random_port is not true # Only set the listen ports if random_port is not true
if self.config["random_port"] is not True: if self.config["random_port"] is not True:

View file

@ -47,8 +47,7 @@ TORRENT_STATE = deluge.common.TORRENT_STATE
class Torrent: class Torrent:
"""Torrent holds information about torrents added to the libtorrent session. """Torrent holds information about torrents added to the libtorrent session.
""" """
def __init__(self, filename, handle, compact, save_path, total_uploaded=0, def __init__(self, handle, options, state=None):
trackers=None):
log.debug("Creating torrent object %s", str(handle.info_hash())) log.debug("Creating torrent object %s", str(handle.info_hash()))
# Get the core config # Get the core config
self.config = ConfigManager("core.conf") self.config = ConfigManager("core.conf")
@ -56,41 +55,32 @@ class Torrent:
# Get a reference to the TorrentQueue # Get a reference to the TorrentQueue
self.torrentqueue = component.get("TorrentQueue") self.torrentqueue = component.get("TorrentQueue")
self.signals = component.get("SignalManager") self.signals = component.get("SignalManager")
# Set the filename
self.filename = filename
# Set the libtorrent handle # Set the libtorrent handle
self.handle = handle self.handle = handle
# Set the torrent_id for this torrent # Set the torrent_id for this torrent
self.torrent_id = str(handle.info_hash()) self.torrent_id = str(handle.info_hash())
# This is for saving the total uploaded between sessions
self.total_uploaded = total_uploaded
# Set the allocation mode
self.compact = compact
# Where the torrent is being saved to
self.save_path = save_path
# Status message holds error info about the torrent
self.statusmsg = "OK"
# The torrents state
self.state = ""
# Holds status info so that we don't need to keep getting it from lt # Holds status info so that we don't need to keep getting it from lt
self.status = self.handle.status() self.status = self.handle.status()
self.torrent_info = self.handle.get_torrent_info() self.torrent_info = self.handle.get_torrent_info()
# Various torrent options # Files dictionary
self.max_connections = -1 self.files = self.get_files()
self.max_upload_slots = -1 # Set the default file priorities to normal
self.max_upload_speed = -1 self.file_priorities = [1]* len(self.files)
self.max_download_speed = -1
self.private = False
self.prioritize_first_last = False
# The tracker status # Default total_uploaded to 0, this may be changed by the state
self.tracker_status = "" self.total_uploaded = 0
# Tracker list
if trackers == None: # Load values from state if we have it
if state is not None:
# This is for saving the total uploaded between sessions
self.total_uploaded = state.total_uploaded
# Set the trackers
self.set_trackers(state.trackers)
else:
# Tracker list
self.trackers = [] self.trackers = []
# Create a list of trackers # Create a list of trackers
for value in self.handle.trackers(): for value in self.handle.trackers():
@ -98,17 +88,33 @@ class Torrent:
tracker["url"] = value.url tracker["url"] = value.url
tracker["tier"] = value.tier tracker["tier"] = value.tier
self.trackers.append(tracker) self.trackers.append(tracker)
else:
self.trackers = trackers
self.set_trackers(self.trackers)
# Files dictionary
self.files = self.get_files()
# Set the default file priorities to normal
self.file_priorities = [1]* len(self.files)
# Set resolve_countries to True # Various torrent options
self.handle.resolve_countries(True) self.set_max_connections(options["max_connections_per_torrent"])
self.set_max_upload_slots(options["max_upload_slots_per_torrent"])
self.set_max_upload_speed(options["max_upload_speed_per_torrent"])
self.set_max_download_speed(options["max_download_speed_per_torrent"])
self.set_prioritize_first_last(options["prioritize_first_last_pieces"])
self.handle.resolve_countries(True)
if options.has_key("file_priorities"):
self.set_file_priorities(options["file_priorities"])
# Set the allocation mode
self.compact = options["compact_allocation"]
# Where the torrent is being saved to
self.save_path = options["download_location"]
# Status message holds error info about the torrent
self.statusmsg = "OK"
# The torrents state
self.state = ""
# The tracker status
self.tracker_status = ""
# This variable is to prevent a state change to 'Paused' when it should
# be 'Queued'
self.next_pause_is_queued = False
log.debug("Torrent object created.") log.debug("Torrent object created.")
@ -132,10 +138,6 @@ class Torrent:
self.max_download_speed = m_down_speed self.max_download_speed = m_down_speed
self.handle.set_download_limit(int(m_down_speed * 1024)) self.handle.set_download_limit(int(m_down_speed * 1024))
def set_private_flag(self, private):
self.private = private
#self.handle.get_torrent_info().set_priv(private)
def set_prioritize_first_last(self, prioritize): def set_prioritize_first_last(self, prioritize):
self.prioritize_first_last = prioritize self.prioritize_first_last = prioritize
@ -155,6 +157,30 @@ class Torrent:
self.file_priorities = file_priorities self.file_priorities = file_priorities
self.handle.prioritize_files(file_priorities) self.handle.prioritize_files(file_priorities)
def set_trackers(self, trackers):
"""Sets trackers"""
if trackers == None:
trackers = []
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers)
tracker_list = []
for tracker in trackers:
new_entry = lt.announce_entry(tracker["url"])
new_entry.tier = tracker["tier"]
tracker_list.append(new_entry)
self.handle.replace_trackers(tracker_list)
# Print out the trackers
for t in self.handle.trackers():
log.debug("tier: %s tracker: %s", t.tier, t.url)
# Set the tracker list in the torrent object
self.trackers = trackers
if len(trackers) > 0:
# Force a reannounce if there is at least 1 tracker
self.force_reannounce()
def set_state_based_on_ltstate(self): def set_state_based_on_ltstate(self):
"""Updates the state based on what libtorrent's state for the torrent is""" """Updates the state based on what libtorrent's state for the torrent is"""
@ -183,8 +209,18 @@ class Torrent:
if state != self.state: if state != self.state:
if state == "Queued" and not self.handle.is_paused(): if state == "Queued" and not self.handle.is_paused():
component.get("TorrentManager").append_not_state_paused(self.torrent_id) #component.get("TorrentManager").append_not_state_paused(self.torrent_id)
self.next_pause_is_queued = True
self.handle.pause() self.handle.pause()
if state == "Error" and not self.handle.is_paused():
self.next_pause_is_queued = True
if state == "Paused":
if self.next_pause_is_queued:
self.state = "Queued"
self.next_pause_is_queued = False
else:
self.state = "Paused"
log.debug("Setting %s's state to %s", self.torrent_id, state) log.debug("Setting %s's state to %s", self.torrent_id, state)
self.state = state self.state = state
@ -256,7 +292,6 @@ class Torrent:
def get_queue_position(self): def get_queue_position(self):
# We augment the queue position + 1 so that the user sees a 1 indexed # We augment the queue position + 1 so that the user sees a 1 indexed
# list. # list.
return self.torrentqueue[self.torrent_id] + 1 return self.torrentqueue[self.torrent_id] + 1
def get_peers(self): def get_peers(self):
@ -335,13 +370,13 @@ class Torrent:
"max_upload_speed": self.max_upload_speed, "max_upload_speed": self.max_upload_speed,
"max_download_speed": self.max_download_speed, "max_download_speed": self.max_download_speed,
"prioritize_first_last": self.prioritize_first_last, "prioritize_first_last": self.prioritize_first_last,
"private": self.private,
"message": self.statusmsg, "message": self.statusmsg,
"hash": self.torrent_id "hash": self.torrent_id
} }
fns = { fns = {
"name": self.torrent_info.name, "name": self.torrent_info.name,
"private": self.torrent_info.priv,
"total_size": self.torrent_info.total_size, "total_size": self.torrent_info.total_size,
"num_files": self.torrent_info.num_files, "num_files": self.torrent_info.num_files,
"num_pieces": self.torrent_info.num_pieces, "num_pieces": self.torrent_info.num_pieces,
@ -372,14 +407,13 @@ class Torrent:
status_dict[key] = fns[key]() status_dict[key] = fns[key]()
return status_dict return status_dict
def apply_options(self): def apply_options(self):
"""Applies the per-torrent options that are set.""" """Applies the per-torrent options that are set."""
self.handle.set_max_connections(self.max_connections) self.handle.set_max_connections(self.max_connections)
self.handle.set_max_uploads(self.max_upload_slots) self.handle.set_max_uploads(self.max_upload_slots)
self.handle.set_upload_limit(int(self.max_upload_speed * 1024)) self.handle.set_upload_limit(int(self.max_upload_speed * 1024))
self.handle.set_download_limit(int(self.max_download_speed * 1024)) self.handle.set_download_limit(int(self.max_download_speed * 1024))
self.handle.get_torrent_info().set_priv(self.private)
self.handle.prioritize_files(self.file_priorities) self.handle.prioritize_files(self.file_priorities)
self.handle.resolve_countries(True) self.handle.resolve_countries(True)
@ -472,8 +506,8 @@ class Torrent:
"""Writes the .fastresume file for the torrent""" """Writes the .fastresume file for the torrent"""
resume_data = lt.bencode(self.handle.write_resume_data()) resume_data = lt.bencode(self.handle.write_resume_data())
path = "%s/%s.fastresume" % ( path = "%s/%s.fastresume" % (
self.config["torrentfiles_location"], self.config["state_location"],
self.filename) self.torrent_id)
log.debug("Saving fastresume file: %s", path) log.debug("Saving fastresume file: %s", path)
try: try:
fastresume = open(path, "wb") fastresume = open(path, "wb")
@ -485,14 +519,25 @@ class Torrent:
def delete_fastresume(self): def delete_fastresume(self):
"""Deletes the .fastresume file""" """Deletes the .fastresume file"""
path = "%s/%s.fastresume" % ( path = "%s/%s.fastresume" % (
self.config["torrentfiles_location"], self.config["state_location"],
self.filename) self.torrent_id)
log.debug("Deleting fastresume file: %s", path) log.debug("Deleting fastresume file: %s", path)
try: try:
os.remove(path) os.remove(path)
except Exception, e: except Exception, e:
log.warning("Unable to delete the fastresume file: %s", e) log.warning("Unable to delete the fastresume file: %s", e)
def delete_torrentfile(self):
"""Deletes the .torrent file in the state"""
path = "%s/%s.torrent" % (
self.config["state_location"],
self.torrent_id)
log.debug("Deleting torrent file: %s", path)
try:
os.remove(path)
except Exception, e:
log.warning("Unable to delete the torrent file: %s", e)
def force_reannounce(self): def force_reannounce(self):
"""Force a tracker reannounce""" """Force a tracker reannounce"""
try: try:
@ -512,52 +557,3 @@ class Torrent:
return False return False
return True return True
def set_trackers(self, trackers):
"""Sets trackers"""
if trackers == None:
trackers = []
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers)
tracker_list = []
for tracker in trackers:
new_entry = lt.announce_entry(tracker["url"])
new_entry.tier = tracker["tier"]
tracker_list.append(new_entry)
self.handle.replace_trackers(tracker_list)
# Print out the trackers
for t in self.handle.trackers():
log.debug("tier: %s tracker: %s", t.tier, t.url)
# Set the tracker list in the torrent object
self.trackers = trackers
if len(trackers) > 0:
# Force a reannounce if there is at least 1 tracker
self.force_reannounce()
def save_torrent_file(self, filedump=None):
"""Saves a torrent file"""
log.debug("Attempting to save torrent file: %s", self.filename)
# Test if the torrentfiles_location is accessible
if os.access(
os.path.join(self.config["torrentfiles_location"]), os.F_OK) \
is False:
# The directory probably doesn't exist, so lets create it
try:
os.makedirs(os.path.join(self.config["torrentfiles_location"]))
except IOError, e:
log.warning("Unable to create torrent files directory: %s", e)
# Write the .torrent file to the torrent directory
try:
save_file = open(os.path.join(self.config["torrentfiles_location"],
self.filename),
"wb")
if filedump == None:
filedump = self.handle.get_torrent_info().create_torrent()
save_file.write(lt.bencode(filedump))
save_file.close()
except IOError, e:
log.warning("Unable to save torrent file: %s", e)

View file

@ -51,8 +51,7 @@ from deluge.log import LOG as log
class TorrentState: class TorrentState:
def __init__(self, def __init__(self,
torrent_id, torrent_id,
filename,
total_uploaded, total_uploaded,
trackers, trackers,
compact, compact,
@ -63,12 +62,10 @@ class TorrentState:
max_upload_speed, max_upload_speed,
max_download_speed, max_download_speed,
prioritize_first_last, prioritize_first_last,
private,
file_priorities, file_priorities,
queue queue
): ):
self.torrent_id = torrent_id self.torrent_id = torrent_id
self.filename = filename
self.total_uploaded = total_uploaded self.total_uploaded = total_uploaded
self.trackers = trackers self.trackers = trackers
self.queue = queue self.queue = queue
@ -82,7 +79,6 @@ class TorrentState:
self.max_upload_speed = max_upload_speed self.max_upload_speed = max_upload_speed
self.max_download_speed = max_download_speed self.max_download_speed = max_download_speed
self.prioritize_first_last = prioritize_first_last self.prioritize_first_last = prioritize_first_last
self.private = private
self.file_priorities = file_priorities self.file_priorities = file_priorities
class TorrentManagerState: class TorrentManagerState:
@ -108,9 +104,6 @@ class TorrentManager(component.Component):
# Create the torrents dict { torrent_id: Torrent } # Create the torrents dict { torrent_id: Torrent }
self.torrents = {} self.torrents = {}
# List of torrents to not set state 'Paused' on lt alert
self.not_state_paused = []
# Register set functions # Register set functions
self.config.register_set_function("max_connections_per_torrent", self.config.register_set_function("max_connections_per_torrent",
@ -172,105 +165,119 @@ class TorrentManager(component.Component):
def get_torrent_list(self): def get_torrent_list(self):
"""Returns a list of torrent_ids""" """Returns a list of torrent_ids"""
return self.torrents.keys() return self.torrents.keys()
def get_torrent_info_from_file(self, filepath):
"""Returns a torrent_info for the file specified or None"""
torrent_info = None
# Get the torrent data from the torrent file
try:
log.debug("Attempting to create torrent_info from %s", filepath)
_file = open(filepath, "rb")
torrent_info = lt.torrent_info(lt.bdecode(_file.read()))
_file.close()
except (IOError, RuntimeError), e:
log.warning("Unable to open %s: %s", filepath, e)
return torrent_info
def append_not_state_paused(self, torrent_id): def get_resume_data_from_file(self, torrent_id):
"""Appends to a list of torrents that we will not set state Paused to """Returns an entry with the resume data or None"""
when we receive the paused alert from libtorrent. The torrents are removed fastresume = None
from this list once we receive the alert they have been paused in libtorrent."""
if torrent_id not in self.not_state_paused:
self.not_state_paused.append(torrent_id)
def add(self, filename, filedump=None, options=None, total_uploaded=0,
trackers=None, queue=-1, state=None, save_state=True):
"""Add a torrent to the manager and returns it's torrent_id"""
log.info("Adding torrent: %s", filename)
log.debug("options: %s", options)
# Make sure 'filename' is a python string
filename = str(filename)
# Convert the filedump data array into a string of bytes
if filedump is not None:
# If the filedump is already of type str, then it's already been
# joined.
if type(filedump) is not str:
filedump = "".join(chr(b) for b in filedump)
try:
filedump = lt.bdecode(filedump)
except RuntimeError, e:
log.warn("Unable to decode torrent file: %s", e)
return None
else:
# Get the data from the file
filedump = self.load_torrent(filename)
if not filedump:
log.warning("Unable to load torrent file..")
return None
# Attempt to load fastresume data
try: try:
_file = open( _file = open(
os.path.join( os.path.join(
self.config["torrentfiles_location"], self.config["state_location"],
filename + ".fastresume"), torrent_id + ".fastresume"),
"rb") "rb")
try: try:
fastresume = lt.bdecode(_file.read()) fastresume = lt.bdecode(_file.read())
except RuntimeError, e: except RuntimeError, e:
log.warning("Unable to bdecode fastresume file: %s", e) log.warning("Unable to bdecode fastresume file: %s", e)
fastresume = None
_file.close() _file.close()
except IOError, e: except IOError, e:
log.debug("Unable to load .fastresume: %s", e) log.debug("Unable to load .fastresume: %s", e)
fastresume = None
handle = None return fastresume
def add(self, torrent_info=None, state=None, options=None, save_state=True):
"""Add a torrent to the manager and returns it's torrent_id"""
if torrent_info is None and state is None:
log.debug("You must specify a valid torrent_info or a torrent state object!")
return
# Check if options is None and load defaults log.debug("torrentmanager.add")
options_keys = [ add_torrent_params = {}
"compact_allocation",
"max_connections_per_torrent", if torrent_info is None:
"max_upload_slots_per_torrent", # We have no torrent_info so we need to add the torrent with information
"max_upload_speed_per_torrent", # from the state object.
"max_download_speed_per_torrent",
"prioritize_first_last_pieces",
"download_location",
"add_paused",
"default_private"
]
if options == None: # Populate the options dict from state
options = {} options = {}
for key in options_keys: options["max_connections_per_torrent"] = state.max_connections
options[key] = self.config[key] options["max_upload_slots_per_torrent"] = state.max_upload_slots
options["max_upload_speed_per_torrent"] = state.max_upload_speed
options["max_download_speed_per_torrent"] = state.max_download_speed
options["prioritize_first_last_pieces"] = state.prioritize_first_last
options["file_priorities"] = state.file_priorities
options["compact_allocation"] = state.compact
options["download_location"] = state.save_path
add_torrent_params["ti"] =\
self.get_torrent_info_from_file(
os.path.join(self.config["state_location"], state.torrent_id + ".torrent"))
add_torrent_params["resume_data"] = self.get_resume_data_from_file(state.torrent_id)
else: else:
for key in options_keys: # We have a torrent_info object so we're not loading from state.
if not options.has_key(key): # Check if options is None and load defaults
options_keys = [
"compact_allocation",
"max_connections_per_torrent",
"max_upload_slots_per_torrent",
"max_upload_speed_per_torrent",
"max_download_speed_per_torrent",
"prioritize_first_last_pieces",
"download_location",
"add_paused",
]
if options == None:
options = {}
for key in options_keys:
options[key] = self.config[key] options[key] = self.config[key]
else:
for key in options_keys:
if not options.has_key(key):
options[key] = self.config[key]
add_torrent_params["ti"] = torrent_info
add_torrent_params["resume_data"] = None
#log.info("Adding torrent: %s", filename)
log.debug("options: %s", options)
# Set the right storage_mode # Set the right storage_mode
if options["compact_allocation"]: if options["compact_allocation"]:
storage_mode = lt.storage_mode_t(2) storage_mode = lt.storage_mode_t(2)
else: else:
storage_mode = lt.storage_mode_t(1) storage_mode = lt.storage_mode_t(1)
# Fill in the rest of the add_torrent_params dictionary
add_torrent_params["save_path"] = str(options["download_location"])
add_torrent_params["storage_mode"] = storage_mode
add_torrent_params["paused"] = True
add_torrent_params["auto_managed"] = False
add_torrent_params["duplicate_is_error"] = True
# We need to pause the AlertManager momentarily to prevent alerts # We need to pause the AlertManager momentarily to prevent alerts
# for this torrent being generated before a Torrent object is created. # for this torrent being generated before a Torrent object is created.
component.pause("AlertManager") component.pause("AlertManager")
# Create the torrent parameters struct for the torrent's options handle = None
t_params = {}
t_params["ti"] = lt.torrent_info(filedump)
t_params["save_path"] = str(options["download_location"])
t_params["resume_data"] = fastresume
t_params["storage_mode"] = storage_mode
t_params["paused"] = True
t_params["auto_managed"] = False
t_params["duplicate_is_error"] = True
try: try:
handle = self.session.add_torrent(t_params) handle = self.session.add_torrent(add_torrent_params)
except RuntimeError, e: except RuntimeError, e:
log.warning("Error adding torrent: %s", e) log.warning("Error adding torrent: %s", e)
@ -278,76 +285,59 @@ class TorrentManager(component.Component):
log.debug("torrent handle is invalid!") log.debug("torrent handle is invalid!")
# The torrent was not added to the session # The torrent was not added to the session
component.resume("AlertManager") component.resume("AlertManager")
return None return
log.debug("handle id: %s", str(handle.info_hash()))
# Create a Torrent object # Create a Torrent object
torrent = Torrent(filename, handle, options["compact_allocation"], torrent = Torrent(handle, options, state)
options["download_location"], total_uploaded, trackers)
# Add the torrent object to the dictionary # Add the torrent object to the dictionary
self.torrents[torrent.torrent_id] = torrent self.torrents[torrent.torrent_id] = torrent
component.resume("AlertManager") component.resume("AlertManager")
# Add the torrent to the queue # Add the torrent to the queue
if queue == -1 and self.config["queue_new_to_top"]: if state is not None:
self.queue.insert(0, torrent.torrent_id) self.queue.insert(state.queue, torrent.torrent_id)
else: else:
self.queue.insert(queue, torrent.torrent_id) if self.config["queue_new_to_top"]:
self.queue.insert(0, torrent.torrent_id)
else:
self.queue.append(torrent.torrent_id)
# Set per-torrent options
torrent.set_max_connections(options["max_connections_per_torrent"])
torrent.set_max_upload_slots(options["max_upload_slots_per_torrent"])
torrent.set_max_upload_speed(options["max_upload_speed_per_torrent"])
torrent.set_max_download_speed(
options["max_download_speed_per_torrent"])
torrent.set_prioritize_first_last(
options["prioritize_first_last_pieces"])
torrent.set_private_flag(options["default_private"])
if options.has_key("file_priorities"):
if options["file_priorities"] != None:
log.debug("set file priorities: %s", options["file_priorities"])
torrent.set_file_priorities(options["file_priorities"])
log.debug("state: %s", state) log.debug("state: %s", state)
# Resume the torrent if needed # Resume the torrent if needed
if state == "Queued": if state == "Paused" or state == "Error":
torrent.state = "Queued"
elif state == "Paused" or state == "Error":
torrent.state = "Paused" torrent.state = "Paused"
if state == None and not options["add_paused"]: elif state == None and not options["add_paused"]:
torrent.handle.resume() torrent.handle.resume()
# We set the state based on libtorrent's state # We set the state based on libtorrent's state
torrent.set_state_based_on_ltstate() torrent.set_state_based_on_ltstate()
if state == None and options["add_paused"]: elif state == None and options["add_paused"]:
torrent.set_state = "Paused" torrent.set_state = "Paused"
# Emit the torrent_added signal
self.signals.emit("torrent_added", torrent.torrent_id)
# Save the torrent file
torrent.save_torrent_file(filedump)
if save_state: if save_state:
# Save the session state # Save the session state
self.save_state() self.save_state()
# Emit the torrent_added signal
self.signals.emit("torrent_added", torrent.torrent_id)
return torrent.torrent_id return torrent.torrent_id
def load_torrent(self, filename): def load_torrent(self, torrent_id):
"""Load a torrent file and return it's torrent info""" """Load a torrent file from state and return it's torrent info"""
filedump = None filedump = None
# Get the torrent data from the torrent file # Get the torrent data from the torrent file
try: try:
log.debug("Attempting to open %s for add.", filename) log.debug("Attempting to open %s for add.", torrent_id)
_file = open( _file = open(
os.path.join( os.path.join(
self.config["torrentfiles_location"], filename), self.config["state_location"], torrent_id + ".torrent"),
"rb") "rb")
filedump = lt.bdecode(_file.read()) filedump = lt.bdecode(_file.read())
_file.close() _file.close()
except (IOError, RuntimeError), e: except (IOError, RuntimeError), e:
log.warning("Unable to open %s: %s", filename, e) log.warning("Unable to open %s: %s", torrent_id, e)
return False return False
return filedump return filedump
@ -379,6 +369,9 @@ class TorrentManager(component.Component):
# Remove the .fastresume if it exists # Remove the .fastresume if it exists
self.torrents[torrent_id].delete_fastresume() self.torrents[torrent_id].delete_fastresume()
# Remove the .torrent file in the state
self.torrents[torrent_id].delete_torrentfile()
# Remove the torrent from the queue # Remove the torrent from the queue
self.queue.remove(torrent_id) self.queue.remove(torrent_id)
@ -417,15 +410,12 @@ class TorrentManager(component.Component):
def force_recheck(self, torrent_id): def force_recheck(self, torrent_id):
"""Forces a re-check of the torrent's data""" """Forces a re-check of the torrent's data"""
log.debug("force recheck is broken for the time being")
return
log.debug("Doing a forced recheck on %s", torrent_id) log.debug("Doing a forced recheck on %s", torrent_id)
torrent = self.torrents[torrent_id] torrent = self.torrents[torrent_id]
paused = self.torrents[torrent_id].handle.is_paused() paused = self.torrents[torrent_id].handle.is_paused()
torrent_info = None torrent_info = torrent.handle.get_torrent_info()
### Check for .torrent file prior to removing and make a copy if needed
if os.access(os.path.join(self.config["torrentfiles_location"] +\
"/" + torrent.filename), os.F_OK) is False:
torrent_info = torrent.handle.get_torrent_info().create_torrent()
torrent.save_torrent_file()
# We need to pause the AlertManager momentarily to prevent alerts # We need to pause the AlertManager momentarily to prevent alerts
# for this torrent being generated before a Torrent object is created. # for this torrent being generated before a Torrent object is created.
@ -439,11 +429,11 @@ class TorrentManager(component.Component):
return False return False
# Remove the fastresume file if there # Remove the fastresume file if there
torrent.delete_fastresume() #torrent.delete_fastresume()
# Load the torrent info from file if needed # Load the torrent info from file if needed
if torrent_info == None: if torrent_info == None:
torrent_info = self.load_torrent(torrent.filename) torrent_info = self.load_torrent(torrent.torrent_id)
# Next we re-add the torrent # Next we re-add the torrent
@ -489,7 +479,7 @@ class TorrentManager(component.Component):
try: try:
log.debug("Opening torrent state file for load.") log.debug("Opening torrent state file for load.")
state_file = open( state_file = open(
os.path.join(self.config["config_location"], "torrents.state"), "rb") os.path.join(self.config["state_location"], "torrents.state"), "rb")
state = cPickle.load(state_file) state = cPickle.load(state_file)
state_file.close() state_file.close()
except IOError: except IOError:
@ -506,37 +496,20 @@ class TorrentManager(component.Component):
fr_first = [] fr_first = []
for torrent_state in state.torrents: for torrent_state in state.torrents:
if os.path.exists(os.path.join( if os.path.exists(os.path.join(
self.config["torrentfiles_location"], self.config["state_location"],
torrent_state.filename, ".fastresume")): torrent_state.torrent_id, ".fastresume")):
fr_first.insert(0, torrent_state) fr_first.insert(0, torrent_state)
else: else:
fr_first.append(torrent_state) fr_first.append(torrent_state)
for torrent_state in fr_first: for torrent_state in fr_first:
try: try:
options = {
"compact_allocation": torrent_state.compact,
"max_connections_per_torrent": torrent_state.max_connections,
"max_upload_slots_per_torrent": torrent_state.max_upload_slots,
"max_upload_speed_per_torrent": torrent_state.max_upload_speed,
"max_download_speed_per_torrent": torrent_state.max_download_speed,
"prioritize_first_last_pieces": torrent_state.prioritize_first_last,
"download_location": torrent_state.save_path,
"add_paused": True,
"default_private": torrent_state.private,
"file_priorities": torrent_state.file_priorities
}
# We need to resume all non-add_paused torrents after plugin hook # We need to resume all non-add_paused torrents after plugin hook
if torrent_state.state not in ["Paused", "Queued", "Error"]: if torrent_state.state not in ["Paused", "Queued", "Error"]:
resume_torrents.append(torrent_state.torrent_id) resume_torrents.append(torrent_state.torrent_id)
self.add( self.add(
torrent_state.filename, state=torrent_state,
options=options,
total_uploaded=torrent_state.total_uploaded,
trackers=torrent_state.trackers,
queue=torrent_state.queue,
state=torrent_state.state,
save_state=False) save_state=False)
except AttributeError, e: except AttributeError, e:
@ -559,7 +532,6 @@ class TorrentManager(component.Component):
for torrent in self.torrents.values(): for torrent in self.torrents.values():
torrent_state = TorrentState( torrent_state = TorrentState(
torrent.torrent_id, torrent.torrent_id,
torrent.filename,
torrent.get_status(["total_uploaded"])["total_uploaded"], torrent.get_status(["total_uploaded"])["total_uploaded"],
torrent.trackers, torrent.trackers,
torrent.compact, torrent.compact,
@ -570,7 +542,6 @@ class TorrentManager(component.Component):
torrent.max_upload_speed, torrent.max_upload_speed,
torrent.max_download_speed, torrent.max_download_speed,
torrent.prioritize_first_last, torrent.prioritize_first_last,
torrent.private,
torrent.file_priorities, torrent.file_priorities,
torrent.get_status(["queue"])["queue"] - 1 # We subtract 1 due to augmentation torrent.get_status(["queue"])["queue"] - 1 # We subtract 1 due to augmentation
) )
@ -580,7 +551,7 @@ class TorrentManager(component.Component):
try: try:
log.debug("Saving torrent state file.") log.debug("Saving torrent state file.")
state_file = open( state_file = open(
os.path.join(self.config["config_location"], "torrents.state"), os.path.join(self.config["state_location"], "torrents.state"),
"wb") "wb")
cPickle.dump(state, state_file) cPickle.dump(state, state_file)
state_file.close() state_file.close()
@ -640,13 +611,9 @@ class TorrentManager(component.Component):
# Get the torrent_id # Get the torrent_id
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
# Set the torrent state # Set the torrent state
log.debug("not_state_paused: %s", self.not_state_paused) log.debug("Setting state 'Paused'..")
if not torrent_id in self.not_state_paused: self.torrents[torrent_id].set_state("Paused")
log.debug("Setting state 'Paused'..") component.get("SignalManager").emit("torrent_paused", torrent_id)
self.torrents[torrent_id].set_state("Paused")
component.get("SignalManager").emit("torrent_paused", torrent_id)
else:
self.not_state_paused.remove(torrent_id)
# Write the fastresume file # Write the fastresume file
self.torrents[torrent_id].write_fastresume() self.torrents[torrent_id].write_fastresume()
@ -731,4 +698,4 @@ class TorrentManager(component.Component):
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
self.torrents[torrent_id].set_state("Error") self.torrents[torrent_id].set_state("Error")
self.torrents[torrent_id].set_status_message(str(alert.msg())) self.torrents[torrent_id].set_status_message(str(alert.msg()))
self.not_state_paused.append(torrent_id)

View file

@ -200,7 +200,7 @@ class TorrentQueue(component.Component):
try: try:
return self.queue.index(torrent_id) return self.queue.index(torrent_id)
except ValueError: except ValueError:
return None return -1
def append(self, torrent_id): def append(self, torrent_id):
"""Append torrent_id to the bottom of the queue""" """Append torrent_id to the bottom of the queue"""