diff --git a/deluge/config.py b/deluge/config.py index 4981a1775..2fd367d98 100644 --- a/deluge/config.py +++ b/deluge/config.py @@ -51,6 +51,8 @@ class Config: # Load the config from file in the config_dir self.config_file = deluge.common.get_config_dir(filename) self.load(self.config_file) + # Save + self.save() def __del__(self): log.debug("Config object deconstructing..") @@ -90,6 +92,8 @@ class Config: # Sets the "key" with "value" in the config dict log.debug("Setting '%s' to %s", key, value) self.config[key] = value + # Whenever something is set, we should save + self.save() def get(self, key): # Attempts to get the "key" value and returns None if the key is @@ -106,4 +110,4 @@ class Config: return self.config[key] def __setitem__(self, key, value): - self.config[key] = value + self.set(key, value) diff --git a/deluge/core/core.py b/deluge/core/core.py index 07c46827d..d25825f02 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -67,9 +67,6 @@ DEFAULT_PREFS = { class Core(dbus.service.Object): def __init__(self, path="/org/deluge_torrent/Core"): log.debug("Core init..") - - # Start the TorrentManager - self.torrents = TorrentManager() # Setup DBUS bus_name = dbus.service.BusName("org.deluge_torrent.Deluge", @@ -87,6 +84,9 @@ class Core(dbus.service.Object): self.session.listen_on(self.config.get("listen_ports")[0], self.config.get("listen_ports")[1]) + # Start the TorrentManager + self.torrents = TorrentManager(self.session) + log.debug("Starting main loop..") self.loop = gobject.MainLoop() self.loop.run() @@ -105,56 +105,27 @@ class Core(dbus.service.Object): This requires the torrents filename and a dump of it's content """ log.info("Adding torrent: %s", filename) - - # Convert the filedump data array into a string of bytes - filedump = "".join(chr(b) for b in filedump) - - # Bdecode the filedata sent from the UI - torrent_filedump = lt.bdecode(filedump) - handle = None - try: - handle = self.session.add_torrent(lt.torrent_info(torrent_filedump), - self.config["download_location"], - self.config["compact_allocation"]) - except RuntimeError: - log.warning("Error adding torrent") - - if not handle or not handle.is_valid(): - # The torrent was not added to the session - # Emit the torrent_add_failed signal + torrent_id = self.torrents.add(filename, filedump) + if torrent_id is not None: + # Emit the torrent_added signal + self.torrent_added(torrent_id) + else: self.torrent_add_failed() - return - - # Write the .torrent file to the torrent directory - log.debug("Attemping to save torrent file: %s", filename) - try: - f = open(os.path.join(self.config["torrentfiles_location"], - filename), - "wb") - f.write(filedump) - f.close() - except IOError: - log.warning("Unable to save torrent file: %s", filename) - - # Add the torrent to the torrentmanager - torrent_id = self.torrents.add(handle) - - # Emit the torrent_added signal - self.torrent_added(torrent_id) @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", in_signature="s", out_signature="") def remove_torrent(self, torrent_id): log.debug("Removing torrent %s from the core.", torrent_id) - try: - # Remove from libtorrent session - self.session.remove_torrent(self.torrents[torrent_id].handle) - # Remove from TorrentManager - self.torrents.remove(torrent_id) + if self.torrents.remove(torrent_id): # Emit the torrent_removed signal self.torrent_removed(torrent_id) - except RuntimeError, KeyError: - log.warning("Error removing torrent") + + @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", + in_signature="s", out_signature="") + def pause_torrent(self, torrent_id): + log.debug("Pausing torrent %s", torrent_id) + if self.torrents.pause(torrent_id): + self.torrent_paused(torrent_id) @dbus.service.method(dbus_interface="org.deluge_torrent.Deluge", in_signature="s", out_signature="(sxi)") @@ -236,3 +207,9 @@ class Core(dbus.service.Object): def torrent_queue_changed(self): """Emitted when a torrent queue position is changed""" log.debug("torrent_queue_changed signal emitted") + + @dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge", + signature="s") + def torrent_paused(self, torrent_id): + """Emitted when a torrent is paused""" + log.debug("torrent_paused signal emitted") diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index 7b7824667..ca58efb67 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -39,7 +39,9 @@ import deluge.libtorrent as lt log = logging.getLogger("deluge") class Torrent: - def __init__(self, handle, queue): + def __init__(self, filename, handle, queue): + # Set the filename + self.filename = filename # Set the libtorrent handle self.handle = handle # Set the queue this torrent belongs too @@ -49,6 +51,10 @@ class Torrent: def __del__(self): self.queue.remove(self.torrent_id) + + def get_state(self): + """Returns the state of this torrent for saving to the session state""" + return (self.torrent_id, self.filename) def get_eta(self): """Returns the ETA in seconds for this torrent""" diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index af715935e..bd40a1340 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -32,16 +32,25 @@ # statement from all source files in the program, then also delete it here. import logging +import pickle +import os.path +import deluge.libtorrent as lt + +import deluge.common +from deluge.config import Config from deluge.core.torrent import Torrent from deluge.core.torrentqueue import TorrentQueue +from deluge.core.torrentmanagerstate import TorrentManagerState, TorrentState # Get the logger log = logging.getLogger("deluge") class TorrentManager: - def __init__(self): + def __init__(self, session): log.debug("TorrentManager init..") + # Set the libtorrent session + self.session = session # Create the torrents dict { torrent_id: Torrent } self.torrents = {} self.queue = TorrentQueue() @@ -50,10 +59,42 @@ class TorrentManager: """Return the Torrent with torrent_id""" return self.torrents[torrent_id] - def add(self, handle): + def add(self, filename, filedump): """Add a torrent to the manager and returns it's torrent_id""" + # Get the core config + config = Config("core.conf") + + # Convert the filedump data array into a string of bytes + filedump = "".join(chr(b) for b in filedump) + + # Bdecode the filedata sent from the UI + torrent_filedump = lt.bdecode(filedump) + handle = None + + try: + handle = self.session.add_torrent(lt.torrent_info(torrent_filedump), + config["download_location"], + config["compact_allocation"]) + except RuntimeError: + log.warning("Error adding torrent") + + if not handle or not handle.is_valid(): + # The torrent was not added to the session + return None + + # Write the .torrent file to the torrent directory + log.debug("Attemping to save torrent file: %s", filename) + try: + f = open(os.path.join(config["torrentfiles_location"], + filename), + "wb") + f.write(filedump) + f.close() + except IOError: + log.warning("Unable to save torrent file: %s", filename) + # Create a Torrent object - torrent = Torrent(handle, self.queue) + torrent = Torrent(filename, handle, self.queue) # Add the torrent object to the dictionary self.torrents[torrent.torrent_id] = torrent # Add the torrent to the queue @@ -62,12 +103,48 @@ class TorrentManager: def remove(self, torrent_id): """Remove a torrent from the manager""" + try: + # Remove from libtorrent session + self.session.remove_torrent(self.torrents[torrent_id].handle) + except RuntimeError, KeyError: + log.warning("Error removing torrent") + return False + try: del self.torrents[torrent_id] except KeyError, ValueError: return False return True + + def pause(self, torrent_id): + """Pause a torrent""" + try: + self.torrents[torrent_id].handle.pause() + except: + return False + + return True + + def save_state(self): + """Save the state of the TorrentManager to the torrents.state file""" + state = TorrentManagerState() + # Grab the queue from TorrentQueue + state.queue = self.queue.queue + # Create the state for each Torrent and append to the list + for (key, torrent) in self.torrents: + t = TorrentState(torrent.get_state()) + state.torrents.append(t) + # Pickle the TorrentManagerState object + try: + log.debug("Saving torrent state file.") + state_file = open(deluge.common.get_config_dir("torrents.state"), "wb") + pickle.dump(state, state_file) + state_file.close() + except IOError: + log.warning("Unable to save state file.") + + def get_info_template(self): """Returns a list of strings that correspond to the info tuple""" return [ diff --git a/deluge/main.py b/deluge/main.py index 393cd9f02..b46f06ffc 100644 --- a/deluge/main.py +++ b/deluge/main.py @@ -53,7 +53,6 @@ log = logging.getLogger("deluge") def main(): # Setup the argument parser - # FIXME: need to use deluge.common to fill in version parser = OptionParser(usage="%prog [options] [actions]", version=deluge.common.get_version()) parser.add_option("--daemon", dest="daemon", help="Start Deluge daemon", diff --git a/deluge/ui/gtkui/functions.py b/deluge/ui/gtkui/functions.py index 7de2d515c..b11cb5c3e 100644 --- a/deluge/ui/gtkui/functions.py +++ b/deluge/ui/gtkui/functions.py @@ -92,6 +92,12 @@ def remove_torrent(torrent_ids): core = get_core() for torrent_id in torrent_ids: core.remove_torrent(torrent_id) + +def pause_torrent(torrent_ids): + """Pauses torrent_ids""" + core = get_core() + for torrent_id in torrent_ids: + core.pause_torrent(torrent_id) def queue_top(torrent_ids): """Attempts to queue all torrent_ids to the top""" diff --git a/deluge/ui/gtkui/menubar.py b/deluge/ui/gtkui/menubar.py index 61bb4a8fa..bc071c9bf 100644 --- a/deluge/ui/gtkui/menubar.py +++ b/deluge/ui/gtkui/menubar.py @@ -123,6 +123,8 @@ class MenuBar: ## Torrent Menu ## def on_menuitem_pause_activate(self, data=None): log.debug("on_menuitem_pause_activate") + functions.pause_torrent( + self.window.torrentview.get_selected_torrents()) def on_menuitem_updatetracker_activate(self, data=None): log.debug("on_menuitem_updatetracker_activate") diff --git a/deluge/ui/gtkui/signals.py b/deluge/ui/gtkui/signals.py index 10c87a105..6a8ba2d29 100644 --- a/deluge/ui/gtkui/signals.py +++ b/deluge/ui/gtkui/signals.py @@ -65,6 +65,7 @@ class Signals: self.torrent_removed_signal) self.core.connect_to_signal("torrent_queue_changed", self.torrent_queue_changed_signal) + self.core.connect_to_signal("torrent_paused", self.torrent_paused) def torrent_added_signal(self, torrent_id): log.debug("torrent_added signal received..") @@ -82,3 +83,7 @@ class Signals: log.debug("torrent_queue_changed signal received..") # Force an update of the torrent view self.ui.main_window.torrentview.update() + + def torrent_paused(self, torrent_id): + log.debug("torrent_paused signal received..") + self.ui.main_window.torrentview.update()