Merge remote-tracking branch 'bro/master-daemon-optimize-speed'
Conflicts: deluge/core/alertmanager.py deluge/core/torrentmanager.py
This commit is contained in:
commit
8c106ce8c4
|
@ -67,12 +67,12 @@ class AlertManager(component.Component):
|
|||
|
||||
# handlers is a dictionary of lists {"alert_type": [handler1,h2,..]}
|
||||
self.handlers = {}
|
||||
|
||||
self.delayed_calls = []
|
||||
self.wait_on_handler = False
|
||||
|
||||
def update(self):
|
||||
self.delayed_calls = [dc for dc in self.delayed_calls if dc.active()]
|
||||
self.handle_alerts()
|
||||
self.handle_alerts(wait=self.wait_on_handler)
|
||||
|
||||
def stop(self):
|
||||
for dc in self.delayed_calls:
|
||||
|
@ -123,6 +123,7 @@ class AlertManager(component.Component):
|
|||
while alert is not None:
|
||||
alert_type = type(alert).__name__
|
||||
# Display the alert message
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("%s: %s", alert_type, decode_string(alert.message()))
|
||||
# Call any handlers for this alert type
|
||||
if alert_type in self.handlers:
|
||||
|
|
|
@ -427,21 +427,25 @@ class Core(component.Component):
|
|||
for torrent_id in torrent_ids:
|
||||
self.torrentmanager[torrent_id].resume()
|
||||
|
||||
@export
|
||||
def get_torrent_status(self, torrent_id, keys, diff=False):
|
||||
# Build the status dictionary
|
||||
def create_torrent_status(self, torrent_id, torrent_keys, plugin_keys, diff=False, update=False):
|
||||
try:
|
||||
status = self.torrentmanager[torrent_id].get_status(keys, diff)
|
||||
status = self.torrentmanager[torrent_id].get_status(torrent_keys, diff, update=update)
|
||||
except KeyError:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
# Torrent was probaly removed meanwhile
|
||||
return {}
|
||||
|
||||
# Get the leftover fields and ask the plugin manager to fill them
|
||||
leftover_fields = list(set(keys) - set(status.keys()))
|
||||
if len(leftover_fields) > 0:
|
||||
status.update(self.pluginmanager.get_status(torrent_id, leftover_fields))
|
||||
# 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
|
||||
|
||||
@export
|
||||
def get_torrent_status(self, torrent_id, keys, diff=False):
|
||||
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)
|
||||
|
||||
@export
|
||||
def get_torrents_status(self, filter_dict, keys, diff=False):
|
||||
"""
|
||||
|
@ -449,12 +453,17 @@ class Core(component.Component):
|
|||
"""
|
||||
torrent_ids = self.filtermanager.filter_torrent_ids(filter_dict)
|
||||
status_dict = {}.fromkeys(torrent_ids)
|
||||
d = self.torrentmanager.torrents_status_update(torrent_ids, keys, diff=False)
|
||||
|
||||
# Get the torrent status for each torrent_id
|
||||
for torrent_id in torrent_ids:
|
||||
status_dict[torrent_id] = self.get_torrent_status(torrent_id, keys, 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
|
||||
|
||||
@export
|
||||
def get_filter_tree(self , show_zero_hits=True, hide_cat=None):
|
||||
|
|
|
@ -113,9 +113,8 @@ def tracker_error_filter(torrent_ids, values):
|
|||
# Check all the torrent's tracker_status for 'Error:' and only return torrent_ids
|
||||
# that have this substring in their tracker_status
|
||||
for torrent_id in torrent_ids:
|
||||
if _("Error") + ":" in tm[torrent_id].get_status(["tracker_status"])["tracker_status"]:
|
||||
if _("Error") + ":" in tm[torrent_id].get_status(["tracker_host"])["tracker_host"]:
|
||||
filtered_torrent_ids.append(torrent_id)
|
||||
|
||||
return filtered_torrent_ids
|
||||
|
||||
class FilterManager(component.Component):
|
||||
|
@ -192,13 +191,11 @@ class FilterManager(component.Component):
|
|||
|
||||
#leftover filter arguments:
|
||||
#default filter on status fields.
|
||||
status_func = self.core.get_torrent_status #premature optimalisation..
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = status_func(torrent_id, filter_dict.keys()) #status={key:value}
|
||||
status = self.torrents[torrent_id].get_status(filter_dict.keys()) #status={key:value}
|
||||
for field, values in filter_dict.iteritems():
|
||||
if (not status[field] in values) and torrent_id in torrent_ids:
|
||||
torrent_ids.remove(torrent_id)
|
||||
|
||||
return torrent_ids
|
||||
|
||||
def get_filter_tree(self, show_zero_hits=True, hide_cat=None):
|
||||
|
@ -207,17 +204,16 @@ class FilterManager(component.Component):
|
|||
for use in sidebar.
|
||||
"""
|
||||
torrent_ids = self.torrents.get_torrent_list()
|
||||
status_func = self.core.get_torrent_status #premature optimalisation..
|
||||
tree_keys = list(self.tree_fields.keys())
|
||||
if hide_cat:
|
||||
for cat in hide_cat:
|
||||
tree_keys.remove(cat)
|
||||
|
||||
torrent_keys, plugin_keys = self.torrents.separate_keys(tree_keys, torrent_ids)
|
||||
items = dict((field, self.tree_fields[field]()) for field in tree_keys)
|
||||
|
||||
#count status fields.
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = status_func(torrent_id, tree_keys) #status={key:value}
|
||||
status = self.core.create_torrent_status(torrent_id, torrent_keys, plugin_keys) #status={key:value}
|
||||
for field in tree_keys:
|
||||
value = status[field]
|
||||
items[field][value] = items[field].get(value, 0) + 1
|
||||
|
@ -264,9 +260,8 @@ class FilterManager(component.Component):
|
|||
del self.tree_fields[field]
|
||||
|
||||
def filter_state_active(self, torrent_ids):
|
||||
get_status = self.core.get_torrent_status
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = get_status(torrent_id, ["download_payload_rate", "upload_payload_rate"])
|
||||
status = self.torrents[torrent_id].get_status(["download_payload_rate", "upload_payload_rate"])
|
||||
if status["download_payload_rate"] or status["upload_payload_rate"]:
|
||||
pass #ok
|
||||
else:
|
||||
|
|
|
@ -109,10 +109,14 @@ class Torrent(object):
|
|||
"""Torrent holds information about torrents added to the libtorrent session.
|
||||
"""
|
||||
def __init__(self, handle, options, state=None, filename=None, magnet=None, owner=None):
|
||||
log.debug("Creating torrent object %s", str(handle.info_hash()))
|
||||
# Set the torrent_id for this torrent
|
||||
self.torrent_id = str(handle.info_hash())
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Creating torrent object %s", self.torrent_id)
|
||||
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
|
||||
self.rpcserver = component.get("RPCServer")
|
||||
|
||||
# This dict holds previous status dicts returned for this torrent
|
||||
|
@ -124,8 +128,6 @@ class Torrent(object):
|
|||
|
||||
# Set the libtorrent handle
|
||||
self.handle = handle
|
||||
# Set the torrent_id for this torrent
|
||||
self.torrent_id = str(handle.info_hash())
|
||||
|
||||
# Keep a list of Deferreds for file indexes we're waiting for file_rename alerts on
|
||||
# This is so we can send one folder_renamed signal instead of multiple
|
||||
|
@ -151,6 +153,9 @@ class Torrent(object):
|
|||
except RuntimeError:
|
||||
self.torrent_info = None
|
||||
|
||||
self.handle_has_metadata = None
|
||||
self.status_funcs = None
|
||||
|
||||
# Default total_uploaded to 0, this may be changed by the state
|
||||
self.total_uploaded = 0
|
||||
|
||||
|
@ -187,9 +192,11 @@ class Torrent(object):
|
|||
self.statusmsg = "OK"
|
||||
|
||||
# The torrents state
|
||||
self.update_state()
|
||||
# This is only one out of 4 calls to update_state for each torrent on startup.
|
||||
# This call doesn't seem to be necessary, it can probably be removed
|
||||
#self.update_state()
|
||||
self.state = None
|
||||
|
||||
# The tracker status
|
||||
self.tracker_status = ""
|
||||
|
||||
# This gets updated when get_tracker_host is called
|
||||
|
@ -217,8 +224,18 @@ class Torrent(object):
|
|||
self.forcing_recheck = False
|
||||
self.forcing_recheck_paused = False
|
||||
|
||||
self.update_status(self.handle.status())
|
||||
self._create_status_funcs()
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Torrent object created.")
|
||||
|
||||
def has_metadata(self):
|
||||
if self.handle_has_metadata:
|
||||
return self.handle_has_metadata
|
||||
self.handle_has_metadata = self.handle.has_metadata()
|
||||
return self.handle_has_metadata
|
||||
|
||||
## Options methods ##
|
||||
def set_options(self, options):
|
||||
OPTIONS_FUNCS = {
|
||||
|
@ -248,7 +265,7 @@ class Torrent(object):
|
|||
return self.options
|
||||
|
||||
def get_name(self):
|
||||
if self.handle.has_metadata():
|
||||
if self.has_metadata():
|
||||
name = self.torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0]
|
||||
if not name:
|
||||
name = self.torrent_info.name()
|
||||
|
@ -306,7 +323,7 @@ class Torrent(object):
|
|||
# reset all the piece priorities
|
||||
self.set_file_priorities(self.options["file_priorities"])
|
||||
return
|
||||
if not self.handle.has_metadata():
|
||||
if not self.has_metadata():
|
||||
return
|
||||
if self.options["compact_allocation"]:
|
||||
log.debug("Setting first/last priority with compact "
|
||||
|
@ -315,7 +332,7 @@ class Torrent(object):
|
|||
# A list of priorities for each piece in the torrent
|
||||
priorities = self.handle.piece_priorities()
|
||||
prioritized_pieces = []
|
||||
ti = self.handle.get_torrent_info()
|
||||
ti = self.torrent_info
|
||||
for i in range(ti.num_files()):
|
||||
f = ti.file_at(i)
|
||||
two_percent_bytes = int(0.02 * f.size)
|
||||
|
@ -366,7 +383,9 @@ class Torrent(object):
|
|||
self.options["move_completed_path"] = move_completed_path
|
||||
|
||||
def set_file_priorities(self, file_priorities):
|
||||
if len(file_priorities) != len(self.get_files()):
|
||||
if not self.has_metadata():
|
||||
return
|
||||
if len(file_priorities) != self.ti_num_files():
|
||||
log.debug("file_priorities len != num_files")
|
||||
self.options["file_priorities"] = self.handle.file_priorities()
|
||||
return
|
||||
|
@ -376,6 +395,7 @@ class Torrent(object):
|
|||
self.options["file_priorities"] = self.handle.file_priorities()
|
||||
return
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("setting %s's file priorities: %s", self.torrent_id, file_priorities)
|
||||
|
||||
self.handle.prioritize_files(file_priorities)
|
||||
|
@ -390,9 +410,9 @@ class Torrent(object):
|
|||
self.update_state()
|
||||
break
|
||||
|
||||
# In case values in file_priorities were faulty (old state?)
|
||||
# we make sure the stored options are in sync
|
||||
self.options["file_priorities"] = self.handle.file_priorities()
|
||||
if self.options["file_priorities"] != list(file_priorities):
|
||||
log.warning("File priorities were not set for this torrent")
|
||||
|
||||
# Set the first/last priorities if needed
|
||||
if self.options["prioritize_first_last_pieces"]:
|
||||
|
@ -411,7 +431,9 @@ class Torrent(object):
|
|||
self.tracker_host = None
|
||||
return
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers)
|
||||
|
||||
tracker_list = []
|
||||
|
||||
for tracker in trackers:
|
||||
|
@ -421,8 +443,9 @@ class Torrent(object):
|
|||
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"])
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
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:
|
||||
|
@ -444,7 +467,8 @@ class Torrent(object):
|
|||
"""Updates the state based on what libtorrent's state for the torrent is"""
|
||||
# Set the initial state based on the lt state
|
||||
LTSTATE = deluge.common.LT_TORRENT_STATE
|
||||
ltstate = int(self.handle.status().state)
|
||||
status = self.handle.status()
|
||||
ltstate = int(status.state)
|
||||
|
||||
# Set self.state to the ltstate right away just incase we don't hit some
|
||||
# of the logic below
|
||||
|
@ -453,21 +477,26 @@ class Torrent(object):
|
|||
else:
|
||||
self.state = str(ltstate)
|
||||
|
||||
session_is_paused = component.get("Core").session.is_paused()
|
||||
is_auto_managed = self.handle.is_auto_managed()
|
||||
handle_is_paused = self.handle.is_paused()
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("set_state_based_on_ltstate: %s", deluge.common.LT_TORRENT_STATE[ltstate])
|
||||
log.debug("session.is_paused: %s", component.get("Core").session.is_paused())
|
||||
log.debug("session.is_paused: %s", session_is_paused)
|
||||
|
||||
# First we check for an error from libtorrent, and set the state to that
|
||||
# if any occurred.
|
||||
if len(self.handle.status().error) > 0:
|
||||
if len(status.error) > 0:
|
||||
# This is an error'd torrent
|
||||
self.state = "Error"
|
||||
self.set_status_message(self.handle.status().error)
|
||||
if self.handle.is_paused():
|
||||
self.set_status_message(status.error)
|
||||
if handle_is_paused:
|
||||
self.handle.auto_managed(False)
|
||||
return
|
||||
|
||||
if ltstate == LTSTATE["Queued"] or ltstate == LTSTATE["Checking"]:
|
||||
if self.handle.is_paused():
|
||||
if handle_is_paused:
|
||||
self.state = "Paused"
|
||||
else:
|
||||
self.state = "Checking"
|
||||
|
@ -479,9 +508,9 @@ class Torrent(object):
|
|||
elif ltstate == LTSTATE["Allocating"]:
|
||||
self.state = "Allocating"
|
||||
|
||||
if self.handle.is_paused() and self.handle.is_auto_managed() and not component.get("Core").session.is_paused():
|
||||
if not session_is_paused and handle_is_paused and is_auto_managed:
|
||||
self.state = "Queued"
|
||||
elif component.get("Core").session.is_paused() or (self.handle.is_paused() and not self.handle.is_auto_managed()):
|
||||
elif session_is_paused or (handle_is_paused and not is_auto_managed):
|
||||
self.state = "Paused"
|
||||
|
||||
def set_state(self, state):
|
||||
|
@ -498,11 +527,7 @@ class Torrent(object):
|
|||
|
||||
def get_eta(self):
|
||||
"""Returns the ETA in seconds for this torrent"""
|
||||
if self.status == None:
|
||||
status = self.handle.status()
|
||||
else:
|
||||
status = self.status
|
||||
|
||||
if self.is_finished and self.options["stop_at_ratio"]:
|
||||
# We're a seed, so calculate the time to the 'stop_share_ratio'
|
||||
if not status.upload_payload_rate:
|
||||
|
@ -524,32 +549,21 @@ class Torrent(object):
|
|||
|
||||
def get_ratio(self):
|
||||
"""Returns the ratio for this torrent"""
|
||||
if self.status == None:
|
||||
status = self.handle.status()
|
||||
else:
|
||||
status = self.status
|
||||
|
||||
if status.total_done > 0:
|
||||
if self.status.total_done > 0:
|
||||
# We use 'total_done' if the downloaded value is 0
|
||||
downloaded = status.total_done
|
||||
downloaded = self.status.total_done
|
||||
else:
|
||||
# Return -1.0 to signify infinity
|
||||
return -1.0
|
||||
|
||||
return float(status.all_time_upload) / float(downloaded)
|
||||
return float(self.status.all_time_upload) / float(downloaded)
|
||||
|
||||
def get_files(self):
|
||||
"""Returns a list of files this torrent contains"""
|
||||
if self.torrent_info == None and self.handle.has_metadata():
|
||||
torrent_info = self.handle.get_torrent_info()
|
||||
else:
|
||||
torrent_info = self.torrent_info
|
||||
|
||||
if not torrent_info:
|
||||
if not self.has_metadata():
|
||||
return []
|
||||
|
||||
ret = []
|
||||
files = torrent_info.files()
|
||||
files = self.torrent_info.files()
|
||||
for index, file in enumerate(files):
|
||||
ret.append({
|
||||
'index': index,
|
||||
|
@ -599,7 +613,7 @@ class Torrent(object):
|
|||
|
||||
def get_file_progress(self):
|
||||
"""Returns the file progress as a list of floats.. 0.0 -> 1.0"""
|
||||
if not self.handle.has_metadata():
|
||||
if not self.has_metadata():
|
||||
return 0.0
|
||||
|
||||
file_progress = self.handle.file_progress()
|
||||
|
@ -618,9 +632,6 @@ class Torrent(object):
|
|||
if self.tracker_host:
|
||||
return self.tracker_host
|
||||
|
||||
if not self.status:
|
||||
self.status = self.handle.status()
|
||||
|
||||
tracker = self.status.current_tracker
|
||||
if not tracker and self.trackers:
|
||||
tracker = self.trackers[0]["url"]
|
||||
|
@ -659,7 +670,7 @@ class Torrent(object):
|
|||
self.calculate_last_seen_complete()
|
||||
return self._last_seen_complete
|
||||
|
||||
def get_status(self, keys, diff=False):
|
||||
def get_status(self, keys, diff=False, update=False):
|
||||
"""
|
||||
Returns the status of the torrent based on the keys provided
|
||||
|
||||
|
@ -668,151 +679,27 @@ class Torrent(object):
|
|||
:param diff: if True, will return a diff of the changes since the last
|
||||
call to get_status based on the session_id
|
||||
:type diff: bool
|
||||
:param update: if True, the status will be updated from libtorrent
|
||||
if False, the cached values will be returned
|
||||
:type update: bool
|
||||
|
||||
:returns: a dictionary of the status keys and their values
|
||||
:rtype: dict
|
||||
|
||||
"""
|
||||
if update:
|
||||
self.update_status(self.handle.status())
|
||||
|
||||
# Create the full dictionary
|
||||
self.status = self.handle.status()
|
||||
if self.handle.has_metadata():
|
||||
self.torrent_info = self.handle.get_torrent_info()
|
||||
if not keys:
|
||||
keys = self.status_funcs.keys()
|
||||
|
||||
# Adjust progress to be 0-100 value
|
||||
progress = self.status.progress * 100
|
||||
|
||||
# Adjust status.distributed_copies to return a non-negative value
|
||||
distributed_copies = self.status.distributed_copies
|
||||
if distributed_copies < 0:
|
||||
distributed_copies = 0.0
|
||||
|
||||
# Calculate the seeds:peers ratio
|
||||
if self.status.num_incomplete == 0:
|
||||
# Use -1.0 to signify infinity
|
||||
seeds_peers_ratio = -1.0
|
||||
else:
|
||||
seeds_peers_ratio = self.status.num_complete / float(self.status.num_incomplete)
|
||||
|
||||
full_status = {
|
||||
"active_time": self.status.active_time,
|
||||
"all_time_download": self.status.all_time_download,
|
||||
"compact": self.options["compact_allocation"],
|
||||
"distributed_copies": distributed_copies,
|
||||
"download_payload_rate": self.status.download_payload_rate,
|
||||
"file_priorities": self.options["file_priorities"],
|
||||
"hash": self.torrent_id,
|
||||
"is_auto_managed": self.options["auto_managed"],
|
||||
"is_finished": self.is_finished,
|
||||
"max_connections": self.options["max_connections"],
|
||||
"max_download_speed": self.options["max_download_speed"],
|
||||
"max_upload_slots": self.options["max_upload_slots"],
|
||||
"max_upload_speed": self.options["max_upload_speed"],
|
||||
"message": self.statusmsg,
|
||||
"move_on_completed_path": self.options["move_completed_path"],
|
||||
"move_on_completed": self.options["move_completed"],
|
||||
"move_completed_path": self.options["move_completed_path"],
|
||||
"move_completed": self.options["move_completed"],
|
||||
"next_announce": self.status.next_announce.seconds,
|
||||
"num_peers": self.status.num_peers - self.status.num_seeds,
|
||||
"num_seeds": self.status.num_seeds,
|
||||
"owner": self.owner,
|
||||
"paused": self.status.paused,
|
||||
"prioritize_first_last": self.options["prioritize_first_last_pieces"],
|
||||
"sequential_download": self.options["sequential_download"],
|
||||
"progress": progress,
|
||||
"shared": self.options["shared"],
|
||||
"remove_at_ratio": self.options["remove_at_ratio"],
|
||||
"save_path": self.options["download_location"],
|
||||
"seeding_time": self.status.seeding_time,
|
||||
"seeds_peers_ratio": seeds_peers_ratio,
|
||||
"seed_rank": self.status.seed_rank,
|
||||
"state": self.state,
|
||||
"stop_at_ratio": self.options["stop_at_ratio"],
|
||||
"stop_ratio": self.options["stop_ratio"],
|
||||
"time_added": self.time_added,
|
||||
"total_done": self.status.total_done,
|
||||
"total_payload_download": self.status.total_payload_download,
|
||||
"total_payload_upload": self.status.total_payload_upload,
|
||||
"total_peers": self.status.num_incomplete,
|
||||
"total_seeds": self.status.num_complete,
|
||||
"total_uploaded": self.status.all_time_upload,
|
||||
"total_wanted": self.status.total_wanted,
|
||||
"tracker": self.status.current_tracker,
|
||||
"trackers": self.trackers,
|
||||
"tracker_status": self.tracker_status,
|
||||
"upload_payload_rate": self.status.upload_payload_rate
|
||||
}
|
||||
|
||||
def ti_comment():
|
||||
if self.handle.has_metadata():
|
||||
try:
|
||||
return self.torrent_info.comment().decode("utf8", "ignore")
|
||||
except UnicodeDecodeError:
|
||||
return self.torrent_info.comment()
|
||||
return ""
|
||||
|
||||
def ti_priv():
|
||||
if self.handle.has_metadata():
|
||||
return self.torrent_info.priv()
|
||||
return False
|
||||
def ti_total_size():
|
||||
if self.handle.has_metadata():
|
||||
return self.torrent_info.total_size()
|
||||
return 0
|
||||
def ti_num_files():
|
||||
if self.handle.has_metadata():
|
||||
return self.torrent_info.num_files()
|
||||
return 0
|
||||
def ti_num_pieces():
|
||||
if self.handle.has_metadata():
|
||||
return self.torrent_info.num_pieces()
|
||||
return 0
|
||||
def ti_piece_length():
|
||||
if self.handle.has_metadata():
|
||||
return self.torrent_info.piece_length()
|
||||
return 0
|
||||
def ti_pieces_info():
|
||||
if self.handle.has_metadata():
|
||||
return self.get_pieces_info()
|
||||
return None
|
||||
|
||||
fns = {
|
||||
"comment": ti_comment,
|
||||
"eta": self.get_eta,
|
||||
"file_progress": self.get_file_progress,
|
||||
"files": self.get_files,
|
||||
"is_seed": self.handle.is_seed,
|
||||
"name": self.get_name,
|
||||
"num_files": ti_num_files,
|
||||
"num_pieces": ti_num_pieces,
|
||||
"pieces": ti_pieces_info,
|
||||
"peers": self.get_peers,
|
||||
"piece_length": ti_piece_length,
|
||||
"private": ti_priv,
|
||||
"queue": self.handle.queue_position,
|
||||
"ratio": self.get_ratio,
|
||||
"total_size": ti_total_size,
|
||||
"tracker_host": self.get_tracker_host,
|
||||
"last_seen_complete": self.get_last_seen_complete
|
||||
}
|
||||
|
||||
# Create the desired status dictionary and return it
|
||||
status_dict = {}
|
||||
|
||||
if len(keys) == 0:
|
||||
status_dict = full_status
|
||||
for key in fns:
|
||||
status_dict[key] = fns[key]()
|
||||
else:
|
||||
for key in keys:
|
||||
if key in full_status:
|
||||
status_dict[key] = full_status[key]
|
||||
elif key in fns:
|
||||
status_dict[key] = fns[key]()
|
||||
status_dict[key] = self.status_funcs[key]()
|
||||
|
||||
session_id = self.rpcserver.get_session_id()
|
||||
if diff:
|
||||
session_id = self.rpcserver.get_session_id()
|
||||
if session_id in self.prev_status:
|
||||
# We have a previous status dict, so lets make a diff
|
||||
status_diff = {}
|
||||
|
@ -831,6 +718,157 @@ class Torrent(object):
|
|||
|
||||
return status_dict
|
||||
|
||||
def update_status(self, status):
|
||||
"""
|
||||
Updates the cached status.
|
||||
|
||||
:param status: a libtorrent status
|
||||
:type status: libtorrent.torrent_status
|
||||
|
||||
"""
|
||||
#import datetime
|
||||
#print datetime.datetime.now().strftime("%H:%M:%S.%f"),
|
||||
#print " update_status"
|
||||
self.status = status
|
||||
|
||||
if self.torrent_info is None and self.has_metadata():
|
||||
self.torrent_info = self.handle.get_torrent_info()
|
||||
|
||||
def _create_status_funcs(self):
|
||||
#if you add a key here->add it to core.py STATUS_KEYS too.
|
||||
self.status_funcs = {
|
||||
"active_time": lambda: self.status.active_time,
|
||||
"all_time_download": lambda: self.status.all_time_download,
|
||||
"compact": lambda: self.options["compact_allocation"],
|
||||
"distributed_copies": lambda: 0.0 if self.status.distributed_copies < 0 else \
|
||||
self.status.distributed_copies, # Adjust status.distributed_copies to return a non-negative value
|
||||
"download_payload_rate": lambda: self.status.download_payload_rate,
|
||||
"file_priorities": lambda: self.options["file_priorities"],
|
||||
"hash": lambda: self.torrent_id,
|
||||
"is_auto_managed": lambda: self.options["auto_managed"],
|
||||
"is_finished": lambda: self.is_finished,
|
||||
"max_connections": lambda: self.options["max_connections"],
|
||||
"max_download_speed": lambda: self.options["max_download_speed"],
|
||||
"max_upload_slots": lambda: self.options["max_upload_slots"],
|
||||
"max_upload_speed": lambda: self.options["max_upload_speed"],
|
||||
"message": lambda: self.statusmsg,
|
||||
"move_on_completed_path": lambda: self.options["move_completed_path"],
|
||||
"move_on_completed": lambda: self.options["move_completed"],
|
||||
"move_completed_path": lambda: self.options["move_completed_path"],
|
||||
"move_completed": lambda: self.options["move_completed"],
|
||||
"next_announce": lambda: self.status.next_announce.seconds,
|
||||
"num_peers": lambda: self.status.num_peers - self.status.num_seeds,
|
||||
"num_seeds": lambda: self.status.num_seeds,
|
||||
"owner": lambda: self.owner,
|
||||
"paused": lambda: self.status.paused,
|
||||
"prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"],
|
||||
"sequential_download": lambda: self.options["sequential_download"],
|
||||
"progress": lambda: self.status.progress * 100,
|
||||
"shared": lambda: self.options["shared"],
|
||||
"remove_at_ratio": lambda: self.options["remove_at_ratio"],
|
||||
"save_path": lambda: self.options["download_location"],
|
||||
"seeding_time": lambda: self.status.seeding_time,
|
||||
"seeds_peers_ratio": lambda: -1.0 if self.status.num_incomplete == 0 else \
|
||||
self.status.num_complete / float(self.status.num_incomplete), # Use -1.0 to signify infinity
|
||||
"seed_rank": lambda: self.status.seed_rank,
|
||||
"state": lambda: self.state,
|
||||
"stop_at_ratio": lambda: self.options["stop_at_ratio"],
|
||||
"stop_ratio": lambda: self.options["stop_ratio"],
|
||||
"time_added": lambda: self.time_added,
|
||||
"total_done": lambda: self.status.total_done,
|
||||
"total_payload_download": lambda: self.status.total_payload_download,
|
||||
"total_payload_upload": lambda: self.status.total_payload_upload,
|
||||
"total_peers": lambda: self.status.num_incomplete,
|
||||
"total_seeds": lambda: self.status.num_complete,
|
||||
"total_uploaded": lambda: self.status.all_time_upload,
|
||||
"total_wanted": lambda: self.status.total_wanted,
|
||||
"tracker": lambda: self.status.current_tracker,
|
||||
"trackers": lambda: self.trackers,
|
||||
"tracker_status": lambda: self.tracker_status,
|
||||
"upload_payload_rate": lambda: self.status.upload_payload_rate,
|
||||
"eta": self.get_eta,
|
||||
"file_progress": self.get_file_progress, # Adjust progress to be 0-100 value
|
||||
"files": self.get_files,
|
||||
"is_seed": self.handle.is_seed,
|
||||
"peers": self.get_peers,
|
||||
"queue": self.handle.queue_position,
|
||||
"ratio": self.get_ratio,
|
||||
"tracker_host": self.get_tracker_host,
|
||||
"last_seen_complete": self.get_last_seen_complete,
|
||||
"comment": self.ti_comment,
|
||||
"name": self.ti_name,
|
||||
"num_files": self.ti_num_files,
|
||||
"num_pieces": self.ti_num_pieces,
|
||||
"pieces": self.ti_pieces_info,
|
||||
"piece_length": self.ti_piece_length,
|
||||
"private": self.ti_priv,
|
||||
"total_size": self.ti_total_size,
|
||||
}
|
||||
|
||||
def ti_comment(self):
|
||||
if self.has_metadata():
|
||||
try:
|
||||
return self.torrent_info.comment().decode("utf8", "ignore")
|
||||
except UnicodeDecodeError:
|
||||
return self.torrent_info.comment()
|
||||
return ""
|
||||
|
||||
def ti_name(self):
|
||||
if self.has_metadata():
|
||||
name = self.torrent_info.file_at(0).path.split("/", 1)[0]
|
||||
if not name:
|
||||
name = self.torrent_info.name()
|
||||
try:
|
||||
return name.decode("utf8", "ignore")
|
||||
except UnicodeDecodeError:
|
||||
return name
|
||||
|
||||
elif self.magnet:
|
||||
try:
|
||||
keys = dict([k.split('=') for k in self.magnet.split('?')[-1].split('&')])
|
||||
name = keys.get('dn')
|
||||
if not name:
|
||||
return self.torrent_id
|
||||
name = unquote(name).replace('+', ' ')
|
||||
try:
|
||||
return name.decode("utf8", "ignore")
|
||||
except UnicodeDecodeError:
|
||||
return name
|
||||
except:
|
||||
pass
|
||||
|
||||
return self.torrent_id
|
||||
|
||||
def ti_priv(self):
|
||||
if self.has_metadata():
|
||||
return self.torrent_info.priv()
|
||||
return False
|
||||
|
||||
def ti_total_size(self):
|
||||
if self.has_metadata():
|
||||
return self.torrent_info.total_size()
|
||||
return 0
|
||||
|
||||
def ti_num_files(self):
|
||||
if self.has_metadata():
|
||||
return self.torrent_info.num_files()
|
||||
return 0
|
||||
|
||||
def ti_num_pieces(self):
|
||||
if self.has_metadata():
|
||||
return self.torrent_info.num_pieces()
|
||||
return 0
|
||||
|
||||
def ti_piece_length(self):
|
||||
if self.has_metadata():
|
||||
return self.torrent_info.piece_length()
|
||||
return 0
|
||||
|
||||
def ti_pieces_info(self):
|
||||
if self.has_metadata():
|
||||
return self.get_pieces_info()
|
||||
return None
|
||||
|
||||
def apply_options(self):
|
||||
"""Applies the per-torrent options that are set."""
|
||||
self.handle.set_max_connections(self.max_connections)
|
||||
|
@ -943,7 +981,6 @@ class Torrent(object):
|
|||
self.torrent_id)
|
||||
log.debug("Writing torrent file: %s", path)
|
||||
try:
|
||||
self.torrent_info = self.handle.get_torrent_info()
|
||||
# Regenerate the file priorities
|
||||
self.set_file_priorities([])
|
||||
md = lt.bdecode(self.torrent_info.metadata())
|
||||
|
@ -1116,7 +1153,7 @@ class Torrent(object):
|
|||
pieces[peer_info.downloading_piece_index] = 2
|
||||
|
||||
# Now, the rest of the pieces
|
||||
for idx, piece in enumerate(self.handle.status().pieces):
|
||||
for idx, piece in enumerate(self.status.pieces):
|
||||
if idx in pieces:
|
||||
# Piece beeing downloaded, handled above
|
||||
continue
|
||||
|
|
|
@ -41,9 +41,11 @@ import os
|
|||
import shutil
|
||||
import operator
|
||||
import logging
|
||||
import time
|
||||
|
||||
from twisted.internet.task import LoopingCall
|
||||
from twisted.internet.defer import Deferred, DeferredList
|
||||
from twisted.internet import reactor
|
||||
|
||||
from deluge._libtorrent import lt
|
||||
|
||||
|
@ -157,6 +159,10 @@ class TorrentManager(component.Component):
|
|||
# Keeps track of resume data
|
||||
self.resume_data = {}
|
||||
|
||||
self.torrents_status_requests = []
|
||||
self.status_dict = {}
|
||||
self.last_state_update_alert_ts = 0
|
||||
|
||||
# Register set functions
|
||||
self.config.register_set_function("max_connections_per_torrent",
|
||||
self.on_set_max_connections_per_torrent)
|
||||
|
@ -200,6 +206,8 @@ class TorrentManager(component.Component):
|
|||
self.on_alert_file_error)
|
||||
self.alerts.register_handler("file_completed_alert",
|
||||
self.on_alert_file_completed)
|
||||
self.alerts.register_handler("state_update_alert",
|
||||
self.on_alert_state_update)
|
||||
|
||||
def start(self):
|
||||
# Get the pluginmanager reference
|
||||
|
@ -286,6 +294,7 @@ class TorrentManager(component.Component):
|
|||
torrent_info = None
|
||||
# Get the torrent data from the torrent file
|
||||
try:
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Attempting to create torrent_info from %s", filepath)
|
||||
_file = open(filepath, "rb")
|
||||
torrent_info = lt.torrent_info(lt.bdecode(_file.read()))
|
||||
|
@ -321,7 +330,6 @@ class TorrentManager(component.Component):
|
|||
def add(self, torrent_info=None, state=None, options=None, save_state=True,
|
||||
filedump=None, filename=None, magnet=None, resume_data=None, owner=None):
|
||||
"""Add a torrent to the manager and returns it's torrent_id"""
|
||||
|
||||
if owner is None:
|
||||
owner = component.get("RPCServer").get_session_user()
|
||||
if not owner:
|
||||
|
@ -331,7 +339,6 @@ class TorrentManager(component.Component):
|
|||
log.debug("You must specify a valid torrent_info, torrent state or magnet.")
|
||||
return
|
||||
|
||||
log.debug("torrentmanager.add")
|
||||
add_torrent_params = {}
|
||||
|
||||
if filedump is not None:
|
||||
|
@ -440,7 +447,7 @@ class TorrentManager(component.Component):
|
|||
|
||||
add_torrent_params["ti"] = torrent_info
|
||||
|
||||
#log.info("Adding torrent: %s", filename)
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("options: %s", options)
|
||||
|
||||
# Set the right storage_mode
|
||||
|
@ -475,6 +482,7 @@ class TorrentManager(component.Component):
|
|||
component.resume("AlertManager")
|
||||
return
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("handle id: %s", str(handle.info_hash()))
|
||||
# Set auto_managed to False because the torrent is paused
|
||||
handle.auto_managed(False)
|
||||
|
@ -486,6 +494,7 @@ class TorrentManager(component.Component):
|
|||
if not account_exists:
|
||||
owner = 'localclient'
|
||||
torrent = Torrent(handle, options, state, filename, magnet, owner)
|
||||
|
||||
# Add the torrent object to the dictionary
|
||||
self.torrents[torrent.torrent_id] = torrent
|
||||
if self.config["queue_new_to_top"]:
|
||||
|
@ -532,10 +541,14 @@ class TorrentManager(component.Component):
|
|||
component.get("EventManager").emit(
|
||||
TorrentAddedEvent(torrent.torrent_id, from_state)
|
||||
)
|
||||
log.info("Torrent %s from user \"%s\" %s",
|
||||
torrent.get_status(["name"])["name"],
|
||||
torrent.get_status(["owner"])["owner"],
|
||||
(from_state and "loaded" or "added"))
|
||||
|
||||
if log.isEnabledFor(logging.INFO):
|
||||
name_and_owner = torrent.get_status(["name", "owner"])
|
||||
log.info("Torrent %s from user \"%s\" %s" % (
|
||||
name_and_owner["name"],
|
||||
name_and_owner["owner"],
|
||||
from_state and "loaded" or "added")
|
||||
)
|
||||
return torrent.torrent_id
|
||||
|
||||
def load_torrent(self, torrent_id):
|
||||
|
@ -647,28 +660,35 @@ class TorrentManager(component.Component):
|
|||
|
||||
# Try to use an old state
|
||||
try:
|
||||
if len(state.torrents) > 0:
|
||||
state_tmp = TorrentState()
|
||||
if dir(state.torrents[0]) != dir(state_tmp):
|
||||
for attr in (set(dir(state_tmp)) - set(dir(state.torrents[0]))):
|
||||
for s in state.torrents:
|
||||
setattr(s, attr, getattr(state_tmp, attr, None))
|
||||
except Exception, e:
|
||||
log.warning("Unable to update state file to a compatible version: %s", e)
|
||||
log.exception("Unable to update state file to a compatible version: %s", e)
|
||||
|
||||
# Reorder the state.torrents list to add torrents in the correct queue
|
||||
# order.
|
||||
state.torrents.sort(key=operator.attrgetter("queue"), reverse=self.config["queue_new_to_top"])
|
||||
|
||||
resume_data = self.load_resume_data_file()
|
||||
|
||||
# Tell alertmanager to wait for the handlers while adding torrents.
|
||||
# This speeds up startup loading the torrents by quite a lot for some reason (~40%)
|
||||
self.alerts.wait_on_handler = True
|
||||
|
||||
for torrent_state in state.torrents:
|
||||
try:
|
||||
self.add(state=torrent_state, save_state=False,
|
||||
resume_data=resume_data.get(torrent_state.torrent_id))
|
||||
except AttributeError, e:
|
||||
log.error("Torrent state file is either corrupt or incompatible! %s", e)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
break
|
||||
|
||||
self.alerts.wait_on_handler = False
|
||||
|
||||
if lt.version_minor < 16:
|
||||
log.debug("libtorrent version is lower than 0.16. Start looping "
|
||||
|
@ -914,6 +934,7 @@ class TorrentManager(component.Component):
|
|||
self.save_resume_data((torrent_id, ))
|
||||
|
||||
def on_alert_torrent_paused(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_torrent_paused")
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
|
@ -931,6 +952,7 @@ class TorrentManager(component.Component):
|
|||
self.save_resume_data((torrent_id,))
|
||||
|
||||
def on_alert_torrent_checked(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_torrent_checked")
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
|
@ -948,6 +970,7 @@ class TorrentManager(component.Component):
|
|||
torrent.update_state()
|
||||
|
||||
def on_alert_tracker_reply(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_tracker_reply: %s", decode_string(alert.message()))
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
|
@ -964,6 +987,7 @@ class TorrentManager(component.Component):
|
|||
torrent.scrape_tracker()
|
||||
|
||||
def on_alert_tracker_announce(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_tracker_announce")
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
|
@ -1016,6 +1040,7 @@ class TorrentManager(component.Component):
|
|||
component.get("EventManager").emit(TorrentResumedEvent(torrent_id))
|
||||
|
||||
def on_alert_state_changed(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_state_changed")
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
|
@ -1036,6 +1061,7 @@ class TorrentManager(component.Component):
|
|||
component.get("EventManager").emit(TorrentStateChangedEvent(torrent_id, torrent.state))
|
||||
|
||||
def on_alert_save_resume_data(self, alert):
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_save_resume_data")
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
|
||||
|
@ -1096,3 +1122,75 @@ class TorrentManager(component.Component):
|
|||
return
|
||||
component.get("EventManager").emit(
|
||||
TorrentFileCompletedEvent(torrent_id, alert.index))
|
||||
|
||||
def separate_keys(self, keys, torrent_ids):
|
||||
"""Separates the input keys into keys for the Torrent class
|
||||
and keys for plugins.
|
||||
"""
|
||||
if self.torrents:
|
||||
for torrent_id in torrent_ids:
|
||||
if torrent_id in self.torrents:
|
||||
status_keys = self.torrents[torrent_id].status_funcs.keys()
|
||||
leftover_keys = list(set(keys) - set(status_keys))
|
||||
torrent_keys = list(set(keys) - set(leftover_keys))
|
||||
return torrent_keys, leftover_keys
|
||||
return [], []
|
||||
|
||||
def on_alert_state_update(self, alert):
|
||||
log.debug("on_status_notification: %s", alert.message())
|
||||
self.last_state_update_alert_ts = time.time()
|
||||
|
||||
for s in alert.status:
|
||||
torrent_id = str(s.info_hash)
|
||||
if torrent_id in self.torrents:
|
||||
self.torrents[torrent_id].update_status(s)
|
||||
|
||||
self.handle_torrents_status_callback(self.torrents_status_requests.pop())
|
||||
|
||||
def handle_torrents_status_callback(self, status_request):
|
||||
"""
|
||||
Builds the status dictionary with the values from the Torrent.
|
||||
"""
|
||||
d, torrent_ids, keys, diff = status_request
|
||||
status_dict = {}.fromkeys(torrent_ids)
|
||||
torrent_keys, plugin_keys = self.separate_keys(keys, torrent_ids)
|
||||
|
||||
# Get the torrent status for each torrent_id
|
||||
for torrent_id in torrent_ids:
|
||||
if not torrent_id in self.torrents:
|
||||
# The torrent_id does not exist in the dict.
|
||||
# Could be the clients cache (sessionproxy) isn't up to speed.
|
||||
del status_dict[torrent_id]
|
||||
else:
|
||||
status_dict[torrent_id] = self.torrents[torrent_id].get_status(torrent_keys, diff)
|
||||
self.status_dict = status_dict
|
||||
d.callback((status_dict, plugin_keys))
|
||||
|
||||
def torrents_status_update(self, torrent_ids, keys, diff=False):
|
||||
"""
|
||||
returns status dict for the supplied torrent_ids async
|
||||
If the torrent states were updated recently (less than 1.5 seconds ago,
|
||||
post_torrent_updates is not called. Instead the cached state is used.
|
||||
|
||||
:param torrent_ids: the torrent IDs to get the status on
|
||||
:type torrent_ids: list of str
|
||||
:param keys: the keys to get the status on
|
||||
:type keys: list of str
|
||||
:param diff: if True, will return a diff of the changes since the last
|
||||
call to get_status based on the session_id
|
||||
:type diff: bool
|
||||
|
||||
:returns: a status dictionary for the equested torrents.
|
||||
:rtype: dict
|
||||
|
||||
"""
|
||||
d = Deferred()
|
||||
now = time.time()
|
||||
# If last update was recent, use cached data instead of request updates from libtorrent
|
||||
if (now - self.last_state_update_alert_ts) < 1.5:
|
||||
reactor.callLater(0, self.handle_torrents_status_callback, (d, torrent_ids, keys, diff))
|
||||
else:
|
||||
# Ask libtorrent for status update
|
||||
self.torrents_status_requests.insert(0, (d, torrent_ids, keys, diff))
|
||||
self.session.post_torrent_updates()
|
||||
return d
|
||||
|
|
|
@ -194,16 +194,14 @@ class StatusBar(component.Component):
|
|||
|
||||
self.health = False
|
||||
|
||||
def update_config_values(configs):
|
||||
self._on_max_connections_global(configs["max_connections_global"])
|
||||
self._on_max_download_speed(configs["max_download_speed"])
|
||||
self._on_max_upload_speed(configs["max_upload_speed"])
|
||||
self._on_dht(configs["dht"])
|
||||
# Get some config values
|
||||
client.core.get_config_value(
|
||||
"max_connections_global").addCallback(self._on_max_connections_global)
|
||||
client.core.get_config_value(
|
||||
"max_download_speed").addCallback(self._on_max_download_speed)
|
||||
client.core.get_config_value(
|
||||
"max_upload_speed").addCallback(self._on_max_upload_speed)
|
||||
client.core.get_config_value("dht").addCallback(self._on_dht)
|
||||
|
||||
self.send_status_request()
|
||||
client.core.get_config_values(["max_connections_global", "max_download_speed",
|
||||
"max_upload_speed", "dht"]).addCallback(update_config_values)
|
||||
|
||||
def stop(self):
|
||||
# When stopped, we just show the not connected thingy
|
||||
|
|
|
@ -172,11 +172,10 @@ class SystemTray(component.Component):
|
|||
self.build_tray_bwsetsubmenu()
|
||||
|
||||
# Get some config values
|
||||
client.core.get_config_value(
|
||||
"max_download_speed").addCallback(self._on_max_download_speed)
|
||||
client.core.get_config_value(
|
||||
"max_upload_speed").addCallback(self._on_max_upload_speed)
|
||||
self.send_status_request()
|
||||
def update_config_values(configs):
|
||||
self._on_max_download_speed(configs["max_download_speed"])
|
||||
self._on_max_upload_speed(configs["max_upload_speed"])
|
||||
client.core.get_config_values(["max_download_speed", "max_upload_speed"]).addCallback(update_config_values)
|
||||
|
||||
def start(self):
|
||||
self.__start()
|
||||
|
|
|
@ -47,10 +47,8 @@ class SessionProxy(component.Component):
|
|||
The SessionProxy component is used to cache session information client-side
|
||||
to reduce the number of RPCs needed to provide a rich user interface.
|
||||
|
||||
On start-up it will query the Core for a full status of all the torrents in
|
||||
the session. After that point, it will query the Core for only changes in
|
||||
the status of the torrents and will try to satisfy client requests from the
|
||||
cache.
|
||||
It will query the Core for only changes in the status of the torrents
|
||||
and will try to satisfy client requests from the cache.
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
|
@ -78,18 +76,6 @@ class SessionProxy(component.Component):
|
|||
# so that upcoming queries or status updates don't throw errors.
|
||||
self.torrents.setdefault(torrent_id, [time.time(), {}])
|
||||
self.cache_times.setdefault(torrent_id, {})
|
||||
# These initial keys are the ones used for the visible columns(by
|
||||
# default) on the GTK UI torrent view. If either the console-ui
|
||||
# or the web-ui needs additional keys, add them here;
|
||||
# There's NO need to fetch every bit of status information from
|
||||
# core if it's not going to be used. Additional status fields
|
||||
# will be queried later, for example, when viewing the status tab
|
||||
# of a torrent.
|
||||
inital_keys = [
|
||||
'queue', 'state', 'name', 'total_wanted', 'progress', 'state',
|
||||
'download_payload_rate', 'upload_payload_rate', 'eta', 'owner'
|
||||
]
|
||||
self.get_torrents_status({'id': torrent_ids}, inital_keys)
|
||||
return client.core.get_session_state().addCallback(on_get_session_state)
|
||||
|
||||
def stop(self):
|
||||
|
|
Loading…
Reference in New Issue