Merge SVN and HG heads.

This commit is contained in:
Pedro Algarvio 2009-11-22 02:34:51 +00:00
commit 8a6ec7232d
15 changed files with 116 additions and 50 deletions

View file

@ -101,6 +101,13 @@ class ComponentRegistry:
if depend != None: if depend != None:
self.depend[name] = depend 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): def get(self, name):
"""Returns a reference to the component 'name'""" """Returns a reference to the component 'name'"""
return self.components[name] return self.components[name]
@ -126,8 +133,14 @@ class ComponentRegistry:
def stop(self): def stop(self):
"""Stops all components""" """Stops all components"""
for component in self.components.keys(): # We create a separate list of the keys and do an additional check to
self.stop_component(component) # 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): def stop_component(self, component):
if self.components[component].get_state() != \ if self.components[component].get_state() != \
@ -187,6 +200,10 @@ def register(name, obj, depend=None):
"""Registers a component with the registry""" """Registers a component with the registry"""
_ComponentRegistry.register(name, obj, depend) _ComponentRegistry.register(name, obj, depend)
def deregister(name):
"""Deregisters a component"""
_ComponentRegistry.deregister(name)
def start(component=None): def start(component=None):
"""Starts all components""" """Starts all components"""
if component == None: if component == None:

View file

@ -131,7 +131,7 @@ class DelugeRPCProtocol(Protocol):
try: try:
request = rencode.loads(dobj.decompress(data)) request = rencode.loads(dobj.decompress(data))
except Exception, e: 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 # This could be cut-off data, so we'll save this in the buffer
# and try to prepend it on the next dataReceived() # and try to prepend it on the next dataReceived()
self.__buffer = data self.__buffer = data

View file

@ -210,8 +210,11 @@ class TorrentManager(component.Component):
def stop(self): def stop(self):
# Stop timers # Stop timers
self.save_state_timer.stop() if self.save_state_timer.running:
self.save_resume_data_timer.stop() self.save_state_timer.stop()
if self.save_resume_data_timer.running:
self.save_resume_data_timer.stop()
# Save state on shutdown # Save state on shutdown
self.save_state() self.save_state()

View file

@ -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): class DelugeEvent(object):
""" """
The base class for all events. The base class for all events.
@ -49,6 +59,8 @@ class DelugeEvent(object):
:prop args: a list of the attribute values :prop args: a list of the attribute values
""" """
__metaclass__ = DelugeEventMetaClass
def _get_name(self): def _get_name(self):
return self.__class__.__name__ return self.__class__.__name__

View file

@ -87,7 +87,7 @@ class PluginManagerBase:
def disable_plugins(self): def disable_plugins(self):
# Disable all plugins that are enabled # Disable all plugins that are enabled
for key in self.plugins.keys(): for key in self.plugins.keys():
self.plugins[key].disable() self.disable_plugin(key)
def __getitem__(self, key): def __getitem__(self, key):
return self.plugins[key] return self.plugins[key]
@ -153,6 +153,7 @@ class PluginManagerBase:
"""Disables a plugin""" """Disables a plugin"""
try: try:
self.plugins[name].disable() self.plugins[name].disable()
component.deregister(self.plugins[name].plugin.get_component_name())
del self.plugins[name] del self.plugins[name]
self.config["enabled_plugins"].remove(name) self.config["enabled_plugins"].remove(name)
except KeyError: except KeyError:

View file

@ -49,3 +49,18 @@ def raiseError(error):
raise error raise error
return new return new
return safer 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(".")])

View file

@ -128,6 +128,8 @@ class Core(CorePluginBase):
self.use_cache = False self.use_cache = False
self.failed_attempts = 0 self.failed_attempts = 0
self.auto_detected = False self.auto_detected = False
if force:
self.reader = None
# Start callback chain # Start callback chain
d = self.download_list() d = self.download_list()
@ -218,8 +220,8 @@ class Core(CorePluginBase):
if self.config["last_update"] and not self.force_download: if self.config["last_update"] and not self.force_download:
headers['If-Modified-Since'] = self.config["last_update"] headers['If-Modified-Since'] = self.config["last_update"]
log.debug("Attempting to download blocklist %s" % url) log.debug("Attempting to download blocklist %s", url)
log.debug("Sending headers: %s" % headers) log.debug("Sending headers: %s", headers)
self.up_to_date = False self.up_to_date = False
self.is_downloading = True self.is_downloading = True
return download_file(url, deluge.configmanager.get_config_dir("blocklist.download"), on_retrieve_data, headers) 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 # Handle redirect errors
location = error_msg.split(" to ")[1] location = error_msg.split(" to ")[1]
if "Moved Permanently" in error_msg: 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 self.config["url"] = location
f.trap(f.type) f.trap(f.type)
d = self.download_list(url=location) d = self.download_list(url=location)
@ -291,7 +293,7 @@ class Core(CorePluginBase):
self.auto_detect(blocklist) self.auto_detect(blocklist)
self.auto_detected = True 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"]) 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 = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range)
d.addCallback(on_finish_read) d.addCallback(on_finish_read)
@ -327,7 +329,7 @@ class Core(CorePluginBase):
elif os.path.exists(blocklist) and not self.use_cache: elif os.path.exists(blocklist) and not self.use_cache:
# If we have a backup and we haven't already used it # If we have a backup and we haven't already used it
e = f.trap(Exception) e = f.trap(Exception)
log.warning("Error reading blocklist: ", e) log.warning("Error reading blocklist: %s", e)
self.use_cache = True self.use_cache = True
try_again = True try_again = True
@ -347,7 +349,7 @@ class Core(CorePluginBase):
""" """
self.config["list_compression"] = detect_compression(blocklist) self.config["list_compression"] = detect_compression(blocklist)
self.config["list_type"] = detect_format(blocklist, self.config["list_compression"]) 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"]: if not self.config["list_type"]:
self.config["list_compression"] = "" self.config["list_compression"] = ""
raise UnknownFormatError raise UnknownFormatError

View file

@ -77,5 +77,4 @@ def create_reader(format, compression=""):
decompressor = DECOMPRESSERS.get(compression) decompressor = DECOMPRESSERS.get(compression)
if decompressor: if decompressor:
reader = decompressor(reader) reader = decompressor(reader)
return reader return reader

View file

@ -33,29 +33,9 @@
# #
# #
from deluge.log import LOG as log from common import raiseError, remove_zeros
from common import raiseError 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): class ReaderParseError(Exception):
pass pass
@ -90,6 +70,9 @@ class BaseReader(object):
if not self.is_ignored(line): if not self.is_ignored(line):
try: try:
(start, end) = self.parse(line) (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: except:
valid = False valid = False
finally: finally:
@ -115,7 +98,7 @@ class SafePeerReader(BaseReader):
"""Blocklist reader for SafePeer style blocklists""" """Blocklist reader for SafePeer style blocklists"""
@raiseError(ReaderParseError) @raiseError(ReaderParseError)
def parse(self, line): def parse(self, line):
return line.strip().split(":")[1].split("-") return line.strip().split(":")[-1].split("-")
class PeerGuardianReader(SafePeerReader): class PeerGuardianReader(SafePeerReader):
"""Blocklist reader for PeerGuardian style blocklists""" """Blocklist reader for PeerGuardian style blocklists"""

View file

@ -249,7 +249,7 @@ class ConsoleUI(component.Component):
""" """
self.batch_write = batch self.batch_write = batch
if not batch: if not batch and self.interactive:
self.screen.refresh() self.screen.refresh()
def write(self, line): def write(self, line):

View file

@ -35,6 +35,8 @@
"""Common functions for various parts of gtkui to use.""" """Common functions for various parts of gtkui to use."""
import os
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk, gtk.glade import gtk, gtk.glade

View file

@ -3,7 +3,6 @@
<!-- interface-requires gtk+ 2.12 --> <!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy toplevel-contextual --> <!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkDialog" id="dialog_add_torrent"> <widget class="GtkDialog" id="dialog_add_torrent">
<property name="height_request">560</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="title" translatable="yes">Add Torrents</property> <property name="title" translatable="yes">Add Torrents</property>
@ -14,12 +13,14 @@
<widget class="GtkVBox" id="dialog-vbox1"> <widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property> <property name="spacing">2</property>
<child> <child>
<widget class="GtkVPaned" id="vpaned1"> <widget class="GtkVPaned" id="vpaned1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkFrame" id="frame2"> <widget class="GtkFrame" id="frame2">
<property name="visible">True</property> <property name="visible">True</property>
@ -37,6 +38,7 @@
<widget class="GtkVBox" id="vbox2"> <widget class="GtkVBox" id="vbox2">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkScrolledWindow" id="scrolledwindow1"> <widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property> <property name="visible">True</property>
@ -345,6 +347,7 @@
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<widget class="GtkFrame" id="frame7"> <widget class="GtkFrame" id="frame7">
@ -425,6 +428,7 @@
<widget class="GtkVBox" id="vbox4"> <widget class="GtkVBox" id="vbox4">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkRadioButton" id="radio_full"> <widget class="GtkRadioButton" id="radio_full">
<property name="label" translatable="yes">Full</property> <property name="label" translatable="yes">Full</property>
@ -657,6 +661,7 @@
<widget class="GtkVBox" id="vbox5"> <widget class="GtkVBox" id="vbox5">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<widget class="GtkCheckButton" id="chk_paused"> <widget class="GtkCheckButton" id="chk_paused">
@ -901,6 +906,8 @@
<signal name="clicked" handler="on_button_cancel_clicked"/> <signal name="clicked" handler="on_button_cancel_clicked"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
@ -915,6 +922,8 @@
<signal name="clicked" handler="on_button_add_clicked"/> <signal name="clicked" handler="on_button_add_clicked"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
@ -942,11 +951,13 @@
<widget class="GtkVBox" id="dialog-vbox4"> <widget class="GtkVBox" id="dialog-vbox4">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property> <property name="spacing">2</property>
<child> <child>
<widget class="GtkVBox" id="vbox6"> <widget class="GtkVBox" id="vbox6">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<widget class="GtkHBox" id="hbox7"> <widget class="GtkHBox" id="hbox7">
@ -1053,6 +1064,8 @@
<property name="use_stock">True</property> <property name="use_stock">True</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
@ -1069,6 +1082,8 @@
<property name="use_stock">True</property> <property name="use_stock">True</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
@ -1096,11 +1111,13 @@
<widget class="GtkVBox" id="dialog-vbox5"> <widget class="GtkVBox" id="dialog-vbox5">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property> <property name="spacing">2</property>
<child> <child>
<widget class="GtkVBox" id="vbox7"> <widget class="GtkVBox" id="vbox7">
<property name="visible">True</property> <property name="visible">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<widget class="GtkHBox" id="hbox8"> <widget class="GtkHBox" id="hbox8">
@ -1246,6 +1263,8 @@
<property name="use_stock">True</property> <property name="use_stock">True</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
@ -1262,6 +1281,8 @@
<property name="use_stock">True</property> <property name="use_stock">True</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>

View file

@ -309,10 +309,7 @@ Please see the details below for more information."), details=traceback.format_e
dialogs.ErrorDialog( dialogs.ErrorDialog(
_("Error Starting Daemon"), _("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() _("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): def on_connect(connector):
component.start() component.start()
def on_connect_fail(result, try_counter): 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 try_counter -= 1
import time import time
time.sleep(0.5) time.sleep(0.5)
do_connect() do_connect(try_counter)
return result return result
def do_connect(): def do_connect(try_counter):
client.connect(*host[1:]).addCallback(on_connect).addErrback(on_connect_fail, try_counter) client.connect(*host[1:]).addCallback(on_connect).addErrback(on_connect_fail, try_counter)
if try_connect: if try_connect:
do_connect() do_connect(6)
break
if self.config["show_connection_manager_on_start"]: if self.config["show_connection_manager_on_start"]:
# XXX: We need to call a simulate() here, but this could be a bug in twisted # XXX: We need to call a simulate() here, but this could be a bug in twisted

View file

@ -35,7 +35,7 @@
import sys import sys
import os.path import os
import base64 import base64
import deluge.rencode import deluge.rencode
@ -104,6 +104,20 @@ class IPCInterface(component.Component):
reactor.run() reactor.run()
sys.exit(0) sys.exit(0)
else: 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: try:
self.factory = Factory() self.factory = Factory()
self.factory.protocol = IPCProtocolServer self.factory.protocol = IPCProtocolServer

View file

@ -1,7 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title>Deluge: Web UI (alpha) ${version}</title> <title>Deluge: Web UI ${version}</title>
<link rel="shortcut icon" href="/icons/deluge.png" type="image/png" /> <link rel="shortcut icon" href="/icons/deluge.png" type="image/png" />
<link rel="icon" href="/icons/deluge.png" type="image/png" /> <link rel="icon" href="/icons/deluge.png" type="image/png" />