parent
37df050e3b
commit
f7010b18f3
|
@ -100,7 +100,7 @@ class Config:
|
|||
if filedump == self.config:
|
||||
# The config has not changed so lets just return
|
||||
return
|
||||
except IOError:
|
||||
except (EOFError, IOError):
|
||||
log.warning("IOError: Unable to open file: '%s'", filename)
|
||||
|
||||
try:
|
||||
|
|
|
@ -78,7 +78,7 @@ class AlertManager(component.Component):
|
|||
# Handler is in this alert type list
|
||||
value.remove(handler)
|
||||
|
||||
def handle_alerts(self):
|
||||
def handle_alerts(self, wait=False):
|
||||
"""Pops all libtorrent alerts in the session queue and handles them
|
||||
appropriately."""
|
||||
alert = self.session.pop_alert()
|
||||
|
@ -91,7 +91,10 @@ class AlertManager(component.Component):
|
|||
# Call any handlers for this alert type
|
||||
if alert_type in self.handlers.keys():
|
||||
for handler in self.handlers[alert_type]:
|
||||
gobject.idle_add(handler, alert)
|
||||
if not wait:
|
||||
gobject.idle_add(handler, alert)
|
||||
else:
|
||||
handler(alert)
|
||||
|
||||
alert = self.session.pop_alert()
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ DEFAULT_PREFS = {
|
|||
"config_location": deluge.configmanager.get_config_dir(),
|
||||
"daemon_port": 58846,
|
||||
"allow_remote": False,
|
||||
"compact_allocation": True,
|
||||
"compact_allocation": False,
|
||||
"download_location": deluge.common.get_default_download_dir(),
|
||||
"listen_ports": [6881, 6891],
|
||||
"torrentfiles_location": os.path.join(deluge.configmanager.get_config_dir(), "torrentfiles"),
|
||||
|
@ -68,11 +68,11 @@ DEFAULT_PREFS = {
|
|||
"state_location": os.path.join(deluge.configmanager.get_config_dir(), "state"),
|
||||
"prioritize_first_last_pieces": False,
|
||||
"random_port": True,
|
||||
"dht": False,
|
||||
"upnp": False,
|
||||
"natpmp": False,
|
||||
"utpex": False,
|
||||
"lsd": False,
|
||||
"dht": True,
|
||||
"upnp": True,
|
||||
"natpmp": True,
|
||||
"utpex": True,
|
||||
"lsd": True,
|
||||
"enc_in_policy": 1,
|
||||
"enc_out_policy": 1,
|
||||
"enc_level": 2,
|
||||
|
@ -89,13 +89,16 @@ DEFAULT_PREFS = {
|
|||
"autoadd_location": "",
|
||||
"autoadd_enable": False,
|
||||
"add_paused": False,
|
||||
"max_active_seeding": -1,
|
||||
"max_active_downloading": -1,
|
||||
"max_active_seeding": 5,
|
||||
"max_active_downloading": 8,
|
||||
"queue_new_to_top": False,
|
||||
"queue_finished_to_bottom": False,
|
||||
"stop_seed_at_ratio": False,
|
||||
"remove_seed_at_ratio": False,
|
||||
"stop_seed_ratio": 1.00
|
||||
"stop_seed_ratio": 2.00,
|
||||
"share_ratio_limit": 2.00,
|
||||
"seed_time_ratio_limit": 7.00,
|
||||
"seed_time_limit": 180,
|
||||
"auto_managed": True
|
||||
}
|
||||
|
||||
class Core(
|
||||
|
@ -234,6 +237,16 @@ class Core(
|
|||
self._on_set_max_download_speed)
|
||||
self.config.register_set_function("max_upload_slots_global",
|
||||
self._on_set_max_upload_slots_global)
|
||||
self.config.register_set_function("share_ratio_limit",
|
||||
self._on_set_share_ratio_limit)
|
||||
self.config.register_set_function("seed_time_ratio_limit",
|
||||
self._on_set_seed_time_ratio_limit)
|
||||
self.config.register_set_function("seed_time_limit",
|
||||
self._on_set_seed_time_limit)
|
||||
self.config.register_set_function("max_active_downloading",
|
||||
self._on_set_max_active_downloading)
|
||||
self.config.register_set_function("max_active_seeding",
|
||||
self._on_set_max_active_seeding)
|
||||
|
||||
self.config.register_change_callback(self._on_config_value_change)
|
||||
# Start the AlertManager
|
||||
|
@ -550,7 +563,7 @@ class Core(
|
|||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue.top(torrent_id):
|
||||
if self.torrents.queue_top(torrent_id):
|
||||
self._torrent_queue_changed()
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
@ -562,7 +575,7 @@ class Core(
|
|||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue.up(torrent_id):
|
||||
if self.torrents.queue_up(torrent_id):
|
||||
self._torrent_queue_changed()
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
@ -574,7 +587,7 @@ class Core(
|
|||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue.down(torrent_id):
|
||||
if self.torrents.queue_down(torrent_id):
|
||||
self._torrent_queue_changed()
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
@ -584,7 +597,7 @@ class Core(
|
|||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrents.queue.bottom(torrent_id):
|
||||
if self.torrents.queue_bottom(torrent_id):
|
||||
self._torrent_queue_changed()
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
|
@ -755,3 +768,32 @@ class Core(
|
|||
def _on_set_max_upload_slots_global(self, key, value):
|
||||
log.debug("max_upload_slots_global set to %s..", value)
|
||||
self.session.set_max_uploads(value)
|
||||
|
||||
def _on_set_share_ratio_limit(self, key, value):
|
||||
log.debug("%s set to %s..", key, value)
|
||||
self.settings.share_ratio_limit = value
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
def _on_set_seed_time_ratio_limit(self, key, value):
|
||||
log.debug("%s set to %s..", key, value)
|
||||
self.settings.seed_time_ratio_limit = value
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
def _on_set_seed_time_limit(self, key, value):
|
||||
log.debug("%s set to %s..", key, value)
|
||||
# This value is stored in minutes in deluge, but libtorrent wants seconds
|
||||
self.settings.seed_time_limit = int(value * 60)
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
def _on_set_max_active_downloading(self, key, value):
|
||||
log.debug("%s set to %s..", key, value)
|
||||
log.debug("active_downloads: %s", self.settings.active_downloads)
|
||||
self.settings.active_downloads = value
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
def _on_set_max_active_seeding(self, key, value):
|
||||
log.debug("%s set to %s..", key, value)
|
||||
log.debug("active_seeds: %s", self.settings.active_seeds)
|
||||
self.settings.active_seeds = value
|
||||
self.session.set_settings(self.settings)
|
||||
|
||||
|
|
|
@ -51,9 +51,7 @@ class Torrent:
|
|||
log.debug("Creating torrent object %s", str(handle.info_hash()))
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
|
||||
# Get a reference to the TorrentQueue
|
||||
self.torrentqueue = component.get("TorrentQueue")
|
||||
|
||||
self.signals = component.get("SignalManager")
|
||||
|
||||
# Set the libtorrent handle
|
||||
|
@ -73,6 +71,9 @@ class Torrent:
|
|||
# Default total_uploaded to 0, this may be changed by the state
|
||||
self.total_uploaded = 0
|
||||
|
||||
# Set default auto_managed value
|
||||
self.set_auto_managed(options["auto_managed"])
|
||||
|
||||
# Load values from state if we have it
|
||||
if state is not None:
|
||||
# This is for saving the total uploaded between sessions
|
||||
|
@ -107,15 +108,12 @@ class Torrent:
|
|||
self.statusmsg = "OK"
|
||||
|
||||
# The torrents state
|
||||
self.state = ""
|
||||
#self.state = ""
|
||||
self.update_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.")
|
||||
|
||||
def set_tracker_status(self, status):
|
||||
|
@ -144,6 +142,11 @@ class Torrent:
|
|||
def set_save_path(self, save_path):
|
||||
self.save_path = save_path
|
||||
|
||||
def set_auto_managed(self, auto_managed):
|
||||
self.auto_managed = auto_managed
|
||||
if not self.handle.is_paused():
|
||||
self.handle.auto_managed(auto_managed)
|
||||
|
||||
def set_file_priorities(self, file_priorities):
|
||||
log.debug("setting %s's file priorities: %s", self.torrent_id, file_priorities)
|
||||
if 0 in self.file_priorities:
|
||||
|
@ -182,7 +185,7 @@ class Torrent:
|
|||
# Force a reannounce if there is at least 1 tracker
|
||||
self.force_reannounce()
|
||||
|
||||
def set_state_based_on_ltstate(self):
|
||||
def update_state(self):
|
||||
"""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
|
||||
|
@ -199,35 +202,26 @@ class Torrent:
|
|||
self.state = "Seeding"
|
||||
elif ltstate == LTSTATE["Allocating"]:
|
||||
self.state = "Allocating"
|
||||
|
||||
if self.handle.is_paused() and len(self.handle.status().error) > 0:
|
||||
# This is an error'd torrent
|
||||
self.state = "Error"
|
||||
self.set_status_message(self.handle.status().error)
|
||||
self.handle.auto_managed(False)
|
||||
elif self.handle.is_paused() and self.handle.is_auto_managed():
|
||||
self.state = "Queued"
|
||||
elif self.handle.is_paused() and not self.handle.is_auto_managed():
|
||||
self.state = "Paused"
|
||||
|
||||
def set_state(self, state):
|
||||
"""Accepts state strings, ie, "Paused", "Seeding", etc."""
|
||||
|
||||
if state not in TORRENT_STATE:
|
||||
log.debug("Trying to set an invalid state %s", state)
|
||||
return
|
||||
|
||||
if state != self.state:
|
||||
if state == "Queued" and not self.handle.is_paused():
|
||||
#component.get("TorrentManager").append_not_state_paused(self.torrent_id)
|
||||
self.next_pause_is_queued = True
|
||||
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"
|
||||
self.state = state
|
||||
return
|
||||
|
||||
log.debug("Setting %s's state to %s", self.torrent_id, state)
|
||||
self.state = state
|
||||
|
||||
# Update the torrentqueue on any state changes
|
||||
self.torrentqueue.update_queue()
|
||||
|
||||
def set_status_message(self, message):
|
||||
self.statusmsg = message
|
||||
|
||||
|
@ -288,11 +282,6 @@ class Torrent:
|
|||
'offset': file.offset
|
||||
})
|
||||
return ret
|
||||
|
||||
def get_queue_position(self):
|
||||
# We augment the queue position + 1 so that the user sees a 1 indexed
|
||||
# list.
|
||||
return self.torrentqueue[self.torrent_id] + 1
|
||||
|
||||
def get_peers(self):
|
||||
"""Returns a list of peers and various information about them"""
|
||||
|
@ -326,7 +315,11 @@ class Torrent:
|
|||
})
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_queue_position(self):
|
||||
"""Returns the torrents queue position"""
|
||||
return self.handle.queue_position()
|
||||
|
||||
def get_status(self, keys):
|
||||
"""Returns the status of the torrent based on the keys provided"""
|
||||
# Create the full dictionary
|
||||
|
@ -371,7 +364,11 @@ class Torrent:
|
|||
"max_download_speed": self.max_download_speed,
|
||||
"prioritize_first_last": self.prioritize_first_last,
|
||||
"message": self.statusmsg,
|
||||
"hash": self.torrent_id
|
||||
"hash": self.torrent_id,
|
||||
"active_time": self.status.active_time,
|
||||
"seeding_time": self.status.seeding_time,
|
||||
"seed_rank": self.status.seed_rank,
|
||||
"is_auto_managed": self.auto_managed
|
||||
}
|
||||
|
||||
fns = {
|
||||
|
@ -384,9 +381,9 @@ class Torrent:
|
|||
"eta": self.get_eta,
|
||||
"ratio": self.get_ratio,
|
||||
"file_progress": self.handle.file_progress,
|
||||
"queue": self.get_queue_position,
|
||||
"queue": self.handle.queue_position,
|
||||
"is_seed": self.handle.is_seed,
|
||||
"peers": self.get_peers
|
||||
"peers": self.get_peers,
|
||||
}
|
||||
|
||||
self.status = None
|
||||
|
@ -419,10 +416,9 @@ class Torrent:
|
|||
|
||||
def pause(self):
|
||||
"""Pause this torrent"""
|
||||
if self.state == "Queued":
|
||||
self.set_state("Paused")
|
||||
return True
|
||||
|
||||
# Turn off auto-management so the torrent will not be unpaused by lt queueing
|
||||
self.handle.auto_managed(False)
|
||||
|
||||
try:
|
||||
self.handle.pause()
|
||||
except Exception, e:
|
||||
|
@ -443,55 +439,19 @@ class Torrent:
|
|||
if self.get_ratio() >= self.config["stop_seed_ratio"]:
|
||||
self.signals.emit("torrent_resume_at_stop_ratio")
|
||||
return
|
||||
|
||||
# If the torrent is a seed and there are already the max number of seeds
|
||||
# active, then just change it to a Queued state.
|
||||
if self.torrentqueue.get_num_seeding() >= self.config["max_active_seeding"]:
|
||||
self.set_state("Queued")
|
||||
|
||||
# Update the queuing order if necessary
|
||||
self.torrentqueue.update_order()
|
||||
|
||||
return True
|
||||
else:
|
||||
if self.torrentqueue.get_num_downloading() >= self.config["max_active_downloading"]:
|
||||
self.set_state("Queued")
|
||||
|
||||
# Update the queuing order if necessary
|
||||
self.torrentqueue.update_order()
|
||||
return True
|
||||
|
||||
|
||||
if self.auto_managed:
|
||||
# This torrent is to be auto-managed by lt queueing
|
||||
self.handle.auto_managed(True)
|
||||
|
||||
try:
|
||||
self.handle.resume()
|
||||
except:
|
||||
pass
|
||||
|
||||
if self.handle.is_finished():
|
||||
self.set_state("Seeding")
|
||||
else:
|
||||
# Only delete the .fastresume file if we're still downloading stuff
|
||||
self.delete_fastresume()
|
||||
self.set_state("Downloading")
|
||||
|
||||
return True
|
||||
|
||||
elif self.state == "Queued":
|
||||
if self.handle.is_finished():
|
||||
if self.torrentqueue.get_num_seeding() < self.config["max_active_seeding"] or\
|
||||
self.config["max_active_seeding"] == -1:
|
||||
self.handle.resume()
|
||||
self.state = "Seeding"
|
||||
self.torrentqueue.update_order()
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
if self.torrentqueue.get_num_downloading() < self.config["max_active_downloading"] or\
|
||||
self.config["max_active_downloading"] == -1:
|
||||
self.handle.resume()
|
||||
self.state = "Downloading"
|
||||
self.torrentqueue.update_order()
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def move_storage(self, dest):
|
||||
"""Move a torrent's storage location"""
|
||||
|
@ -566,4 +526,3 @@ class Torrent:
|
|||
log.debug("Unable to force recheck: %s", e)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ import deluge.libtorrent as lt
|
|||
|
||||
import deluge.common
|
||||
import deluge.component as component
|
||||
from deluge.core.torrentqueue import TorrentQueue
|
||||
from deluge.configmanager import ConfigManager
|
||||
from deluge.core.torrent import Torrent
|
||||
|
||||
|
@ -55,7 +54,7 @@ class TorrentState:
|
|||
total_uploaded,
|
||||
trackers,
|
||||
compact,
|
||||
state,
|
||||
paused,
|
||||
save_path,
|
||||
max_connections,
|
||||
max_upload_slots,
|
||||
|
@ -63,7 +62,8 @@ class TorrentState:
|
|||
max_download_speed,
|
||||
prioritize_first_last,
|
||||
file_priorities,
|
||||
queue
|
||||
queue,
|
||||
auto_managed
|
||||
):
|
||||
self.torrent_id = torrent_id
|
||||
self.total_uploaded = total_uploaded
|
||||
|
@ -72,7 +72,7 @@ class TorrentState:
|
|||
|
||||
# Options
|
||||
self.compact = compact
|
||||
self.state = state
|
||||
self.paused = paused
|
||||
self.save_path = save_path
|
||||
self.max_connections = max_connections
|
||||
self.max_upload_slots = max_upload_slots
|
||||
|
@ -80,6 +80,7 @@ class TorrentState:
|
|||
self.max_download_speed = max_download_speed
|
||||
self.prioritize_first_last = prioritize_first_last
|
||||
self.file_priorities = file_priorities
|
||||
self.auto_managed = auto_managed
|
||||
|
||||
class TorrentManagerState:
|
||||
def __init__(self):
|
||||
|
@ -91,7 +92,7 @@ class TorrentManager(component.Component):
|
|||
session for use on restart."""
|
||||
|
||||
def __init__(self, session, alerts):
|
||||
component.Component.__init__(self, "TorrentManager", depend=["PluginManager"])
|
||||
component.Component.__init__(self, "TorrentManager", interval=5000, depend=["PluginManager"])
|
||||
log.debug("TorrentManager init..")
|
||||
# Set the libtorrent session
|
||||
self.session = session
|
||||
|
@ -99,8 +100,6 @@ class TorrentManager(component.Component):
|
|||
self.alerts = alerts
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
# Create the TorrentQueue object
|
||||
self.queue = TorrentQueue()
|
||||
|
||||
# Create the torrents dict { torrent_id: Torrent }
|
||||
self.torrents = {}
|
||||
|
@ -131,7 +130,8 @@ class TorrentManager(component.Component):
|
|||
self.on_alert_tracker_warning)
|
||||
self.alerts.register_handler("storage_moved_alert",
|
||||
self.on_alert_storage_moved)
|
||||
self.alerts.register_handler("file_error_alert", self.on_alert_file_error)
|
||||
self.alerts.register_handler("torrent_resumed_alert",
|
||||
self.on_alert_torrent_resumed)
|
||||
|
||||
def start(self):
|
||||
# Get the pluginmanager reference
|
||||
|
@ -149,14 +149,17 @@ class TorrentManager(component.Component):
|
|||
# Save state on shutdown
|
||||
self.save_state()
|
||||
for key in self.torrents.keys():
|
||||
if not self.torrents[key].handle.is_paused() and \
|
||||
not self.torrents[key].handle.is_finished():
|
||||
if self.torrents[key].compact:
|
||||
try:
|
||||
self.torrents[key].pause()
|
||||
except:
|
||||
log.warning("Unable to pause torrent %s", key)
|
||||
self.torrents[key].write_fastresume()
|
||||
self.torrents[key].handle.pause()
|
||||
# Wait for all alerts
|
||||
self.alerts.handle_alerts(True)
|
||||
|
||||
def update(self):
|
||||
if self.config["stop_seed_at_ratio"]:
|
||||
for torrent in self.torrents:
|
||||
if torrent.get_ratio() >= self.config["stop_seed_ratio"]:
|
||||
torrent.pause()
|
||||
if self.config["remove_seed_at_ratio"]:
|
||||
self.remove(torrent.torrent_id)
|
||||
|
||||
def __getitem__(self, torrent_id):
|
||||
"""Return the Torrent with torrent_id"""
|
||||
|
@ -223,10 +226,16 @@ class TorrentManager(component.Component):
|
|||
options["file_priorities"] = state.file_priorities
|
||||
options["compact_allocation"] = state.compact
|
||||
options["download_location"] = state.save_path
|
||||
options["auto_managed"] = state.auto_managed
|
||||
options["add_paused"] = state.paused
|
||||
|
||||
add_torrent_params["ti"] =\
|
||||
self.get_torrent_info_from_file(
|
||||
os.path.join(self.config["state_location"], state.torrent_id + ".torrent"))
|
||||
if not add_torrent_params["ti"]:
|
||||
log.error("Unable to add torrent!")
|
||||
return
|
||||
|
||||
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.
|
||||
|
@ -240,6 +249,7 @@ class TorrentManager(component.Component):
|
|||
"prioritize_first_last_pieces",
|
||||
"download_location",
|
||||
"add_paused",
|
||||
"auto_managed"
|
||||
]
|
||||
|
||||
if options == None:
|
||||
|
@ -292,28 +302,15 @@ class TorrentManager(component.Component):
|
|||
torrent = Torrent(handle, options, state)
|
||||
# Add the torrent object to the dictionary
|
||||
self.torrents[torrent.torrent_id] = torrent
|
||||
if self.config["queue_new_to_top"]:
|
||||
handle.queue_position_top()
|
||||
|
||||
component.resume("AlertManager")
|
||||
|
||||
# Add the torrent to the queue
|
||||
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)
|
||||
else:
|
||||
self.queue.append(torrent.torrent_id)
|
||||
|
||||
log.debug("state: %s", state)
|
||||
|
||||
# Resume the torrent if needed
|
||||
if state == "Paused" or state == "Error":
|
||||
torrent.state = "Paused"
|
||||
elif state == None and not options["add_paused"]:
|
||||
torrent.handle.resume()
|
||||
# We set the state based on libtorrent's state
|
||||
torrent.set_state_based_on_ltstate()
|
||||
elif state == None and options["add_paused"]:
|
||||
torrent.set_state = "Paused"
|
||||
if not options["add_paused"]:
|
||||
handle.resume()
|
||||
handle.auto_managed(options["auto_managed"])
|
||||
|
||||
if save_state:
|
||||
# Save the session state
|
||||
|
@ -342,7 +339,7 @@ class TorrentManager(component.Component):
|
|||
|
||||
return filedump
|
||||
|
||||
def remove(self, torrent_id, remove_torrent, remove_data):
|
||||
def remove(self, torrent_id, remove_torrent=False, remove_data=False):
|
||||
"""Remove a torrent from the manager"""
|
||||
try:
|
||||
# Remove from libtorrent session
|
||||
|
@ -372,9 +369,6 @@ class TorrentManager(component.Component):
|
|||
# Remove the .torrent file in the state
|
||||
self.torrents[torrent_id].delete_torrentfile()
|
||||
|
||||
# Remove the torrent from the queue
|
||||
self.queue.remove(torrent_id)
|
||||
|
||||
# Remove the torrent from deluge's session
|
||||
try:
|
||||
del self.torrents[torrent_id]
|
||||
|
@ -418,60 +412,44 @@ class TorrentManager(component.Component):
|
|||
os.path.join(self.config["state_location"], "torrents.state"), "rb")
|
||||
state = cPickle.load(state_file)
|
||||
state_file.close()
|
||||
except IOError:
|
||||
except (EOFError, IOError):
|
||||
log.warning("Unable to load state file.")
|
||||
|
||||
# Try to add the torrents in the state to the session
|
||||
resume_torrents = []
|
||||
# First lets clear the queue and make it the correct length.. This will
|
||||
# help with inserting values at the right position.
|
||||
self.queue.set_size(len(state.torrents))
|
||||
|
||||
# Reorder the state.torrents list to add torrents with .fastresume files
|
||||
# first.
|
||||
fr_first = []
|
||||
# Reorder the state.torrents list to add torrents in the correct queue
|
||||
# order.
|
||||
ordered_state = []
|
||||
for torrent_state in state.torrents:
|
||||
if os.path.exists(os.path.join(
|
||||
self.config["state_location"],
|
||||
torrent_state.torrent_id, ".fastresume")):
|
||||
fr_first.insert(0, torrent_state)
|
||||
else:
|
||||
fr_first.append(torrent_state)
|
||||
for t in ordered_state:
|
||||
if torrent_state.queue < t.queue:
|
||||
ordered_state.insert(0, torrent_state)
|
||||
break
|
||||
ordered_state.append(torrent_state)
|
||||
|
||||
for torrent_state in fr_first:
|
||||
for torrent_state in ordered_state:
|
||||
try:
|
||||
# We need to resume all non-add_paused torrents after plugin hook
|
||||
if torrent_state.state not in ["Paused", "Queued", "Error"]:
|
||||
resume_torrents.append(torrent_state.torrent_id)
|
||||
|
||||
self.add(
|
||||
state=torrent_state,
|
||||
save_state=False)
|
||||
|
||||
self.add(state=torrent_state, save_state=False)
|
||||
except AttributeError, e:
|
||||
log.error("Torrent state file is either corrupt or incompatible!")
|
||||
add_paused = {}
|
||||
break
|
||||
|
||||
# Run the post_session_load plugin hooks
|
||||
self.plugins.run_post_session_load()
|
||||
|
||||
# Resume any torrents that need to be resumed
|
||||
for torrent_id in resume_torrents:
|
||||
self.torrents[torrent_id].handle.resume()
|
||||
self.torrents[torrent_id].set_state_based_on_ltstate()
|
||||
|
||||
def save_state(self):
|
||||
"""Save the state of the TorrentManager to the torrents.state file"""
|
||||
state = TorrentManagerState()
|
||||
# Create the state for each Torrent and append to the list
|
||||
for torrent in self.torrents.values():
|
||||
paused = False
|
||||
if torrent.state == "Paused":
|
||||
paused = True
|
||||
|
||||
torrent_state = TorrentState(
|
||||
torrent.torrent_id,
|
||||
torrent.get_status(["total_uploaded"])["total_uploaded"],
|
||||
torrent.trackers,
|
||||
torrent.compact,
|
||||
torrent.state,
|
||||
paused,
|
||||
torrent.save_path,
|
||||
torrent.max_connections,
|
||||
torrent.max_upload_slots,
|
||||
|
@ -479,7 +457,8 @@ class TorrentManager(component.Component):
|
|||
torrent.max_download_speed,
|
||||
torrent.prioritize_first_last,
|
||||
torrent.file_priorities,
|
||||
torrent.get_status(["queue"])["queue"] - 1 # We subtract 1 due to augmentation
|
||||
torrent.get_queue_position(),
|
||||
torrent.auto_managed
|
||||
)
|
||||
state.torrents.append(torrent_state)
|
||||
|
||||
|
@ -496,7 +475,39 @@ class TorrentManager(component.Component):
|
|||
|
||||
# We return True so that the timer thread will continue
|
||||
return True
|
||||
|
||||
|
||||
def queue_top(self, torrent_id):
|
||||
"""Queue torrent to top"""
|
||||
if self.torrents[torrent_id].get_queue_position() == 0:
|
||||
return False
|
||||
|
||||
self.torrents[torrent_id].handle.queue_position_top()
|
||||
return True
|
||||
|
||||
def queue_up(self, torrent_id):
|
||||
"""Queue torrent up one position"""
|
||||
if self.torrents[torrent_id].get_queue_position() == 0:
|
||||
return False
|
||||
|
||||
self.torrents[torrent_id].handle.queue_position_up()
|
||||
return True
|
||||
|
||||
def queue_down(self, torrent_id):
|
||||
"""Queue torrent down one position"""
|
||||
if self.torrents[torrent_id].get_queue_position() == (len(self.torrents) - 1):
|
||||
return False
|
||||
|
||||
self.torrents[torrent_id].handle.queue_position_down()
|
||||
return True
|
||||
|
||||
def queue_bottom(self, torrent_id):
|
||||
"""Queue torrent to bottom"""
|
||||
if self.torrents[torrent_id].get_queue_position() == (len(self.torrents) - 1):
|
||||
return False
|
||||
|
||||
self.torrents[torrent_id].handle.queue_position_bottom()
|
||||
return True
|
||||
|
||||
def on_set_max_connections_per_torrent(self, key, value):
|
||||
"""Sets the per-torrent connection limit"""
|
||||
log.debug("max_connections_per_torrent set to %s..", value)
|
||||
|
@ -508,7 +519,7 @@ class TorrentManager(component.Component):
|
|||
log.debug("max_upload_slots_per_torrent set to %s..", value)
|
||||
for key in self.torrents.keys():
|
||||
self.torrents[key].set_max_upload_slots(value)
|
||||
|
||||
|
||||
def on_set_max_upload_speed_per_torrent(self, key, value):
|
||||
log.debug("max_upload_speed_per_torrent set to %s..", value)
|
||||
for key in self.torrents.keys():
|
||||
|
@ -525,20 +536,7 @@ class TorrentManager(component.Component):
|
|||
# Get the torrent_id
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
log.debug("%s is finished..", torrent_id)
|
||||
|
||||
# Queue to bottom if enabled
|
||||
if alert.msg() == "torrent has finished downloading":
|
||||
if self.config["queue_finished_to_bottom"]:
|
||||
self.queue.bottom(torrent_id)
|
||||
|
||||
# Set the torrent state if not paused
|
||||
if not self.torrents[torrent_id].handle.is_paused():
|
||||
if self.queue.get_num_seeding() < self.config["max_active_seeding"] or\
|
||||
self.config["max_active_seeding"] == -1:
|
||||
self.torrents[torrent_id].set_state("Seeding")
|
||||
else:
|
||||
self.torrents[torrent_id].set_state("Queued")
|
||||
|
||||
self.torrents[torrent_id].update_state()
|
||||
# Write the fastresume file
|
||||
self.torrents[torrent_id].write_fastresume()
|
||||
|
||||
|
@ -547,8 +545,7 @@ class TorrentManager(component.Component):
|
|||
# Get the torrent_id
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
# Set the torrent state
|
||||
log.debug("Setting state 'Paused'..")
|
||||
self.torrents[torrent_id].set_state("Paused")
|
||||
self.torrents[torrent_id].update_state()
|
||||
component.get("SignalManager").emit("torrent_paused", torrent_id)
|
||||
|
||||
# Write the fastresume file
|
||||
|
@ -559,12 +556,8 @@ class TorrentManager(component.Component):
|
|||
# Get the torrent_id
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
# Set the torrent state
|
||||
if not self.torrents[torrent_id].handle.is_paused():
|
||||
if self.torrents[torrent_id].handle.is_finished():
|
||||
self.torrents[torrent_id].set_state("Seeding")
|
||||
else:
|
||||
self.torrents[torrent_id].set_state("Downloading")
|
||||
|
||||
self.torrents[torrent_id].update_state()
|
||||
|
||||
def on_alert_tracker_reply(self, alert):
|
||||
log.debug("on_alert_tracker_reply")
|
||||
# Get the torrent_id
|
||||
|
@ -622,16 +615,16 @@ class TorrentManager(component.Component):
|
|||
|
||||
def on_alert_storage_moved(self, alert):
|
||||
log.debug("on_alert_storage_moved")
|
||||
log.debug("save_path: %s", alert.handle.save_path())
|
||||
# Get the torrent_id
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
try:
|
||||
log.debug("save_path2: %s", self.torrents[torrent_id].handle.save_path())
|
||||
self.torrents[torrent_id].set_save_path(alert.handle.save_path())
|
||||
except KeyError:
|
||||
log.debug("torrent_id doesn't exist.")
|
||||
|
||||
def on_alert_file_error(self, alert):
|
||||
log.debug("on_alert_file_error")
|
||||
def on_alert_torrent_resumed(self, alert):
|
||||
log.debug("on_alert_torrent_resumed")
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
self.torrents[torrent_id].set_state("Error")
|
||||
self.torrents[torrent_id].set_status_message(str(alert.msg()))
|
||||
|
||||
self.torrents[torrent_id].update_state()
|
||||
|
|
|
@ -1,331 +0,0 @@
|
|||
#
|
||||
# torrentqueue.py
|
||||
#
|
||||
# Copyright (C) 2007, 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
|
||||
#
|
||||
# Deluge is free software.
|
||||
#
|
||||
# You may redistribute it and/or modify it under the terms of the
|
||||
# GNU General Public License, as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# deluge is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with deluge. If not, write to:
|
||||
# The Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# In addition, as a special exception, the copyright holders give
|
||||
# permission to link the code of portions of this program with the OpenSSL
|
||||
# library.
|
||||
# You must obey the GNU General Public License in all respects for all of
|
||||
# the code used other than OpenSSL. If you modify file(s) with this
|
||||
# exception, you may extend this exception to your version of the file(s),
|
||||
# but you are not obligated to do so. If you do not wish to do so, delete
|
||||
# this exception statement from your version. If you delete this exception
|
||||
# statement from all source files in the program, then also delete it here.
|
||||
|
||||
import deluge.component as component
|
||||
import deluge.common
|
||||
from deluge.configmanager import ConfigManager
|
||||
from deluge.log import LOG as log
|
||||
|
||||
class TorrentQueue(component.Component):
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "TorrentQueue", depend=["TorrentManager"])
|
||||
# This is a list of torrent_ids in the queueing order
|
||||
self.queue = []
|
||||
|
||||
# These lists keep track of the torrent states
|
||||
self.seeding = []
|
||||
self.queued_seeding = []
|
||||
self.downloading = []
|
||||
self.queued_downloading = []
|
||||
|
||||
self.torrents = component.get("TorrentManager")
|
||||
self.config = ConfigManager("core.conf")
|
||||
|
||||
# Register config set functions
|
||||
self.config.register_set_function("max_active_seeding",
|
||||
self._on_set_max_active_seeding, False)
|
||||
self.config.register_set_function("max_active_downloading",
|
||||
self._on_set_max_active_downloading, False)
|
||||
|
||||
def update(self):
|
||||
# If we're not checking share ratios, just return
|
||||
if not self.config["stop_seed_at_ratio"]:
|
||||
return
|
||||
|
||||
stop_ratio = self.config["stop_seed_ratio"]
|
||||
|
||||
for torrent_id in self.torrents.get_torrent_list():
|
||||
if self.torrents[torrent_id].handle.is_finished():
|
||||
if self.torrents[torrent_id].get_ratio() >= stop_ratio:
|
||||
# This torrent is at or exceeding the stop ratio so we need to
|
||||
# pause or remove it from the session.
|
||||
if self.config["remove_seed_at_ratio"]:
|
||||
self.torrents.remove(torrent_id, False, False)
|
||||
else:
|
||||
self.torrents[torrent_id].pause()
|
||||
|
||||
def update_queue(self):
|
||||
# Updates the queueing order and max active states
|
||||
# This only gets called when necessary
|
||||
self.update_state_lists()
|
||||
self.update_order()
|
||||
self.update_max_active()
|
||||
|
||||
def update_state_lists(self):
|
||||
# Get ordered lists of torrents
|
||||
self.seeding = []
|
||||
self.queued_seeding = []
|
||||
self.downloading = []
|
||||
self.queued_downloading = []
|
||||
|
||||
for torrent_id in self.torrents.get_torrent_list():
|
||||
if self.torrents[torrent_id].state == "Seeding":
|
||||
self.seeding.append((self.queue.index(torrent_id), torrent_id))
|
||||
elif self.torrents[torrent_id].state == "Downloading":
|
||||
self.downloading.append((self.queue.index(torrent_id), torrent_id))
|
||||
elif self.torrents[torrent_id].state == "Queued":
|
||||
if self.torrents[torrent_id].handle.is_finished():
|
||||
self.queued_seeding.append((self.queue.index(torrent_id), torrent_id))
|
||||
else:
|
||||
self.queued_downloading.append((self.queue.index(torrent_id), torrent_id))
|
||||
|
||||
# We need to sort these lists by queue position
|
||||
self.seeding.sort()
|
||||
self.downloading.sort()
|
||||
self.queued_downloading.sort()
|
||||
self.queued_seeding.sort()
|
||||
|
||||
#log.debug("total seeding: %s", len(self.seeding))
|
||||
#log.debug("total downloading: %s", len(self.downloading))
|
||||
#log.debug("queued seeding: %s", len(self.queued_seeding))
|
||||
#log.debug("queued downloading: %s", len(self.queued_downloading))
|
||||
|
||||
def update_order(self):
|
||||
# This will queue/resume torrents if the queueing order changes
|
||||
|
||||
#try:
|
||||
# log.debug("max(seeding): %s", max(self.seeding)[0])
|
||||
# log.debug("min(queued_seeding): %s", min(self.queued_seeding)[0])
|
||||
#except:
|
||||
# pass
|
||||
|
||||
#log.debug("queued seeding: %s", self.queued_seeding)
|
||||
#log.debug("queued downloading: %s", self.queued_downloading)
|
||||
|
||||
if self.seeding != [] and self.queued_seeding != []:
|
||||
if min(self.queued_seeding)[0] < max(self.seeding)[0]:
|
||||
num_to_queue = max(self.seeding)[0] - min(self.queued_seeding)[0]
|
||||
log.debug("queueing: %s", self.seeding[-num_to_queue:])
|
||||
|
||||
for (pos, torrent_id) in self.seeding[-num_to_queue:]:
|
||||
self.torrents[torrent_id].set_state("Queued")
|
||||
|
||||
if self.downloading != [] and self.queued_downloading != []:
|
||||
if min(self.queued_downloading)[0] < max(self.downloading)[0]:
|
||||
num_to_queue = max(self.downloading)[0] - min(self.queued_downloading)[0]
|
||||
log.debug("queueing: %s", self.downloading[-num_to_queue:])
|
||||
|
||||
for (pos, torrent_id) in self.downloading[-num_to_queue:]:
|
||||
self.torrents[torrent_id].set_state("Queued")
|
||||
|
||||
def update_max_active(self):
|
||||
if self.config["max_active_seeding"] > -1:
|
||||
log.debug("max_active_seeding: %s", self.config["max_active_seeding"])
|
||||
if len(self.seeding) > self.config["max_active_seeding"]:
|
||||
# We need to queue some more torrents because we're over the active limit
|
||||
num_to_queue = len(self.seeding) - self.config["max_active_seeding"]
|
||||
for (pos, torrent_id) in self.seeding[-num_to_queue:]:
|
||||
self.torrents[torrent_id].set_state("Queued")
|
||||
else:
|
||||
# We need to unqueue more torrents if possible
|
||||
num_to_unqueue = self.config["max_active_seeding"] - len(self.seeding)
|
||||
to_unqueue = []
|
||||
if num_to_unqueue <= len(self.queued_seeding):
|
||||
to_unqueue = self.queued_seeding[:num_to_unqueue]
|
||||
else:
|
||||
to_unqueue = self.queued_seeding
|
||||
for (pos, torrent_id) in to_unqueue:
|
||||
self.torrents[torrent_id].resume()
|
||||
else:
|
||||
# The max_active_seeding is set to unlimited, so lets make sure
|
||||
# all queued seeds are activated.
|
||||
for (pos, torrent_id) in self.queued_seeding:
|
||||
self.torrents[torrent_id].resume()
|
||||
|
||||
if self.config["max_active_downloading"] > -1:
|
||||
if len(self.downloading) > self.config["max_active_downloading"]:
|
||||
num_to_queue = len(self.downloading) - self.config["max_active_downloading"]
|
||||
for (pos, torrent_id) in self.downloading[-num_to_queue:]:
|
||||
self.torrents[torrent_id].set_state("Queued")
|
||||
else:
|
||||
# We need to unqueue more torrents if possible
|
||||
num_to_unqueue = self.config["max_active_downloading"] - len(self.downloading)
|
||||
to_unqueue = []
|
||||
if num_to_unqueue <= len(self.queued_downloading):
|
||||
to_unqueue = self.queued_downloading[:num_to_unqueue]
|
||||
else:
|
||||
to_unqueue = self.queued_downloading
|
||||
for (pos, torrent_id) in to_unqueue:
|
||||
self.torrents[torrent_id].resume()
|
||||
else:
|
||||
# Unlimited downloading torrents set
|
||||
for (pos, torrent_id) in self.queued_downloading:
|
||||
self.torrents[torrent_id].resume()
|
||||
|
||||
def set_size(self, size):
|
||||
"""Clear and set the self.queue list to the length of size"""
|
||||
log.debug("Setting queue size to %s..", size)
|
||||
self.queue = [None] * size
|
||||
|
||||
def get_num_seeding(self):
|
||||
self.update_state_lists()
|
||||
return len(self.seeding)
|
||||
|
||||
def get_num_downloading(self):
|
||||
self.update_state_lists()
|
||||
return len(self.downloading)
|
||||
|
||||
def __getitem__(self, torrent_id):
|
||||
"""Return the queue position of the torrent_id"""
|
||||
try:
|
||||
return self.queue.index(torrent_id)
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
def append(self, torrent_id):
|
||||
"""Append torrent_id to the bottom of the queue"""
|
||||
log.debug("Append torrent %s to queue..", torrent_id)
|
||||
self.queue.append(torrent_id)
|
||||
return self.queue.index(torrent_id)
|
||||
|
||||
def prepend(self, torrent_id):
|
||||
"""Prepend torrent_id to the top of the queue"""
|
||||
log.debug("Prepend torrent %s to queue..", torrent_id)
|
||||
self.queue.insert(0, torrent_id)
|
||||
return self.queue.index(torrent_id)
|
||||
|
||||
def insert(self, position, torrent_id):
|
||||
"""Inserts torrent_id at position in queue."""
|
||||
log.debug("Inserting torrent %s at position %s..", torrent_id, position)
|
||||
|
||||
if position < 0:
|
||||
for q in self.queue:
|
||||
if q == None:
|
||||
self.queue[self.queue.index(q)] = torrent_id
|
||||
return self.queue.index(q)
|
||||
|
||||
self.queue.append(torrent_id)
|
||||
return self.queue.index(torrent_id)
|
||||
|
||||
else:
|
||||
if position > (len(self.queue) - 1):
|
||||
self.queue.insert(position, torrent_id)
|
||||
|
||||
try:
|
||||
value = self.queue[position]
|
||||
except KeyError, IndexError:
|
||||
self.queue.insert(position, torrent_id)
|
||||
return position
|
||||
|
||||
if value == None:
|
||||
self.queue[position] = torrent_id
|
||||
else:
|
||||
self.queue.insert(position, torrent_id)
|
||||
|
||||
return position
|
||||
|
||||
def remove(self, torrent_id):
|
||||
"""Removes torrent_id from the list"""
|
||||
log.debug("Remove torrent %s from queue..", torrent_id)
|
||||
self.queue.remove(torrent_id)
|
||||
|
||||
def up(self, torrent_id):
|
||||
"""Move torrent_id up one in the queue"""
|
||||
if torrent_id not in self.queue:
|
||||
# Raise KeyError if the torrent_id is not in the queue
|
||||
raise KeyError
|
||||
|
||||
log.debug("Move torrent %s up..", torrent_id)
|
||||
# Get the index of the torrent_id
|
||||
index = self.queue.index(torrent_id)
|
||||
|
||||
# Can't queue up if torrent is already at top
|
||||
if index is 0:
|
||||
return False
|
||||
|
||||
# Pop and insert the torrent_id at index - 1
|
||||
self.queue.insert(index - 1, self.queue.pop(index))
|
||||
self.update_queue()
|
||||
return True
|
||||
|
||||
def top(self, torrent_id):
|
||||
"""Move torrent_id to top of the queue"""
|
||||
if torrent_id not in self.queue:
|
||||
# Raise KeyError if the torrent_id is not in the queue
|
||||
raise KeyError
|
||||
|
||||
log.debug("Move torrent %s to top..", torrent_id)
|
||||
# Get the index of the torrent_id
|
||||
index = self.queue.index(torrent_id)
|
||||
|
||||
# Can't queue up if torrent is already at top
|
||||
if index is 0:
|
||||
return False
|
||||
|
||||
self.queue.insert(0, self.queue.pop(index))
|
||||
self.update_queue()
|
||||
return True
|
||||
|
||||
def down(self, torrent_id):
|
||||
"""Move torrent_id down one in the queue"""
|
||||
if torrent_id not in self.queue:
|
||||
# Raise KeyError if torrent_id is not in the queue
|
||||
raise KeyError
|
||||
|
||||
log.debug("Move torrent %s down..", torrent_id)
|
||||
# Get the index of the torrent_id
|
||||
index = self.queue.index(torrent_id)
|
||||
|
||||
# Can't queue down of torrent_id is at bottom
|
||||
if index is len(self.queue) - 1:
|
||||
return False
|
||||
|
||||
# Pop and insert the torrent_id at index + 1
|
||||
self.queue.insert(index + 1, self.queue.pop(index))
|
||||
self.update_queue()
|
||||
return True
|
||||
|
||||
def bottom(self, torrent_id):
|
||||
"""Move torrent_id to bottom of the queue"""
|
||||
if torrent_id not in self.queue:
|
||||
# Raise KeyError if torrent_id is not in the queue
|
||||
raise KeyError
|
||||
|
||||
log.debug("Move torrent %s to bottom..", torrent_id)
|
||||
# Get the index of the torrent_id
|
||||
index = self.queue.index(torrent_id)
|
||||
|
||||
# Can't queue down of torrent_id is at bottom
|
||||
if index is len(self.queue) - 1:
|
||||
return False
|
||||
|
||||
# Pop and append the torrent_id
|
||||
self.append(self.queue.pop(index))
|
||||
self.update_queue()
|
||||
return True
|
||||
|
||||
def _on_set_max_active_seeding(self, key, value):
|
||||
self.update_queue()
|
||||
|
||||
def _on_set_max_active_downloading(self, key, value):
|
||||
self.update_queue()
|
|
@ -194,7 +194,7 @@ class FilesTab(Tab):
|
|||
state_file = open(os.path.join(config_location, filename), "rb")
|
||||
state = cPickle.load(state_file)
|
||||
state_file.close()
|
||||
except IOError, e:
|
||||
except (EOFError, IOError), e:
|
||||
log.warning("Unable to load state file: %s", e)
|
||||
|
||||
if state == None:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.4.5 on Mon Jun 2 18:29:37 2008 -->
|
||||
<!--Generated with glade3 3.4.4 on Thu Jun 12 01:03:18 2008 -->
|
||||
<glade-interface>
|
||||
<widget class="GtkDialog" id="pref_dialog">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
|
@ -2153,40 +2153,6 @@ Disabled</property>
|
|||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="column_spacing">10</property>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_downloading">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">-1 -1 9999 1 10 10</property>
|
||||
<property name="snap_to_ticks">True</property>
|
||||
<property name="numeric">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_seeding">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">-1 -1 9999 1 10 10</property>
|
||||
<property name="snap_to_ticks">True</property>
|
||||
<property name="numeric">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label42">
|
||||
<property name="visible">True</property>
|
||||
|
@ -2195,11 +2161,25 @@ Disabled</property>
|
|||
<property name="label" translatable="yes">Total active downloading:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_downloading">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">0 -1 9999 1 10 10</property>
|
||||
<property name="snap_to_ticks">True</property>
|
||||
<property name="numeric">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label48">
|
||||
<property name="visible">True</property>
|
||||
|
@ -2208,9 +2188,29 @@ Disabled</property>
|
|||
<property name="label" translatable="yes">Total active seeding:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_seeding">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">0 -1 9999 1 10 10</property>
|
||||
<property name="snap_to_ticks">True</property>
|
||||
<property name="numeric">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -2251,13 +2251,93 @@ Disabled</property>
|
|||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="chk_finished_bottom">
|
||||
<widget class="GtkTable" id="table2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Queue newly finished torrents to bottom</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="column_spacing">10</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label53">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Share Ratio Limit:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label54">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Seed Time Ratio:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label55">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Seed Time (m):</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_share_ratio_limit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="width_chars">6</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">1.5 -1 100 0.10000000000000001 10 10</property>
|
||||
<property name="digits">2</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_seed_time_ratio_limit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="width_chars">6</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">6 -1 100 0.10000000000000001 10 10</property>
|
||||
<property name="digits">2</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSpinButton" id="spin_seed_time_limit">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="width_chars">6</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">6 -1 100 1 10 10</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -2286,7 +2366,7 @@ Disabled</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="adjustment">1 0.5 100 0.10000000000000001 1 1</property>
|
||||
<property name="adjustment">2 0.5 100 0.10000000000000001 1 1</property>
|
||||
<property name="digits">2</property>
|
||||
<property name="numeric">True</property>
|
||||
</widget>
|
||||
|
|
|
@ -189,7 +189,7 @@ class ListView:
|
|||
state_file = open(os.path.join(config_location, filename), "rb")
|
||||
state = cPickle.load(state_file)
|
||||
state_file.close()
|
||||
except IOError, e:
|
||||
except (EOFError, IOError), e:
|
||||
log.warning("Unable to load state file: %s", e)
|
||||
|
||||
# Keep the state in self.state so we can access it as we add new columns
|
||||
|
|
|
@ -83,8 +83,6 @@ class MainWindow(component.Component):
|
|||
except:
|
||||
pass
|
||||
|
||||
# Load the state prior to showing
|
||||
self.load_window_state()
|
||||
self.window.show()
|
||||
|
||||
def hide(self):
|
||||
|
|
|
@ -176,7 +176,7 @@ class PeersTab(Tab):
|
|||
state_file = open(os.path.join(config_location, filename), "rb")
|
||||
state = cPickle.load(state_file)
|
||||
state_file.close()
|
||||
except IOError, e:
|
||||
except (EOFError, IOError), e:
|
||||
log.warning("Unable to load state file: %s", e)
|
||||
|
||||
if state == None:
|
||||
|
|
|
@ -238,7 +238,10 @@ class Preferences(component.Component):
|
|||
"spin_seeding": ("value", self.core_config["max_active_seeding"]),
|
||||
"spin_downloading": ("value", self.core_config["max_active_downloading"]),
|
||||
"chk_queue_new_top": ("active", self.core_config["queue_new_to_top"]),
|
||||
"chk_finished_bottom": ("active", self.core_config["queue_finished_to_bottom"]),
|
||||
"spin_share_ratio_limit": ("value", self.core_config["share_ratio_limit"]),
|
||||
"spin_seed_time_ratio_limit": \
|
||||
("value", self.core_config["seed_time_ratio_limit"]),
|
||||
"spin_seed_time_limit": ("value", self.core_config["seed_time_limit"]),
|
||||
"chk_seed_ratio": ("active", self.core_config["stop_seed_at_ratio"]),
|
||||
"spin_share_ratio": ("value", self.core_config["stop_seed_ratio"]),
|
||||
"chk_remove_ratio": ("active", self.core_config["remove_seed_at_ratio"])
|
||||
|
@ -324,10 +327,12 @@ class Preferences(component.Component):
|
|||
"spin_seeding",
|
||||
"spin_downloading",
|
||||
"chk_queue_new_top",
|
||||
"chk_finished_bottom",
|
||||
"chk_seed_ratio",
|
||||
"spin_share_ratio",
|
||||
"chk_remove_ratio"
|
||||
"chk_remove_ratio",
|
||||
"spin_share_ratio_limit",
|
||||
"spin_seed_time_ratio_limit",
|
||||
"spin_seed_time_limit"
|
||||
]
|
||||
# We don't appear to be connected to a daemon
|
||||
for key in core_widget_list:
|
||||
|
@ -500,14 +505,18 @@ class Preferences(component.Component):
|
|||
self.glade.get_widget("spin_seeding").get_value_as_int()
|
||||
new_core_config["max_active_downloading"] = \
|
||||
self.glade.get_widget("spin_downloading").get_value_as_int()
|
||||
new_core_config["queue_finished_to_bottom"] = \
|
||||
self.glade.get_widget("chk_finished_bottom").get_active()
|
||||
new_core_config["stop_seed_at_ratio"] = \
|
||||
self.glade.get_widget("chk_seed_ratio").get_active()
|
||||
new_core_config["remove_seed_at_ratio"] = \
|
||||
self.glade.get_widget("chk_remove_ratio").get_active()
|
||||
new_core_config["stop_seed_ratio"] = \
|
||||
self.glade.get_widget("spin_share_ratio").get_value()
|
||||
new_core_config["share_ratio_limit"] = \
|
||||
self.glade.get_widget("spin_share_ratio_limit").get_value()
|
||||
new_core_config["seed_time_ratio_limit"] = \
|
||||
self.glade.get_widget("spin_seed_time_ratio_limit").get_value()
|
||||
new_core_config["seed_time_limit"] = \
|
||||
self.glade.get_widget("spin_seed_time_limit").get_value()
|
||||
|
||||
# GtkUI
|
||||
for key in new_gtkui_config.keys():
|
||||
|
|
|
@ -37,6 +37,7 @@ from deluge.ui.client import aclient as client
|
|||
import deluge.component as component
|
||||
import deluge.common
|
||||
from deluge.ui.gtkui.torrentdetails import Tab
|
||||
from deluge.log import LOG as log
|
||||
|
||||
def fpeer_sized(first, second):
|
||||
return "%s (%s)" % (deluge.common.fsize(first), deluge.common.fsize(second))
|
||||
|
@ -79,6 +80,10 @@ class StatisticsTab(Tab):
|
|||
(glade.get_widget("summary_share_ratio"), fratio, ("ratio",)),
|
||||
(glade.get_widget("summary_tracker_status"), None, ("tracker_status",)),
|
||||
(glade.get_widget("summary_next_announce"), deluge.common.ftime, ("next_announce",)),
|
||||
(glade.get_widget("summary_active_time"), deluge.common.ftime, ("active_time",)),
|
||||
(glade.get_widget("summary_seed_time"), deluge.common.ftime, ("seeding_time",)),
|
||||
(glade.get_widget("summary_seed_rank"), str, ("seed_rank",)),
|
||||
(glade.get_widget("summary_auto_managed"), str, ("is_auto_managed",)),
|
||||
(glade.get_widget("progressbar"), fpcnt, ("progress",))
|
||||
]
|
||||
|
||||
|
@ -100,7 +105,8 @@ class StatisticsTab(Tab):
|
|||
"upload_payload_rate", "num_peers", "num_seeds", "total_peers",
|
||||
"total_seeds", "eta", "ratio", "next_announce",
|
||||
"tracker_status", "max_connections", "max_upload_slots",
|
||||
"max_upload_speed", "max_download_speed"]
|
||||
"max_upload_speed", "max_download_speed", "active_time",
|
||||
"seeding_time", "seed_rank", "is_auto_managed"]
|
||||
|
||||
client.get_torrent_status(
|
||||
self._on_get_torrent_status, selected, status_keys)
|
||||
|
|
|
@ -299,7 +299,7 @@ class TorrentDetails(component.Component):
|
|||
state_file = open(os.path.join(config_location, filename), "rb")
|
||||
state = cPickle.load(state_file)
|
||||
state_file.close()
|
||||
except IOError, e:
|
||||
except (EOFError, IOError), e:
|
||||
log.warning("Unable to load state file: %s", e)
|
||||
|
||||
return state
|
||||
|
|
|
@ -92,7 +92,14 @@ def cell_data_progress(column, cell, model, row, data):
|
|||
textstr = textstr + " %.2f%%" % value
|
||||
if cell.get_property("text") != textstr:
|
||||
cell.set_property("text", textstr)
|
||||
|
||||
|
||||
def cell_data_queue(column, cell, model, row, data):
|
||||
value = model.get_value(row, data)
|
||||
if value < 0:
|
||||
cell.set_property("text", "")
|
||||
else:
|
||||
cell.set_property("text", value + 1)
|
||||
|
||||
class TorrentView(listview.ListView, component.Component):
|
||||
"""TorrentView handles the listing of torrents."""
|
||||
def __init__(self):
|
||||
|
@ -116,7 +123,7 @@ class TorrentView(listview.ListView, component.Component):
|
|||
# Add the columns to the listview
|
||||
self.add_text_column("torrent_id", hidden=True)
|
||||
self.add_bool_column("filter", hidden=True)
|
||||
self.add_text_column("#", col_type=int, status_field=["queue"])
|
||||
self.add_func_column("#", cell_data_queue, [int], status_field=["queue"])
|
||||
self.add_texticon_column(_("Name"), status_field=["state", "name"],
|
||||
function=cell_data_statusicon)
|
||||
self.add_func_column(_("Size"),
|
||||
|
|
|
@ -74,6 +74,7 @@ void bind_torrent_status()
|
|||
.def_readonly("seeding_time", &torrent_status::seeding_time)
|
||||
.def_readonly("seed_rank", &torrent_status::seed_rank)
|
||||
.def_readonly("last_scrape", &torrent_status::last_scrape)
|
||||
.def_readonly("error", &torrent_status::error)
|
||||
;
|
||||
|
||||
enum_<torrent_status::state_t>("states")
|
||||
|
|
|
@ -207,20 +207,11 @@ namespace libtorrent
|
|||
int num_blocks;
|
||||
// the pointers to the block data
|
||||
boost::shared_array<char*> blocks;
|
||||
#ifndef NDEBUG
|
||||
~cached_piece_entry()
|
||||
{
|
||||
TORRENT_ASSERT(storage == 0);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef boost::recursive_mutex mutex_t;
|
||||
typedef std::list<cached_piece_entry> cache_t;
|
||||
|
||||
char* allocate_buffer(mutex_t::scoped_lock& l);
|
||||
void free_buffer(char* buf, mutex_t::scoped_lock& l);
|
||||
|
||||
// cache operations
|
||||
cache_t::iterator find_cached_piece(
|
||||
cache_t& cache, disk_io_job const& j
|
||||
|
@ -228,7 +219,7 @@ namespace libtorrent
|
|||
|
||||
// write cache operations
|
||||
void flush_oldest_piece(mutex_t::scoped_lock& l);
|
||||
void flush_expired_pieces(mutex_t::scoped_lock& l);
|
||||
void flush_expired_pieces();
|
||||
void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
|
||||
void flush(cache_t::iterator i, mutex_t::scoped_lock& l);
|
||||
void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);
|
||||
|
@ -242,14 +233,18 @@ namespace libtorrent
|
|||
bool make_room(int num_blocks
|
||||
, cache_t::iterator ignore
|
||||
, mutex_t::scoped_lock& l);
|
||||
int try_read_from_cache(disk_io_job const& j, mutex_t::scoped_lock& l);
|
||||
int try_read_from_cache(disk_io_job const& j);
|
||||
|
||||
mutable mutex_t m_mutex;
|
||||
// this mutex only protects m_jobs, m_queue_buffer_size
|
||||
// and m_abort
|
||||
mutable mutex_t m_queue_mutex;
|
||||
boost::condition m_signal;
|
||||
bool m_abort;
|
||||
std::list<disk_io_job> m_jobs;
|
||||
size_type m_queue_buffer_size;
|
||||
|
||||
// this protects the piece cache and related members
|
||||
mutable mutex_t m_piece_mutex;
|
||||
// write cache
|
||||
cache_t m_pieces;
|
||||
|
||||
|
@ -280,6 +275,8 @@ namespace libtorrent
|
|||
bool m_coalesce_reads;
|
||||
bool m_use_read_cache;
|
||||
|
||||
// this only protects the pool allocator
|
||||
mutable mutex_t m_pool_mutex;
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
// memory pool for read and write operations
|
||||
// and disk cache
|
||||
|
|
|
@ -129,7 +129,7 @@ namespace libtorrent
|
|||
, resume_data(0)
|
||||
, storage_mode(storage_mode_sparse)
|
||||
, paused(true)
|
||||
, auto_managed(false)
|
||||
, auto_managed(true)
|
||||
, duplicate_is_error(false)
|
||||
, storage(sc)
|
||||
, userdata(0)
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace libtorrent
|
|||
|
||||
void disk_io_thread::join()
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_queue_mutex);
|
||||
disk_io_job j;
|
||||
j.action = disk_io_job::abort_thread;
|
||||
m_jobs.insert(m_jobs.begin(), j);
|
||||
|
@ -90,7 +90,7 @@ namespace libtorrent
|
|||
|
||||
void disk_io_thread::get_cache_info(sha1_hash const& ih, std::vector<cached_piece_info>& ret) const
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
ret.clear();
|
||||
ret.reserve(m_pieces.size());
|
||||
for (cache_t::const_iterator i = m_pieces.begin()
|
||||
|
@ -111,20 +111,20 @@ namespace libtorrent
|
|||
|
||||
cache_status disk_io_thread::status() const
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
return m_cache_stats;
|
||||
}
|
||||
|
||||
void disk_io_thread::set_cache_size(int s)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
TORRENT_ASSERT(s >= 0);
|
||||
m_cache_size = s;
|
||||
}
|
||||
|
||||
void disk_io_thread::set_cache_expiry(int ex)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
TORRENT_ASSERT(ex > 0);
|
||||
m_cache_expiry = ex;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ namespace libtorrent
|
|||
// aborts read operations
|
||||
void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_queue_mutex);
|
||||
// read jobs are aborted, write and move jobs are syncronized
|
||||
for (std::list<disk_io_job>::iterator i = m_jobs.begin();
|
||||
i != m_jobs.end();)
|
||||
|
@ -200,10 +200,12 @@ namespace libtorrent
|
|||
return cache.end();
|
||||
}
|
||||
|
||||
void disk_io_thread::flush_expired_pieces(mutex_t::scoped_lock& l)
|
||||
void disk_io_thread::flush_expired_pieces()
|
||||
{
|
||||
ptime now = time_now();
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
|
||||
INVARIANT_CHECK;
|
||||
for (;;)
|
||||
{
|
||||
|
@ -226,15 +228,12 @@ namespace libtorrent
|
|||
for (int i = 0; i < blocks_in_piece; ++i)
|
||||
{
|
||||
if (p.blocks[i] == 0) continue;
|
||||
free_buffer(p.blocks[i], l);
|
||||
free_buffer(p.blocks[i]);
|
||||
p.blocks[i] = 0;
|
||||
--p.num_blocks;
|
||||
--m_cache_stats.cache_size;
|
||||
--m_cache_stats.read_cache_size;
|
||||
}
|
||||
l.unlock();
|
||||
p.storage = 0;
|
||||
l.lock();
|
||||
}
|
||||
|
||||
bool disk_io_thread::clear_oldest_read_piece(
|
||||
|
@ -330,7 +329,7 @@ namespace libtorrent
|
|||
offset += m_block_size;
|
||||
buffer_size += block_size;
|
||||
}
|
||||
free_buffer(p.blocks[i], l);
|
||||
free_buffer(p.blocks[i]);
|
||||
p.blocks[i] = 0;
|
||||
TORRENT_ASSERT(p.num_blocks > 0);
|
||||
--p.num_blocks;
|
||||
|
@ -343,9 +342,6 @@ namespace libtorrent
|
|||
for (int i = 0; i < blocks_in_piece; ++i)
|
||||
TORRENT_ASSERT(p.blocks[i] == 0);
|
||||
#endif
|
||||
l.unlock();
|
||||
p.storage = 0;
|
||||
l.lock();
|
||||
}
|
||||
|
||||
void disk_io_thread::cache_block(disk_io_job& j, mutex_t::scoped_lock& l)
|
||||
|
@ -368,9 +364,6 @@ namespace libtorrent
|
|||
p.blocks[block] = j.buffer;
|
||||
++m_cache_stats.cache_size;
|
||||
m_pieces.push_back(p);
|
||||
#ifndef NDEBUG
|
||||
p.storage = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// fills a piece with data from disk, returns the total number of bytes
|
||||
|
@ -388,7 +381,7 @@ namespace libtorrent
|
|||
// stop allocating and don't read more than
|
||||
// what we've allocated now
|
||||
if (p.blocks[i]) break;
|
||||
p.blocks[i] = allocate_buffer(l);
|
||||
p.blocks[i] = allocate_buffer();
|
||||
|
||||
// the allocation failed, break
|
||||
if (p.blocks[i] == 0) break;
|
||||
|
@ -484,9 +477,6 @@ namespace libtorrent
|
|||
else
|
||||
m_read_pieces.push_back(p);
|
||||
|
||||
#ifndef NDEBUG
|
||||
p.storage = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -509,7 +499,7 @@ namespace libtorrent
|
|||
if (p.blocks[k])
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
TORRENT_ASSERT(m_pool.is_from(p.blocks[k]));
|
||||
TORRENT_ASSERT(is_disk_buffer(p.blocks[k]));
|
||||
#endif
|
||||
++blocks;
|
||||
}
|
||||
|
@ -533,7 +523,7 @@ namespace libtorrent
|
|||
if (p.blocks[k])
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
TORRENT_ASSERT(m_pool.is_from(p.blocks[k]));
|
||||
TORRENT_ASSERT(is_disk_buffer(p.blocks[k]));
|
||||
#endif
|
||||
++blocks;
|
||||
}
|
||||
|
@ -551,10 +541,11 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
int disk_io_thread::try_read_from_cache(disk_io_job const& j, mutex_t::scoped_lock& l)
|
||||
int disk_io_thread::try_read_from_cache(disk_io_job const& j)
|
||||
{
|
||||
TORRENT_ASSERT(j.buffer);
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
if (!m_use_read_cache) return -2;
|
||||
|
||||
cache_t::iterator p
|
||||
|
@ -624,7 +615,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(!j.callback);
|
||||
TORRENT_ASSERT(j.storage);
|
||||
TORRENT_ASSERT(j.buffer_size <= m_block_size);
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_queue_mutex);
|
||||
#ifndef NDEBUG
|
||||
if (j.action == disk_io_job::write)
|
||||
{
|
||||
|
@ -696,7 +687,7 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
return true;
|
||||
#else
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_pool_mutex);
|
||||
return m_pool.is_from(buffer);
|
||||
#endif
|
||||
}
|
||||
|
@ -704,18 +695,7 @@ namespace libtorrent
|
|||
|
||||
char* disk_io_thread::allocate_buffer()
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
return allocate_buffer(l);
|
||||
}
|
||||
|
||||
void disk_io_thread::free_buffer(char* buf)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
free_buffer(buf, l);
|
||||
}
|
||||
|
||||
char* disk_io_thread::allocate_buffer(mutex_t::scoped_lock& l)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_pool_mutex);
|
||||
#ifdef TORRENT_STATS
|
||||
++m_allocations;
|
||||
#endif
|
||||
|
@ -726,8 +706,9 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
void disk_io_thread::free_buffer(char* buf, mutex_t::scoped_lock& l)
|
||||
void disk_io_thread::free_buffer(char* buf)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_pool_mutex);
|
||||
#ifdef TORRENT_STATS
|
||||
--m_allocations;
|
||||
#endif
|
||||
|
@ -745,12 +726,15 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " idle" << std::endl;
|
||||
#endif
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock jl(m_queue_mutex);
|
||||
|
||||
while (m_jobs.empty() && !m_abort)
|
||||
m_signal.wait(l);
|
||||
m_signal.wait(jl);
|
||||
if (m_abort && m_jobs.empty())
|
||||
{
|
||||
jl.unlock();
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
// flush all disk caches
|
||||
for (cache_t::iterator i = m_pieces.begin()
|
||||
, end(m_pieces.end()); i != end; ++i)
|
||||
|
@ -758,10 +742,8 @@ namespace libtorrent
|
|||
for (cache_t::iterator i = m_read_pieces.begin()
|
||||
, end(m_read_pieces.end()); i != end; ++i)
|
||||
free_piece(*i, l);
|
||||
l.unlock();
|
||||
m_pieces.clear();
|
||||
m_read_pieces.clear();
|
||||
l.lock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -777,40 +759,14 @@ namespace libtorrent
|
|||
|
||||
disk_io_job j = m_jobs.front();
|
||||
m_jobs.pop_front();
|
||||
|
||||
if (j.action == disk_io_job::abort_thread)
|
||||
{
|
||||
m_abort = true;
|
||||
|
||||
for (std::list<disk_io_job>::iterator i = m_jobs.begin();
|
||||
i != m_jobs.end();)
|
||||
{
|
||||
if (i->action == disk_io_job::read)
|
||||
{
|
||||
if (i->callback) m_ios.post(bind(i->callback, -1, *i));
|
||||
m_jobs.erase(i++);
|
||||
continue;
|
||||
}
|
||||
if (i->action == disk_io_job::check_files)
|
||||
{
|
||||
if (i->callback) m_ios.post(bind(i->callback
|
||||
, piece_manager::disk_check_aborted, *i));
|
||||
m_jobs.erase(i++);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
m_queue_buffer_size -= j.buffer_size;
|
||||
jl.unlock();
|
||||
|
||||
flush_expired_pieces(l);
|
||||
l.unlock();
|
||||
flush_expired_pieces();
|
||||
|
||||
int ret = 0;
|
||||
|
||||
TORRENT_ASSERT(j.storage);
|
||||
TORRENT_ASSERT(j.storage || j.action == disk_io_job::abort_thread);
|
||||
#ifdef TORRENT_DISK_STATS
|
||||
ptime start = time_now();
|
||||
#endif
|
||||
|
@ -820,6 +776,31 @@ namespace libtorrent
|
|||
|
||||
switch (j.action)
|
||||
{
|
||||
case disk_io_job::abort_thread:
|
||||
{
|
||||
mutex_t::scoped_lock jl(m_queue_mutex);
|
||||
m_abort = true;
|
||||
|
||||
for (std::list<disk_io_job>::iterator i = m_jobs.begin();
|
||||
i != m_jobs.end();)
|
||||
{
|
||||
if (i->action == disk_io_job::read)
|
||||
{
|
||||
if (i->callback) m_ios.post(bind(i->callback, -1, *i));
|
||||
m_jobs.erase(i++);
|
||||
continue;
|
||||
}
|
||||
if (i->action == disk_io_job::check_files)
|
||||
{
|
||||
if (i->callback) m_ios.post(bind(i->callback
|
||||
, piece_manager::disk_check_aborted, *i));
|
||||
m_jobs.erase(i++);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case disk_io_job::read:
|
||||
{
|
||||
std::string const& error_string = j.storage->error();
|
||||
|
@ -837,7 +818,6 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " read " << j.buffer_size << std::endl;
|
||||
#endif
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_ASSERT(j.buffer == 0);
|
||||
j.buffer = allocate_buffer();
|
||||
|
@ -850,7 +830,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
disk_buffer_holder read_holder(*this, j.buffer);
|
||||
ret = try_read_from_cache(j, l);
|
||||
ret = try_read_from_cache(j);
|
||||
|
||||
// -2 means there's no space in the read cache
|
||||
// or that the read cache is disabled
|
||||
|
@ -864,7 +844,6 @@ namespace libtorrent
|
|||
}
|
||||
else if (ret == -2)
|
||||
{
|
||||
l.unlock();
|
||||
ret = j.storage->read_impl(j.buffer, j.piece, j.offset
|
||||
, j.buffer_size);
|
||||
if (ret < 0)
|
||||
|
@ -874,7 +853,6 @@ namespace libtorrent
|
|||
j.storage->clear_error();
|
||||
break;
|
||||
}
|
||||
l.lock();
|
||||
++m_cache_stats.blocks_read;
|
||||
}
|
||||
read_holder.release();
|
||||
|
@ -897,7 +875,7 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " write " << j.buffer_size << std::endl;
|
||||
#endif
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
INVARIANT_CHECK;
|
||||
cache_t::iterator p
|
||||
= find_cached_piece(m_pieces, j, l);
|
||||
|
@ -934,8 +912,7 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " hash" << std::endl;
|
||||
#endif
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
INVARIANT_CHECK;
|
||||
|
||||
cache_t::iterator i
|
||||
|
@ -993,8 +970,8 @@ namespace libtorrent
|
|||
m_log << log_time() << " release" << std::endl;
|
||||
#endif
|
||||
TORRENT_ASSERT(j.buffer == 0);
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
INVARIANT_CHECK;
|
||||
|
||||
for (cache_t::iterator i = m_pieces.begin(); i != m_pieces.end();)
|
||||
|
@ -1009,10 +986,13 @@ namespace libtorrent
|
|||
++i;
|
||||
}
|
||||
}
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
m_pool.release_memory();
|
||||
#endif
|
||||
l.unlock();
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
{
|
||||
mutex_t::scoped_lock l(m_pool_mutex);
|
||||
m_pool.release_memory();
|
||||
}
|
||||
#endif
|
||||
ret = j.storage->release_files_impl();
|
||||
if (ret != 0)
|
||||
{
|
||||
|
@ -1028,8 +1008,8 @@ namespace libtorrent
|
|||
m_log << log_time() << " delete" << std::endl;
|
||||
#endif
|
||||
TORRENT_ASSERT(j.buffer == 0);
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
|
||||
mutex_t::scoped_lock l(m_piece_mutex);
|
||||
INVARIANT_CHECK;
|
||||
|
||||
cache_t::iterator i = std::remove_if(
|
||||
|
@ -1042,15 +1022,18 @@ namespace libtorrent
|
|||
for (int j = 0; j < blocks_in_piece; ++j)
|
||||
{
|
||||
if (k->blocks[j] == 0) continue;
|
||||
free_buffer(k->blocks[j], l);
|
||||
free_buffer(k->blocks[j]);
|
||||
k->blocks[j] = 0;
|
||||
}
|
||||
}
|
||||
m_pieces.erase(i, m_pieces.end());
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
m_pool.release_memory();
|
||||
#endif
|
||||
l.unlock();
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
{
|
||||
mutex_t::scoped_lock l(m_pool_mutex);
|
||||
m_pool.release_memory();
|
||||
}
|
||||
#endif
|
||||
ret = j.storage->delete_files_impl();
|
||||
if (ret != 0)
|
||||
{
|
||||
|
@ -1094,9 +1077,7 @@ namespace libtorrent
|
|||
// if the check is not done, add it at the end of the job queue
|
||||
if (ret == piece_manager::need_full_check)
|
||||
{
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
m_jobs.push_back(j);
|
||||
m_jobs.back().callback.swap(handler);
|
||||
add_job(j, handler);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -37,9 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
// non-standard header, is_sorted()
|
||||
//#include <algo.h>
|
||||
|
||||
#include "libtorrent/piece_picker.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
|
@ -255,6 +252,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_num_have >= 0);
|
||||
TORRENT_ASSERT(m_num_have_filtered >= 0);
|
||||
TORRENT_ASSERT(m_num_filtered >= 0);
|
||||
TORRENT_ASSERT(m_seeds >= 0);
|
||||
|
||||
if (!m_downloads.empty())
|
||||
{
|
||||
|
@ -446,6 +444,7 @@ namespace libtorrent
|
|||
|
||||
float piece_picker::distributed_copies() const
|
||||
{
|
||||
TORRENT_ASSERT(m_seeds >= 0);
|
||||
const float num_pieces = static_cast<float>(m_piece_map.size());
|
||||
|
||||
int min_availability = piece_pos::max_peer_count;
|
||||
|
@ -768,8 +767,12 @@ namespace libtorrent
|
|||
int new_priority = p.priority(this);
|
||||
|
||||
if (new_priority == prev_priority) return;
|
||||
if (m_sequential_download >= 0) return;
|
||||
if (m_dirty) return;
|
||||
if (m_sequential_download >= 0)
|
||||
{
|
||||
m_dirty = true;
|
||||
return;
|
||||
}
|
||||
if (prev_priority == -1)
|
||||
{
|
||||
add(index);
|
||||
|
@ -784,7 +787,6 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
++m_seeds;
|
||||
if (m_sequential_download >= 0) return;
|
||||
if (m_seeds == 1)
|
||||
{
|
||||
// when m_seeds is increased from 0 to 1
|
||||
|
@ -798,12 +800,6 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
|
||||
if (m_sequential_download >= 0)
|
||||
{
|
||||
--m_seeds;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_seeds > 0)
|
||||
{
|
||||
--m_seeds;
|
||||
|
@ -816,6 +812,7 @@ namespace libtorrent
|
|||
}
|
||||
return;
|
||||
}
|
||||
TORRENT_ASSERT(m_seeds == 0);
|
||||
|
||||
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
|
||||
, end(m_piece_map.end()); i != end; ++i)
|
||||
|
@ -835,6 +832,7 @@ namespace libtorrent
|
|||
if (m_sequential_download >= 0)
|
||||
{
|
||||
++p.peer_count;
|
||||
m_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -856,7 +854,9 @@ namespace libtorrent
|
|||
piece_pos& p = m_piece_map[index];
|
||||
if (m_sequential_download >= 0)
|
||||
{
|
||||
TORRENT_ASSERT(p.peer_count > 0);
|
||||
--p.peer_count;
|
||||
m_dirty = true;
|
||||
return;
|
||||
}
|
||||
int prev_priority = p.priority(this);
|
||||
|
@ -1756,6 +1756,7 @@ namespace libtorrent
|
|||
|
||||
void piece_picker::get_availability(std::vector<int>& avail) const
|
||||
{
|
||||
TORRENT_ASSERT(m_seeds >= 0);
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
|
||||
avail.resize(m_piece_map.size());
|
||||
|
|
|
@ -524,6 +524,12 @@ namespace aux {
|
|||
m_disk_thread.set_cache_size(s.cache_size);
|
||||
if (m_settings.cache_expiry != s.cache_expiry)
|
||||
m_disk_thread.set_cache_size(s.cache_expiry);
|
||||
// if queuing settings were changed, recalculate
|
||||
// queued torrents sooner
|
||||
if ((m_settings.active_downloads != s.active_downloads
|
||||
|| m_settings.active_seeds != s.active_seeds)
|
||||
&& m_auto_manage_time_scaler > 2)
|
||||
m_auto_manage_time_scaler = 2;
|
||||
m_settings = s;
|
||||
if (m_settings.connection_speed <= 0) m_settings.connection_speed = 200;
|
||||
|
||||
|
@ -1324,7 +1330,6 @@ namespace aux {
|
|||
if (t->is_finished())
|
||||
{
|
||||
--num_seeds;
|
||||
--num_downloaders;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1368,9 +1373,8 @@ namespace aux {
|
|||
, end(seeds.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = *i;
|
||||
if (num_downloaders > 0 && num_seeds > 0)
|
||||
if (num_seeds > 0)
|
||||
{
|
||||
--num_downloaders;
|
||||
--num_seeds;
|
||||
if (t->is_paused()) t->resume();
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ namespace libtorrent
|
|||
template <class Path>
|
||||
void recursive_copy(Path const& old_path, Path const& new_path, std::string& error)
|
||||
{
|
||||
using boost::filesystem::directory_iterator;
|
||||
using boost::filesystem::basic_directory_iterator;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
|
@ -263,7 +263,7 @@ namespace libtorrent
|
|||
if (is_directory(old_path))
|
||||
{
|
||||
create_directory(new_path);
|
||||
for (directory_iterator i(old_path), end; i != end; ++i)
|
||||
for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i)
|
||||
{
|
||||
recursive_copy(i->path(), new_path / i->leaf(), error);
|
||||
if (!error.empty()) return;
|
||||
|
@ -281,13 +281,13 @@ namespace libtorrent
|
|||
template <class Path>
|
||||
void recursive_remove(Path const& old_path)
|
||||
{
|
||||
using boost::filesystem::directory_iterator;
|
||||
using boost::filesystem::basic_directory_iterator;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
if (is_directory(old_path))
|
||||
{
|
||||
for (directory_iterator i(old_path), end; i != end; ++i)
|
||||
for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i)
|
||||
recursive_remove(i->path());
|
||||
remove(old_path);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue