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
parent abbba8bf3b
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,11 +302,30 @@ 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(filename, filedump=filedump, options=options) torrent_id = self.torrents.add(torrent_info=torrent_info, 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)
@ -498,10 +519,6 @@ class Core(
"""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)
@ -637,6 +654,13 @@ class Core(
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")
@ -57,40 +56,31 @@ class Torrent:
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
# 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 # Tracker list
if trackers == None:
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 # Various torrent options
self.files = self.get_files() self.set_max_connections(options["max_connections_per_torrent"])
# Set the default file priorities to normal self.set_max_upload_slots(options["max_upload_slots_per_torrent"])
self.file_priorities = [1]* len(self.files) self.set_max_upload_speed(options["max_upload_speed_per_torrent"])
self.set_max_download_speed(options["max_download_speed_per_torrent"])
# Set resolve_countries to True self.set_prioritize_first_last(options["prioritize_first_last_pieces"])
self.handle.resolve_countries(True) 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
@ -156,6 +158,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"""
# Set the initial state based on the lt state # Set the initial state based on the lt state
@ -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,
@ -379,7 +414,6 @@ class Torrent:
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

@ -52,7 +52,6 @@ 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:
@ -109,9 +105,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",
self.on_set_max_connections_per_torrent) self.on_set_max_connections_per_torrent)
@ -173,59 +166,70 @@ class TorrentManager(component.Component):
"""Returns a list of torrent_ids""" """Returns a list of torrent_ids"""
return self.torrents.keys() return self.torrents.keys()
def append_not_state_paused(self, torrent_id): def get_torrent_info_from_file(self, filepath):
"""Appends to a list of torrents that we will not set state Paused to """Returns a torrent_info for the file specified or None"""
when we receive the paused alert from libtorrent. The torrents are removed torrent_info = None
from this list once we receive the alert they have been paused in libtorrent.""" # Get the torrent data from the torrent file
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: try:
filedump = lt.bdecode(filedump) log.debug("Attempting to create torrent_info from %s", filepath)
except RuntimeError, e: _file = open(filepath, "rb")
log.warn("Unable to decode torrent file: %s", e) torrent_info = lt.torrent_info(lt.bdecode(_file.read()))
return None _file.close()
else: except (IOError, RuntimeError), e:
# Get the data from the file log.warning("Unable to open %s: %s", filepath, e)
filedump = self.load_torrent(filename)
if not filedump:
log.warning("Unable to load torrent file..")
return None
# Attempt to load fastresume data return torrent_info
def get_resume_data_from_file(self, torrent_id):
"""Returns an entry with the resume data or None"""
fastresume = None
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
log.debug("torrentmanager.add")
add_torrent_params = {}
if torrent_info is None:
# We have no torrent_info so we need to add the torrent with information
# from the state object.
# Populate the options dict from state
options = {}
options["max_connections_per_torrent"] = state.max_connections
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:
# We have a torrent_info object so we're not loading from state.
# Check if options is None and load defaults # Check if options is None and load defaults
options_keys = [ options_keys = [
"compact_allocation", "compact_allocation",
@ -236,7 +240,6 @@ class TorrentManager(component.Component):
"prioritize_first_last_pieces", "prioritize_first_last_pieces",
"download_location", "download_location",
"add_paused", "add_paused",
"default_private"
] ]
if options == None: if options == None:
@ -248,29 +251,33 @@ class TorrentManager(component.Component):
if not options.has_key(key): if not options.has_key(key):
options[key] = self.config[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(state.queue, torrent.torrent_id)
else:
if self.config["queue_new_to_top"]:
self.queue.insert(0, torrent.torrent_id) self.queue.insert(0, torrent.torrent_id)
else: else:
self.queue.insert(queue, torrent.torrent_id) 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)
if not torrent_id in self.not_state_paused:
log.debug("Setting state 'Paused'..") log.debug("Setting state 'Paused'..")
self.torrents[torrent_id].set_state("Paused") self.torrents[torrent_id].set_state("Paused")
component.get("SignalManager").emit("torrent_paused", torrent_id) 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"""