diff --git a/deluge/component.py b/deluge/component.py index 764c38609..f433ad6e0 100644 --- a/deluge/component.py +++ b/deluge/component.py @@ -101,6 +101,13 @@ class ComponentRegistry: if depend != None: self.depend[name] = depend + def deregister(self, name): + """Deregisters a component""" + if name in self.components: + log.debug("Deregistering Component: %s", name) + self.stop_component(name) + del self.components[name] + def get(self, name): """Returns a reference to the component 'name'""" return self.components[name] @@ -126,8 +133,14 @@ class ComponentRegistry: def stop(self): """Stops all components""" - for component in self.components.keys(): - self.stop_component(component) + # We create a separate list of the keys and do an additional check to + # make sure the key still exists in the components dict. + # This is because components could be deregistered during a stop and + # the dictionary would get modified while iterating through it. + components = self.components.keys() + for component in components: + if component in self.components: + self.stop_component(component) def stop_component(self, component): if self.components[component].get_state() != \ @@ -187,6 +200,10 @@ def register(name, obj, depend=None): """Registers a component with the registry""" _ComponentRegistry.register(name, obj, depend) +def deregister(name): + """Deregisters a component""" + _ComponentRegistry.deregister(name) + def start(component=None): """Starts all components""" if component == None: diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py index 7525fdb5c..425ccb6c8 100644 --- a/deluge/core/rpcserver.py +++ b/deluge/core/rpcserver.py @@ -131,7 +131,7 @@ class DelugeRPCProtocol(Protocol): try: request = rencode.loads(dobj.decompress(data)) except Exception, e: - log.debug("Received possible invalid message (%r): %s", data, e) + #log.debug("Received possible invalid message (%r): %s", data, e) # This could be cut-off data, so we'll save this in the buffer # and try to prepend it on the next dataReceived() self.__buffer = data diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 0bfe1c1d8..c9d69f487 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -210,8 +210,11 @@ class TorrentManager(component.Component): def stop(self): # Stop timers - self.save_state_timer.stop() - self.save_resume_data_timer.stop() + if self.save_state_timer.running: + self.save_state_timer.stop() + + if self.save_resume_data_timer.running: + self.save_resume_data_timer.stop() # Save state on shutdown self.save_state() diff --git a/deluge/event.py b/deluge/event.py index 118a76e59..67618e9df 100644 --- a/deluge/event.py +++ b/deluge/event.py @@ -41,6 +41,16 @@ and subsequently emitted to the clients. """ +event_list = [] + +class DelugeEventMetaClass(type): + """ + This metaclass simply keeps a list of all events classes created. + """ + def __init__(cls, name, bases, dct): + event_list.append(name) + super(DelugeEventMetaClass, cls).__init__(name, bases, dct) + class DelugeEvent(object): """ The base class for all events. @@ -49,6 +59,8 @@ class DelugeEvent(object): :prop args: a list of the attribute values """ + __metaclass__ = DelugeEventMetaClass + def _get_name(self): return self.__class__.__name__ diff --git a/deluge/pluginmanagerbase.py b/deluge/pluginmanagerbase.py index 7a899475e..35c551d25 100644 --- a/deluge/pluginmanagerbase.py +++ b/deluge/pluginmanagerbase.py @@ -87,7 +87,7 @@ class PluginManagerBase: def disable_plugins(self): # Disable all plugins that are enabled for key in self.plugins.keys(): - self.plugins[key].disable() + self.disable_plugin(key) def __getitem__(self, key): return self.plugins[key] @@ -153,6 +153,7 @@ class PluginManagerBase: """Disables a plugin""" try: self.plugins[name].disable() + component.deregister(self.plugins[name].plugin.get_component_name()) del self.plugins[name] self.config["enabled_plugins"].remove(name) except KeyError: diff --git a/deluge/plugins/blocklist/blocklist/common.py b/deluge/plugins/blocklist/blocklist/common.py index a8d6d93b9..d1181ddf5 100644 --- a/deluge/plugins/blocklist/blocklist/common.py +++ b/deluge/plugins/blocklist/blocklist/common.py @@ -49,3 +49,18 @@ def raiseError(error): raise error return new return safer + +def remove_zeros(ip): + """ + Removes unneeded zeros from ip addresses. + + Example: 000.000.000.003 -> 0.0.0.3 + + :param ip: the ip address + :type ip: string + + :returns: the ip address without the unneeded zeros + :rtype: string + + """ + return ".".join([part.lstrip("0").zfill(1) for part in ip.split(".")]) diff --git a/deluge/plugins/blocklist/blocklist/core.py b/deluge/plugins/blocklist/blocklist/core.py index c734ca0fc..0d772a2ad 100644 --- a/deluge/plugins/blocklist/blocklist/core.py +++ b/deluge/plugins/blocklist/blocklist/core.py @@ -128,6 +128,8 @@ class Core(CorePluginBase): self.use_cache = False self.failed_attempts = 0 self.auto_detected = False + if force: + self.reader = None # Start callback chain d = self.download_list() @@ -218,8 +220,8 @@ class Core(CorePluginBase): if self.config["last_update"] and not self.force_download: headers['If-Modified-Since'] = self.config["last_update"] - log.debug("Attempting to download blocklist %s" % url) - log.debug("Sending headers: %s" % headers) + log.debug("Attempting to download blocklist %s", url) + log.debug("Sending headers: %s", headers) self.up_to_date = False self.is_downloading = True return download_file(url, deluge.configmanager.get_config_dir("blocklist.download"), on_retrieve_data, headers) @@ -239,7 +241,7 @@ class Core(CorePluginBase): # Handle redirect errors location = error_msg.split(" to ")[1] if "Moved Permanently" in error_msg: - log.debug("Setting blocklist url to %s" % location) + log.debug("Setting blocklist url to %s", location) self.config["url"] = location f.trap(f.type) d = self.download_list(url=location) @@ -291,7 +293,7 @@ class Core(CorePluginBase): self.auto_detect(blocklist) self.auto_detected = True - log.debug("Importing using reader: %s",self.reader) + log.debug("Importing using reader: %s", self.reader) log.debug("Reader type: %s compression: %s", self.config["list_type"], self.config["list_compression"]) d = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range) d.addCallback(on_finish_read) @@ -327,7 +329,7 @@ class Core(CorePluginBase): elif os.path.exists(blocklist) and not self.use_cache: # If we have a backup and we haven't already used it e = f.trap(Exception) - log.warning("Error reading blocklist: ", e) + log.warning("Error reading blocklist: %s", e) self.use_cache = True try_again = True @@ -347,7 +349,7 @@ class Core(CorePluginBase): """ self.config["list_compression"] = detect_compression(blocklist) self.config["list_type"] = detect_format(blocklist, self.config["list_compression"]) - log.debug("Auto-detected type: %s compression: %s", self.config["list_type"], self.config["list_compression"]) + log.debug("Auto-detected type: %s compression: %s", self.config["list_type"], self.config["list_compression"]) if not self.config["list_type"]: self.config["list_compression"] = "" raise UnknownFormatError diff --git a/deluge/plugins/blocklist/blocklist/detect.py b/deluge/plugins/blocklist/blocklist/detect.py index af1450424..f429e1e9f 100644 --- a/deluge/plugins/blocklist/blocklist/detect.py +++ b/deluge/plugins/blocklist/blocklist/detect.py @@ -77,5 +77,4 @@ def create_reader(format, compression=""): decompressor = DECOMPRESSERS.get(compression) if decompressor: reader = decompressor(reader) - return reader diff --git a/deluge/plugins/blocklist/blocklist/readers.py b/deluge/plugins/blocklist/blocklist/readers.py index ddfea004c..a520fad3c 100644 --- a/deluge/plugins/blocklist/blocklist/readers.py +++ b/deluge/plugins/blocklist/blocklist/readers.py @@ -33,29 +33,9 @@ # # -from deluge.log import LOG as log -from common import raiseError +from common import raiseError, remove_zeros +import re -def remove_zeros(ip): - """ - Removes unneeded zeros from ip addresses. - - Example: 000.000.000.003 -> 0.0.0.3 - - :param ip: the ip address - :type ip: string - - :returns: the ip address without the unneeded zeros - :rtype: string - - """ - new_ip = [] - for part in ip.split("."): - while part[0] == "0" and len(part) > 1: - part = part[1:] - new_ip.append(part) - return ".".join(new_ip) - class ReaderParseError(Exception): pass @@ -90,6 +70,9 @@ class BaseReader(object): if not self.is_ignored(line): try: (start, end) = self.parse(line) + if not re.match("^(\d{1,3}\.){4}$", start + ".") or \ + not re.match("^(\d{1,3}\.){4}$", end + "."): + valid = False except: valid = False finally: @@ -115,7 +98,7 @@ class SafePeerReader(BaseReader): """Blocklist reader for SafePeer style blocklists""" @raiseError(ReaderParseError) def parse(self, line): - return line.strip().split(":")[1].split("-") + return line.strip().split(":")[-1].split("-") class PeerGuardianReader(SafePeerReader): """Blocklist reader for PeerGuardian style blocklists""" diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py index 749f8d826..afbe6a7ac 100644 --- a/deluge/ui/console/main.py +++ b/deluge/ui/console/main.py @@ -249,7 +249,7 @@ class ConsoleUI(component.Component): """ self.batch_write = batch - if not batch: + if not batch and self.interactive: self.screen.refresh() def write(self, line): diff --git a/deluge/ui/gtkui/common.py b/deluge/ui/gtkui/common.py index 72bbbb139..aceee3679 100644 --- a/deluge/ui/gtkui/common.py +++ b/deluge/ui/gtkui/common.py @@ -35,6 +35,8 @@ """Common functions for various parts of gtkui to use.""" +import os + import pygtk pygtk.require('2.0') import gtk, gtk.glade diff --git a/deluge/ui/gtkui/glade/add_torrent_dialog.glade b/deluge/ui/gtkui/glade/add_torrent_dialog.glade index 00aa52cd4..d59c24d20 100644 --- a/deluge/ui/gtkui/glade/add_torrent_dialog.glade +++ b/deluge/ui/gtkui/glade/add_torrent_dialog.glade @@ -3,7 +3,6 @@ - 560 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 Add Torrents @@ -14,12 +13,14 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 2 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical True @@ -37,6 +38,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical True @@ -345,6 +347,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 + vertical 5 @@ -425,6 +428,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical Full @@ -657,6 +661,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 5 @@ -901,6 +906,8 @@ + False + False 0 @@ -915,6 +922,8 @@ + False + False 1 @@ -942,11 +951,13 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 2 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 5 @@ -1053,6 +1064,8 @@ True + False + False 0 @@ -1069,6 +1082,8 @@ True + False + False 1 @@ -1096,11 +1111,13 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 2 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + vertical 5 @@ -1246,6 +1263,8 @@ True + False + False 0 @@ -1262,6 +1281,8 @@ True + False + False 1 diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py index 37f44861c..b8f435716 100644 --- a/deluge/ui/gtkui/gtkui.py +++ b/deluge/ui/gtkui/gtkui.py @@ -309,10 +309,7 @@ Please see the details below for more information."), details=traceback.format_e dialogs.ErrorDialog( _("Error Starting Daemon"), _("There was an error starting the daemon process. Try running it from a console to see if there is an error.")).run() - - # We'll try 30 reconnects at 500ms intervals - try_counter = 30 - + def on_connect(connector): component.start() def on_connect_fail(result, try_counter): @@ -323,15 +320,15 @@ Please see the details below for more information."), details=traceback.format_e try_counter -= 1 import time time.sleep(0.5) - do_connect() + do_connect(try_counter) return result - - def do_connect(): + + def do_connect(try_counter): client.connect(*host[1:]).addCallback(on_connect).addErrback(on_connect_fail, try_counter) - + if try_connect: - do_connect() - + do_connect(6) + break if self.config["show_connection_manager_on_start"]: # XXX: We need to call a simulate() here, but this could be a bug in twisted diff --git a/deluge/ui/gtkui/ipcinterface.py b/deluge/ui/gtkui/ipcinterface.py index 2ee48fd21..046073399 100644 --- a/deluge/ui/gtkui/ipcinterface.py +++ b/deluge/ui/gtkui/ipcinterface.py @@ -35,7 +35,7 @@ import sys -import os.path +import os import base64 import deluge.rencode @@ -104,6 +104,20 @@ class IPCInterface(component.Component): reactor.run() sys.exit(0) else: + lockfile = socket + ".lock" + log.debug("Checking if lockfile exists: %s", lockfile) + if os.path.lexists(lockfile): + try: + os.kill(int(os.readlink(lockfile)), 0) + except OSError: + log.debug("Removing lockfile since it's stale.") + try: + os.remove(lockfile) + os.remove(socket) + except Exception, e: + log.error("Problem deleting lockfile or socket file!") + log.exception(e) + try: self.factory = Factory() self.factory.protocol = IPCProtocolServer diff --git a/deluge/ui/web/index.html b/deluge/ui/web/index.html index 0eb3b7cef..d0fed9d63 100644 --- a/deluge/ui/web/index.html +++ b/deluge/ui/web/index.html @@ -1,7 +1,7 @@ - Deluge: Web UI (alpha) ${version} + Deluge: Web UI ${version}