mirror of
https://github.com/codex-storage/deluge.git
synced 2025-01-13 13:05:37 +00:00
[#1032] [Core] Force a torrent error if resume data is rejected
* Add two new methods, force_error_state and clear_forced_error_state. * Force error state upon rejected resume data. * Keep original resume data in forced_error state.
This commit is contained in:
parent
34e92b9f12
commit
0ab7ebd017
@ -98,6 +98,14 @@ class TorrentOptions(dict):
|
||||
self["file_priorities"] = []
|
||||
self["mapped_files"] = {}
|
||||
|
||||
|
||||
class TorrentError(object):
|
||||
def __init__(self, error_message, was_paused=False, restart_to_resume=False):
|
||||
self.error_message = error_message
|
||||
self.was_paused = was_paused
|
||||
self.restart_to_resume = restart_to_resume
|
||||
|
||||
|
||||
class Torrent(object):
|
||||
"""Torrent holds information about torrents added to the libtorrent session.
|
||||
"""
|
||||
@ -188,11 +196,14 @@ class Torrent(object):
|
||||
# Various torrent options
|
||||
self.handle.resolve_countries(True)
|
||||
|
||||
self.set_options(self.options)
|
||||
# Details of torrent forced into error state (i.e. not by libtorrent).
|
||||
self.forced_error = None
|
||||
|
||||
# Status message holds error info about the torrent
|
||||
self.statusmsg = "OK"
|
||||
|
||||
self.set_options(self.options)
|
||||
|
||||
# The torrents state
|
||||
self.update_state()
|
||||
|
||||
@ -391,7 +402,11 @@ class Torrent(object):
|
||||
|
||||
# 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 self.forced_error:
|
||||
self.state = "Error"
|
||||
log.debug("Torrent Error state message: %s", self.forced_error.error_message)
|
||||
self.set_status_message("Error: " + self.forced_error.error_message)
|
||||
elif len(self.handle.status().error) > 0:
|
||||
# This is an error'd torrent
|
||||
self.state = "Error"
|
||||
self.set_status_message(self.handle.status().error)
|
||||
@ -427,6 +442,37 @@ class Torrent(object):
|
||||
def set_status_message(self, message):
|
||||
self.statusmsg = message
|
||||
|
||||
def force_error_state(self, message, restart_to_resume=True):
|
||||
"""Forces the torrent into an error state.
|
||||
|
||||
For setting an error state not covered by libtorrent.
|
||||
|
||||
Args:
|
||||
message (str): The error status message.
|
||||
restart_to_resume (bool, optional): Prevent resuming clearing the error, only restarting
|
||||
session can resume.
|
||||
"""
|
||||
status = self.handle.status()
|
||||
self.handle.auto_managed(False)
|
||||
self.forced_error = TorrentError(message, status.paused, restart_to_resume)
|
||||
if not status.paused:
|
||||
self.handle.pause()
|
||||
self.update_state()
|
||||
|
||||
def clear_forced_error_state(self, update_state=True):
|
||||
if not self.forced_error:
|
||||
return
|
||||
|
||||
if self.forced_error.restart_to_resume:
|
||||
log.error("Restart deluge to clear this torrent error")
|
||||
|
||||
if not self.forced_error.was_paused and self.options["auto_managed"]:
|
||||
self.handle.auto_managed(True)
|
||||
self.forced_error = None
|
||||
self.set_status_message("OK")
|
||||
if update_state:
|
||||
self.update_state()
|
||||
|
||||
def get_eta(self):
|
||||
"""Returns the ETA in seconds for this torrent"""
|
||||
if self.status == None:
|
||||
@ -782,6 +828,8 @@ class Torrent(object):
|
||||
|
||||
def pause(self):
|
||||
"""Pause this torrent"""
|
||||
if self.state == "Error":
|
||||
return False
|
||||
# Turn off auto-management so the torrent will not be unpaused by lt queueing
|
||||
self.handle.auto_managed(False)
|
||||
if self.handle.is_paused():
|
||||
@ -806,6 +854,8 @@ class Torrent(object):
|
||||
if self.handle.is_paused() and self.handle.is_auto_managed():
|
||||
log.debug("Torrent is being auto-managed, cannot resume!")
|
||||
return
|
||||
elif self.forced_error and self.forced_error.was_paused:
|
||||
log.debug("Skip resuming Error state torrent that was originally paused.")
|
||||
else:
|
||||
# Reset the status message just in case of resuming an Error'd torrent
|
||||
self.set_status_message("OK")
|
||||
@ -829,6 +879,9 @@ class Torrent(object):
|
||||
|
||||
return True
|
||||
|
||||
if self.forced_error and not self.forced_error.restart_to_resume:
|
||||
self.clear_forced_error_state()
|
||||
|
||||
def connect_peer(self, ip, port):
|
||||
"""adds manual peer"""
|
||||
try:
|
||||
@ -874,8 +927,12 @@ class Torrent(object):
|
||||
def save_resume_data(self):
|
||||
"""Signals libtorrent to build resume data for this torrent, it gets
|
||||
returned in a libtorrent alert"""
|
||||
self.handle.save_resume_data()
|
||||
self.waiting_on_resume_data = True
|
||||
# Don't generate fastresume data if torrent is in a Deluge Error state.
|
||||
if self.forced_error:
|
||||
log.debug("Skipped creating resume_data while in Error state")
|
||||
else:
|
||||
self.handle.save_resume_data()
|
||||
self.waiting_on_resume_data = True
|
||||
|
||||
def on_metadata_received(self):
|
||||
if self.options["prioritize_first_last_pieces"]:
|
||||
@ -933,7 +990,11 @@ class Torrent(object):
|
||||
def force_recheck(self):
|
||||
"""Forces a recheck of the torrents pieces"""
|
||||
self.forcing_recheck = True
|
||||
self.forcing_recheck_paused = self.handle.is_paused()
|
||||
if self.forced_error:
|
||||
self.forcing_recheck_paused = self.forced_error.was_paused
|
||||
self.clear_forced_error_state(update_state=False)
|
||||
else:
|
||||
self.forcing_recheck_paused = self.handle.is_paused()
|
||||
# Store trackers for paused torrents to prevent unwanted announce before pausing again.
|
||||
if self.forcing_recheck_paused:
|
||||
self.set_trackers(None, reannounce=False)
|
||||
|
@ -205,6 +205,10 @@ class TorrentManager(component.Component):
|
||||
self.alerts.register_handler("fastresume_rejected_alert",
|
||||
self.on_alert_fastresume_rejected)
|
||||
|
||||
# Define timers
|
||||
self.save_state_timer = LoopingCall(self.save_state)
|
||||
self.save_resume_data_timer = LoopingCall(self.save_resume_data)
|
||||
|
||||
def start(self):
|
||||
# Get the pluginmanager reference
|
||||
self.plugins = component.get("CorePluginManager")
|
||||
@ -212,14 +216,12 @@ class TorrentManager(component.Component):
|
||||
# Run the old state upgrader before loading state
|
||||
deluge.core.oldstateupgrader.OldStateUpgrader()
|
||||
|
||||
# Try to load the state from file
|
||||
# Try to load the state from file.
|
||||
self.load_state()
|
||||
|
||||
# Save the state every 5 minutes
|
||||
self.save_state_timer = LoopingCall(self.save_state)
|
||||
# Save the state and resume data every ~3 minutes.
|
||||
self.save_state_timer.start(200, False)
|
||||
self.save_resume_data_timer = LoopingCall(self.save_resume_data)
|
||||
self.save_resume_data_timer.start(190)
|
||||
self.save_resume_data_timer.start(190, False)
|
||||
|
||||
def stop(self):
|
||||
# Stop timers
|
||||
@ -682,6 +684,8 @@ class TorrentManager(component.Component):
|
||||
for torrent in self.torrents.values():
|
||||
if self.session.is_paused():
|
||||
paused = torrent.handle.is_paused()
|
||||
elif torrent.forced_error:
|
||||
paused = torrent.forced_error.was_paused
|
||||
elif torrent.state == "Paused":
|
||||
paused = True
|
||||
else:
|
||||
@ -1147,9 +1151,7 @@ class TorrentManager(component.Component):
|
||||
else:
|
||||
error_msg = "Problem with resume data: %s" % alert_msg.split(":", 1)[1].strip()
|
||||
|
||||
torrent.set_status_message("Error: " + error_msg)
|
||||
torrent.pause()
|
||||
torrent.update_state()
|
||||
torrent.force_error_state(error_msg, restart_to_resume=True)
|
||||
|
||||
def on_alert_file_renamed(self, alert):
|
||||
log.debug("on_alert_file_renamed")
|
||||
|
Loading…
x
Reference in New Issue
Block a user