mirror of
https://github.com/codex-storage/deluge.git
synced 2025-01-27 11:45:44 +00:00
[#2250] [Core] [GTKUI] Added method remove_torrents to core
Removing multiple torrents with remove_torrents will be faster than calling remove_torrent for each torrent, as the state file will be written only once, after all the torrents are deleted.
This commit is contained in:
parent
2aaae7c6a1
commit
08363f28dd
@ -326,22 +326,48 @@ class Core(component.Component):
|
||||
|
||||
@export
|
||||
def remove_torrent(self, torrent_id, remove_data):
|
||||
"""
|
||||
Removes a torrent from the session.
|
||||
"""Removes a single torrent from the session.
|
||||
|
||||
:param torrent_id: the torrent_id of the torrent to remove
|
||||
:type torrent_id: string
|
||||
:param remove_data: if True, remove the data associated with this torrent
|
||||
:type remove_data: boolean
|
||||
:returns: True if removed successfully
|
||||
:rtype: bool
|
||||
Args:
|
||||
torrent_id (str): The torrent ID to remove.
|
||||
remove_data (bool): If True, also remove the downloaded data.
|
||||
|
||||
:raises InvalidTorrentError: if the torrent_id does not exist in the session
|
||||
Returns:
|
||||
bool: True if removed successfully.
|
||||
|
||||
Raises:
|
||||
InvalidTorrentError: If the torrent ID does not exist in the session.
|
||||
|
||||
"""
|
||||
log.debug("Removing torrent %s from the core.", torrent_id)
|
||||
return self.torrentmanager.remove(torrent_id, remove_data)
|
||||
|
||||
@export
|
||||
def remove_torrents(self, torrent_ids, remove_data):
|
||||
"""Remove multiple torrents from the session.
|
||||
|
||||
Args:
|
||||
torrent_ids (list): The torrent IDs to remove.
|
||||
remove_data (bool, optional): If True, also remove the downloaded data.
|
||||
|
||||
Returns:
|
||||
list: a list containing all the errors, empty list if no errors occured
|
||||
|
||||
"""
|
||||
log.info("Removing %d torrents from core.", len(torrent_ids))
|
||||
|
||||
def do_remove_torrents():
|
||||
errors = []
|
||||
for torrent_id in torrent_ids:
|
||||
try:
|
||||
self.torrentmanager.remove(torrent_id, remove_data=remove_data, save_state=False)
|
||||
except InvalidTorrentError, ite:
|
||||
errors.append((torrent_id, ite))
|
||||
# Save the session state
|
||||
self.torrentmanager.save_state()
|
||||
return errors
|
||||
return task.deferLater(reactor, 0, do_remove_torrents)
|
||||
|
||||
@export
|
||||
def get_session_status(self, keys):
|
||||
"""
|
||||
|
@ -523,12 +523,13 @@ class TorrentManager(component.Component):
|
||||
from_state and "loaded" or "added")
|
||||
return torrent.torrent_id
|
||||
|
||||
def remove(self, torrent_id, remove_data=False):
|
||||
"""Remove specified torrent from the session.
|
||||
def remove(self, torrent_id, remove_data=False, save_state=True):
|
||||
"""Remove a torrent from the session.
|
||||
|
||||
Args:
|
||||
torrent_id (str): The torrent to remove.
|
||||
torrent_id (str): The torrent ID to remove.
|
||||
remove_data (bool, optional): If True, remove the downloaded data, defaults to False.
|
||||
save_state (bool, optional): If True, save the session state after removal, defaults to True.
|
||||
|
||||
Returns:
|
||||
bool: True if removed successfully, False if not.
|
||||
@ -538,16 +539,16 @@ class TorrentManager(component.Component):
|
||||
|
||||
"""
|
||||
try:
|
||||
torrent_name = self.torrents[torrent_id].get_status(["name"])["name"]
|
||||
torrent = self.torrents[torrent_id]
|
||||
except KeyError:
|
||||
raise InvalidTorrentError("torrent_id not in session")
|
||||
raise InvalidTorrentError("torrent_id '%s' not in session." % torrent_id)
|
||||
|
||||
# Emit the signal to the clients
|
||||
component.get("EventManager").emit(PreTorrentRemovedEvent(torrent_id))
|
||||
|
||||
try:
|
||||
self.session.remove_torrent(self.torrents[torrent_id].handle, 1 if remove_data else 0)
|
||||
except (RuntimeError, KeyError) as ex:
|
||||
self.session.remove_torrent(torrent.handle, 1 if remove_data else 0)
|
||||
except RuntimeError as ex:
|
||||
log.warning("Error removing torrent: %s", ex)
|
||||
return False
|
||||
|
||||
@ -555,10 +556,11 @@ class TorrentManager(component.Component):
|
||||
self.resume_data.pop(torrent_id, None)
|
||||
|
||||
# Remove the .torrent file in the state
|
||||
self.torrents[torrent_id].delete_torrentfile()
|
||||
torrent.delete_torrentfile()
|
||||
|
||||
# Remove the torrent file from the user specified directory
|
||||
filename = self.torrents[torrent_id].filename
|
||||
torrent_name = torrent.get_status(["name"])["name"]
|
||||
filename = torrent.filename
|
||||
if self.config["copy_torrent_file"] and self.config["del_copy_torrent_file"] and filename:
|
||||
users_torrent_file = os.path.join(self.config["torrentfiles_location"], filename)
|
||||
log.info("Delete user's torrent file: %s", users_torrent_file)
|
||||
@ -568,25 +570,22 @@ class TorrentManager(component.Component):
|
||||
log.warning("Unable to remove copy torrent file: %s", ex)
|
||||
|
||||
# Remove from set if it wasn't finished
|
||||
if not self.torrents[torrent_id].is_finished:
|
||||
if not torrent.is_finished:
|
||||
try:
|
||||
self.queued_torrents.remove(torrent_id)
|
||||
except KeyError:
|
||||
log.debug("%s isn't in queued torrents set?", torrent_id)
|
||||
raise InvalidTorrentError("%s isn't in queued torrents set?" % torrent_id)
|
||||
|
||||
# Remove the torrent from deluge's session
|
||||
try:
|
||||
del self.torrents[torrent_id]
|
||||
except (KeyError, ValueError):
|
||||
return False
|
||||
del self.torrents[torrent_id]
|
||||
|
||||
# Save the session state
|
||||
self.save_state()
|
||||
if save_state:
|
||||
self.save_state()
|
||||
|
||||
# Emit the signal to the clients
|
||||
component.get("EventManager").emit(TorrentRemovedEvent(torrent_id))
|
||||
log.info("Torrent %s removed by user: %s", torrent_name,
|
||||
component.get("RPCServer").get_session_user())
|
||||
log.info("Torrent %s removed by user: %s", torrent_name, component.get("RPCServer").get_session_user())
|
||||
return True
|
||||
|
||||
def load_state(self):
|
||||
|
@ -1,3 +1,4 @@
|
||||
import base64
|
||||
import os
|
||||
from hashlib import sha1 as sha
|
||||
|
||||
@ -11,9 +12,10 @@ from twisted.web.server import Site
|
||||
from twisted.web.static import File
|
||||
|
||||
import deluge.component as component
|
||||
import deluge.error
|
||||
import deluge.core.torrent
|
||||
from deluge.core.core import Core
|
||||
from deluge.core.rpcserver import RPCServer
|
||||
from deluge.error import InvalidTorrentError
|
||||
from deluge.ui.web.common import compress
|
||||
|
||||
from . import common
|
||||
@ -104,7 +106,6 @@ class CoreTestCase(BaseTestCase):
|
||||
def test_add_torrent_file(self):
|
||||
options = {}
|
||||
filename = os.path.join(os.path.dirname(__file__), "test.torrent")
|
||||
import base64
|
||||
torrent_id = self.core.add_torrent_file(filename, base64.encodestring(open(filename).read()), options)
|
||||
|
||||
# Get the info hash from the test.torrent
|
||||
@ -168,16 +169,53 @@ class CoreTestCase(BaseTestCase):
|
||||
def test_remove_torrent(self):
|
||||
options = {}
|
||||
filename = os.path.join(os.path.dirname(__file__), "test.torrent")
|
||||
import base64
|
||||
torrent_id = self.core.add_torrent_file(filename, base64.encodestring(open(filename).read()), options)
|
||||
|
||||
self.assertRaises(deluge.error.InvalidTorrentError, self.core.remove_torrent, "torrentidthatdoesntexist", True)
|
||||
|
||||
ret = self.core.remove_torrent(torrent_id, True)
|
||||
|
||||
self.assertTrue(ret)
|
||||
removed = self.core.remove_torrent(torrent_id, True)
|
||||
self.assertTrue(removed)
|
||||
self.assertEquals(len(self.core.get_session_state()), 0)
|
||||
|
||||
def test_remove_torrent_invalid(self):
|
||||
d = self.core.remove_torrents(["torrentidthatdoesntexist"], True)
|
||||
|
||||
def test_true(val):
|
||||
self.assertTrue(val[0][0] == "torrentidthatdoesntexist")
|
||||
|
||||
self.assertTrue(type(val[0][1]) == InvalidTorrentError)
|
||||
d.addCallback(test_true)
|
||||
return d
|
||||
|
||||
def test_remove_torrents(self):
|
||||
options = {}
|
||||
filename = os.path.join(os.path.dirname(__file__), "test.torrent")
|
||||
torrent_id = self.core.add_torrent_file(filename, base64.encodestring(open(filename).read()), options)
|
||||
filename2 = os.path.join(os.path.dirname(__file__), "unicode_filenames.torrent")
|
||||
torrent_id2 = self.core.add_torrent_file(filename2, base64.encodestring(open(filename2).read()), options)
|
||||
d = self.core.remove_torrents([torrent_id, torrent_id2], True)
|
||||
|
||||
def test_ret(val):
|
||||
self.assertTrue(val == [])
|
||||
d.addCallback(test_ret)
|
||||
|
||||
def test_session_state(val):
|
||||
self.assertEquals(len(self.core.get_session_state()), 0)
|
||||
d.addCallback(test_session_state)
|
||||
return d
|
||||
|
||||
def test_remove_torrents_invalid(self):
|
||||
options = {}
|
||||
filename = os.path.join(os.path.dirname(__file__), "test.torrent")
|
||||
torrent_id = self.core.add_torrent_file(filename, base64.encodestring(open(filename).read()), options)
|
||||
d = self.core.remove_torrents(["invalidid1", "invalidid2", torrent_id], False)
|
||||
|
||||
def test_ret(val):
|
||||
self.assertTrue(len(val) == 2)
|
||||
self.assertTrue(val[0][0] == "invalidid1")
|
||||
self.assertTrue(type(val[0][1]) == InvalidTorrentError)
|
||||
self.assertTrue(val[1][0] == "invalidid2")
|
||||
self.assertTrue(type(val[1][1]) == InvalidTorrentError)
|
||||
d.addCallback(test_ret)
|
||||
return d
|
||||
|
||||
def test_get_session_status(self):
|
||||
status = self.core.get_session_status(["upload_rate", "download_rate"])
|
||||
self.assertEquals(type(status), dict)
|
||||
|
44
deluge/tests/test_torrentmanager.py
Normal file
44
deluge/tests/test_torrentmanager.py
Normal file
@ -0,0 +1,44 @@
|
||||
import base64
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from twisted.trial import unittest
|
||||
|
||||
import common
|
||||
from deluge import component
|
||||
from deluge.core.core import Core
|
||||
from deluge.core.rpcserver import RPCServer
|
||||
from deluge.error import InvalidTorrentError
|
||||
|
||||
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
||||
warnings.resetwarnings()
|
||||
|
||||
|
||||
class TorrentmanagerTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self): # NOQA
|
||||
common.set_tmp_config_dir()
|
||||
self.rpcserver = RPCServer(listen=False)
|
||||
self.core = Core()
|
||||
self.torrentManager = self.core.torrentmanager
|
||||
return component.start()
|
||||
|
||||
def tearDown(self): # NOQA
|
||||
def on_shutdown(result):
|
||||
component._ComponentRegistry.components = {}
|
||||
del self.rpcserver
|
||||
del self.core
|
||||
del self.torrentManager
|
||||
return component.shutdown().addCallback(on_shutdown)
|
||||
|
||||
def test_remove_torrent(self):
|
||||
filename = os.path.join(os.path.dirname(__file__), "test.torrent")
|
||||
torrent_id = self.core.add_torrent_file(filename, base64.encodestring(open(filename).read()), {})
|
||||
self.assertTrue(self.torrentManager.remove(torrent_id, False))
|
||||
|
||||
def test_remove_torrent_false(self):
|
||||
"""Test when remove_torrent returns False"""
|
||||
raise unittest.SkipTest("")
|
||||
|
||||
def test_remove_invalid_torrent(self):
|
||||
self.assertRaises(InvalidTorrentError, self.torrentManager.remove, "torrentidthatdoesntexist")
|
@ -67,8 +67,14 @@ class RemoveTorrentDialog(object):
|
||||
# Unselect all to avoid issues with the selection changed event
|
||||
component.get("TorrentView").treeview.get_selection().unselect_all()
|
||||
|
||||
for torrent_id in self.__torrent_ids:
|
||||
client.core.remove_torrent(torrent_id, remove_data)
|
||||
def on_removed_finished(errors):
|
||||
if errors:
|
||||
log.info("Error(s) occured when trying to delete torrent(s).")
|
||||
for t_id, e_msg in errors:
|
||||
log.warn("Error removing torrent %s : %s" % (t_id, e_msg))
|
||||
|
||||
d = client.core.remove_torrents(self.__torrent_ids, remove_data)
|
||||
d.addCallback(on_removed_finished)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user