Example #1
0
    def run_converter(self, input_range, output_version, func):
        """
        Runs a function that will convert file versions in the `:param:input_range`
        to the `:param:output_version`.

        :param input_range: tuple, (int, int) the range of input versions this
            function will accept
        :param output_version: int, the version this function will return
        :param func: func, the function that will do the conversion, it will take
            the config dict as an argument and return the augmented dict

        :raises ValueError: if the output_version is less than the input_range

        """
        if output_version in input_range or output_version <= max(input_range):
            raise ValueError("output_version needs to be greater than input_range")

        if self.__version["file"] not in input_range:
            log.debug("File version %s is not in input_range %s, ignoring converter function..",
                self.__version["file"], input_range)
            return

        try:
            self.__config = func(self.__config)
        except Exception, e:
            log.exception(e)
            log.error("There was an exception try to convert config file %s %s to %s",
                self.__config_file, self.__version["file"], output_version)
            raise e
Example #2
0
 def _shutdown(self, *args, **kwargs):
     if os.path.exists(deluge.configmanager.get_config_dir("deluged.pid")):
         try:
             os.remove(deluge.configmanager.get_config_dir("deluged.pid"))
         except Exception, e:
             log.exception(e)
             log.error("Error removing deluged.pid!")
Example #3
0
    def run_converter(self, input_range, output_version, func):
        """
        Runs a function that will convert file versions in the `:param:input_range`
        to the `:param:output_version`.

        :param input_range: tuple, (int, int) the range of input versions this
            function will accept
        :param output_version: int, the version this function will return
        :param func: func, the function that will do the conversion, it will take
            the config dict as an argument and return the augmented dict

        :raises ValueError: if the output_version is less than the input_range

        """
        if output_version in input_range or output_version <= max(input_range):
            raise ValueError(
                "output_version needs to be greater than input_range")

        if self.__version["file"] not in input_range:
            log.debug(
                "File version %s is not in input_range %s, ignoring converter function..",
                self.__version["file"], input_range)
            return

        try:
            self.__config = func(self.__config)
        except Exception, e:
            log.exception(e)
            log.error(
                "There was an exception try to convert config file %s %s to %s",
                self.__config_file, self.__version["file"], output_version)
            raise e
Example #4
0
 def update_plugins(self):
     for plugin in self.plugins.keys():
         if hasattr(self.plugins[plugin], "update"):
             try:
                 self.plugins[plugin].update()
             except Exception, e:
                 log.exception(e)
Example #5
0
 def _shutdown(self, *args, **kwargs):
     if os.path.exists(deluge.configmanager.get_config_dir("deluged.pid")):
         try:
             os.remove(deluge.configmanager.get_config_dir("deluged.pid"))
         except Exception, e:
             log.exception(e)
             log.error("Error removing deluged.pid!")
Example #6
0
    def start_daemon(self, port, config):
        """
        Starts a daemon process.

        :param port: the port for the daemon to listen on
        :type port: int
        :param config: the path to the current config folder
        :type config: str
        :returns: True if started, False if not
        :rtype: bool

        :raises OSError: received from subprocess.call()

        """
        try:
            if deluge.common.windows_check():
                subprocess.Popen(["deluged", "--port=%s" % port, "--config=%s" % config])
            else:
                subprocess.call(["deluged", "--port=%s" % port, "--config=%s" % config])
        except OSError, e:
            from errno import ENOENT
            if e.errno == ENOENT:
                log.error(_("Deluge cannot find the 'deluged' executable, it is likely \
that you forgot to install the deluged package or it's not in your PATH."))
            else:
                log.exception(e)
            raise e
    def enable_plugin(self, plugin_name):
        """Enables a plugin"""
        if plugin_name not in self.available_plugins:
            log.warning("Cannot enable non-existant plugin %s", plugin_name)
            return

        if plugin_name in self.plugins:
            log.warning("Cannot enable already enabled plugin %s", plugin_name)
            return

        plugin_name = plugin_name.replace(" ", "-")
        egg = self.pkg_env[plugin_name][0]
        egg.activate()
        for name in egg.get_entry_map(self.entry_name):
            entry_point = egg.get_entry_info(self.entry_name, name)
            try:
                cls = entry_point.load()
                instance = cls(plugin_name.replace("-", "_"))
            except Exception, e:
                log.error("Unable to instantiate plugin!")
                log.exception(e)
                continue
            instance.enable()
            if self._component_state == "Started":
                component.start([instance.plugin._component_name])
            plugin_name = plugin_name.replace("-", " ")
            self.plugins[plugin_name] = instance
            if plugin_name not in self.config["enabled_plugins"]:
                log.debug("Adding %s to enabled_plugins list in config",
                          plugin_name)
                self.config["enabled_plugins"].append(plugin_name)
            log.info("Plugin %s enabled..", plugin_name)
    def enable_plugin(self, plugin_name):
        """Enables a plugin"""
        if plugin_name not in self.available_plugins:
            log.warning("Cannot enable non-existant plugin %s", plugin_name)
            return

        if plugin_name in self.plugins:
            log.warning("Cannot enable already enabled plugin %s", plugin_name)
            return

        plugin_name = plugin_name.replace(" ", "-")
        egg = self.pkg_env[plugin_name][0]
        egg.activate()
        for name in egg.get_entry_map(self.entry_name):
            entry_point = egg.get_entry_info(self.entry_name, name)
            try:
                cls = entry_point.load()
                instance = cls(plugin_name.replace("-", "_"))
            except Exception, e:
                log.error("Unable to instantiate plugin!")
                log.exception(e)
                continue
            instance.enable()
            if self._component_state == "Started":
                component.start([instance.plugin._component_name])
            plugin_name = plugin_name.replace("-", " ")
            self.plugins[plugin_name] = instance
            if plugin_name not in self.config["enabled_plugins"]:
                log.debug("Adding %s to enabled_plugins list in config",
                    plugin_name)
                self.config["enabled_plugins"].append(plugin_name)
            log.info("Plugin %s enabled..", plugin_name)
Example #9
0
    def start_daemon(self, port, config):
        """
        Starts a daemon process.

        :param port: the port for the daemon to listen on
        :type port: int
        :param config: the path to the current config folder
        :type config: str
        :returns: True if started, False if not
        :rtype: bool

        :raises OSError: received from subprocess.call()

        """
        try:
            if deluge.common.windows_check():
                subprocess.Popen(
                    ["deluged",
                     "--port=%s" % port,
                     "--config=%s" % config])
            else:
                subprocess.call(
                    ["deluged",
                     "--port=%s" % port,
                     "--config=%s" % config])
        except OSError, e:
            from errno import ENOENT
            if e.errno == ENOENT:
                log.error(
                    _("Deluge cannot find the 'deluged' executable, it is likely \
that you forgot to install the deluged package or it's not in your PATH."))
            else:
                log.exception(e)
            raise e
Example #10
0
    def call(self, method, *args, **kwargs):
        #log.debug("call: %s %s %s", method, args, kwargs)

        import copy

        try:
            m = self.__daemon.rpcserver.get_object_method(method)
        except Exception, e:
            log.exception(e)
            return defer.fail(e)
Example #11
0
 def doRead(self):
     """
     Called when there is data to be read, ie, input from the keyboard.
     """
     # We wrap this function to catch exceptions and shutdown the mainloop
     try:
         self._doRead()
     except Exception, e:
         log.exception(e)
         reactor.stop()
Example #12
0
 def doRead(self):
     """
     Called when there is data to be read, ie, input from the keyboard.
     """
     # We wrap this function to catch exceptions and shutdown the mainloop
     try:
         self._doRead()
     except Exception, e:
         log.exception(e)
         reactor.stop()
Example #13
0
    def call(self, method, *args, **kwargs):
        #log.debug("call: %s %s %s", method, args, kwargs)

        import copy

        try:
            m = self.__daemon.rpcserver.get_object_method(method)
        except Exception, e:
            log.exception(e)
            return defer.fail(e)
Example #14
0
    def upload_plugin(self, filename, filedump):
        """This method is used to upload new plugins to the daemon.  It is used
        when connecting to the daemon remotely and installing a new plugin on
        the client side. 'plugin_data' is a xmlrpc.Binary object of the file data,
        ie, plugin_file.read()"""

        try:
            filedump = base64.decodestring(filedump)
        except Exception, e:
            log.error("There was an error decoding the filedump string!")
            log.exception(e)
            return
Example #15
0
    def upload_plugin(self, filename, filedump):
        """This method is used to upload new plugins to the daemon.  It is used
        when connecting to the daemon remotely and installing a new plugin on
        the client side. 'plugin_data' is a xmlrpc.Binary object of the file data,
        ie, plugin_file.read()"""

        try:
            filedump = base64.decodestring(filedump)
        except Exception, e:
            log.error("There was an error decoding the filedump string!")
            log.exception(e)
            return
Example #16
0
    def move_storage(self, dest):
        """Move a torrent's storage location"""
        try:
           dest = unicode(dest, "utf-8")
        except TypeError:
           # String is already unicode
           pass

        if not os.path.exists(dest):
            try:
                # Try to make the destination path if it doesn't exist
                os.makedirs(dest)
            except IOError, e:
                log.exception(e)
                log.error("Could not move storage for torrent %s since %s does not exist and could not create the directory.", self.torrent_id, dest_u)
                return False
Example #17
0
 def move_storage(self, dest):
     """Move a torrent's storage location"""
     try:
        dest = unicode(dest, "utf-8")
     except TypeError:
        # String is already unicode
        pass
         
     if not os.path.exists(dest):
         try:
             # Try to make the destination path if it doesn't exist
             os.makedirs(dest)
         except IOError, e:
             log.exception(e)
             log.error("Could not move storage for torrent %s since %s does not exist and could not create the directory.", self.torrent_id, dest_u)
             return False
Example #18
0
    def dispatch(self, request_id, method, args, kwargs):
        """
        This method is run when a RPC Request is made.  It will run the local method
        and will send either a RPC Response or RPC Error back to the client.

        :param request_id: the request_id from the client (sent in the RPC Request)
        :type request_id: int
        :param method: the local method to call. It must be registered with
            the :class:`RPCServer`.
        :type method: str
        :param args: the arguments to pass to `method`
        :type args: list
        :param kwargs: the keyword-arguments to pass to `method`
        :type kwargs: dict

        """
        def sendError():
            """
            Sends an error response with the contents of the exception that was raised.
            """
            exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()

            self.sendData((
                RPC_ERROR,
                request_id,
                (exceptionType.__name__,
                exceptionValue.args[0] if len(exceptionValue.args) == 1 else "",
                "".join(traceback.format_tb(exceptionTraceback)))
            ))

        if method == "daemon.login":
            # This is a special case and used in the initial connection process
            # We need to authenticate the user here
            try:
                ret = component.get("AuthManager").authorize(*args, **kwargs)
                if ret:
                    self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
                    self.factory.session_protocols[self.transport.sessionno] = self
            except Exception, e:
                sendError()
                log.exception(e)
            else:
                self.sendData((RPC_RESPONSE, request_id, (ret)))
                if not ret:
                    self.transport.loseConnection()
            finally:
Example #19
0
    def dispatch(self, request_id, method, args, kwargs):
        """
        This method is run when a RPC Request is made.  It will run the local method
        and will send either a RPC Response or RPC Error back to the client.

        :param request_id: the request_id from the client (sent in the RPC Request)
        :type request_id: int
        :param method: the local method to call. It must be registered with
            the :class:`RPCServer`.
        :type method: str
        :param args: the arguments to pass to `method`
        :type args: list
        :param kwargs: the keyword-arguments to pass to `method`
        :type kwargs: dict

        """
        def sendError():
            """
            Sends an error response with the contents of the exception that was raised.
            """
            exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()

            self.sendData((RPC_ERROR, request_id,
                           (exceptionType.__name__, exceptionValue.args[0]
                            if len(exceptionValue.args) == 1 else "",
                            "".join(traceback.format_tb(exceptionTraceback)))))

        if method == "daemon.login":
            # This is a special case and used in the initial connection process
            # We need to authenticate the user here
            try:
                ret = component.get("AuthManager").authorize(*args, **kwargs)
                if ret:
                    self.factory.authorized_sessions[
                        self.transport.sessionno] = (ret, args[0])
                    self.factory.session_protocols[
                        self.transport.sessionno] = self
            except Exception, e:
                sendError()
                log.exception(e)
            else:
                self.sendData((RPC_RESPONSE, request_id, (ret)))
                if not ret:
                    self.transport.loseConnection()
            finally:
Example #20
0
 def on_show(self, widget=None, data=None):
     try:
         for child in self.sub_menu.get_children():
             self.sub_menu.remove(child)
         # TODO: Make thise times customizable, and/or add a custom popup
         for time in (None, 1, 2, 3, 7, 14, 30):
             if time is None:
                 item = gtk.MenuItem('Never')
             else:
                 item = gtk.MenuItem(str(time) + ' days')
             item.connect("activate", self.on_select_time, time)
             self.sub_menu.append(item)
         item = gtk.MenuItem('Custom')
         item.connect('activate', self.on_custom_time)
         self.sub_menu.append(item)
         self.show_all()
     except Exception, e:
         log.exception('AHH!')
Example #21
0
    def move_storage(self, dest):
        """Move a torrent's storage location"""

        # Attempt to convert utf8 path to unicode
        # Note: Inconsistent encoding for 'dest', needs future investigation
        try:
           dest_u = unicode(dest, "utf-8")
        except TypeError:
           # String is already unicode
           dest_u = dest

        if not os.path.exists(dest_u):
            try:
                # Try to make the destination path if it doesn't exist
                os.makedirs(dest_u)
            except IOError, e:
                log.exception(e)
                log.error("Could not move storage for torrent %s since %s does not exist and could not create the directory.", self.torrent_id, dest_u)
                return False
Example #22
0
    def add_torrent_file(self, filename, filedump, options):
        """
        Adds a torrent file to the session.

        :param filename: the filename of the torrent
        :type filename: string
        :param filedump:  a base64 encoded string of the torrent file contents
        :type filedump: string
        :param options: the options to apply to the torrent on add
        :type options: dict

        :returns: the torrent_id as a str or None
        :rtype: string

        """
        try:
            filedump = base64.decodestring(filedump)
        except Exception, e:
            log.error("There was an error decoding the filedump string!")
            log.exception(e)
Example #23
0
    def add_torrent_file(self, filename, filedump, options):
        """
        Adds a torrent file to the session.

        :param filename: the filename of the torrent
        :type filename: string
        :param filedump:  a base64 encoded string of the torrent file contents
        :type filedump: string
        :param options: the options to apply to the torrent on add
        :type options: dict

        :returns: the torrent_id as a str or None
        :rtype: string

        """
        try:
            filedump = base64.decodestring(filedump)
        except Exception, e:
            log.error("There was an error decoding the filedump string!")
            log.exception(e)
Example #24
0
class Config(object):
    """
    This class is used to access/create/modify config files

    :param filename: the name of the config file
    :param defaults: dictionary of default values
    :param config_dir: the path to the config directory

    """
    def __init__(self, filename, defaults=None, config_dir=None):
        self.__config = {}
        self.__set_functions = {}
        self.__change_callbacks = []

        # These hold the version numbers and they will be set when loaded
        self.__version = {"format": 1, "file": 1}

        # This will get set with a reactor.callLater whenever a config option
        # is set.
        self._save_timer = None

        if defaults:
            for key, value in defaults.iteritems():
                self.set_item(key, value)

        # Load the config from file in the config_dir
        if config_dir:
            self.__config_file = os.path.join(config_dir, filename)
        else:
            self.__config_file = deluge.common.get_default_config_dir(filename)

        self.load()

    def __contains__(self, item):
        return item in self.__config

    def __setitem__(self, key, value):
        """
        See
        :meth:`set_item`
        """

        return self.set_item(key, value)

    def set_item(self, key, value):
        """
        Sets item 'key' to 'value' in the config dictionary, but does not allow
        changing the item's type unless it is None.  If the types do not match,
        it will attempt to convert it to the set type before raising a ValueError.

        :param key: string, item to change to change
        :param value: the value to change item to, must be same type as what is currently in the config

        :raises ValueError: raised when the type of value is not the same as\
what is currently in the config and it could not convert the value

        **Usage**

        >>> config = Config("test.conf")
        >>> config["test"] = 5
        >>> config["test"]
        5

        """
        if isinstance(value, basestring):
            value = deluge.common.utf8_encoded(value)

        if not self.__config.has_key(key):
            self.__config[key] = value
            log.debug("Setting '%s' to %s of %s", key, value, type(value))
            return

        if self.__config[key] == value:
            return

        # Do not allow the type to change unless it is None
        oldtype, newtype = type(self.__config[key]), type(value)

        if value is not None and oldtype != type(None) and oldtype != newtype:
            try:
                if oldtype == unicode:
                    value = oldtype(value, "utf8")
                elif oldtype == bool:
                    value = str_to_bool[value]
                else:
                    value = oldtype(value)
            except (ValueError, KeyError):
                log.warning("Type '%s' invalid for '%s'", newtype, key)
                raise

        log.debug("Setting '%s' to %s of %s", key, value, type(value))

        self.__config[key] = value
        # Run the set_function for this key if any
        from twisted.internet import reactor
        try:
            for func in self.__set_functions[key]:
                reactor.callLater(0, func, key, value)
        except KeyError:
            pass
        try:

            def do_change_callbacks(key, value):
                for func in self.__change_callbacks:
                    func(key, value)

            reactor.callLater(0, do_change_callbacks, key, value)
        except:
            pass

        # We set the save_timer for 5 seconds if not already set
        if not self._save_timer or not self._save_timer.active():
            self._save_timer = reactor.callLater(5, self.save)

    def __getitem__(self, key):
        """
        See
        :meth:`get_item`
        """
        return self.get_item(key)

    def get_item(self, key):
        """
        Gets the value of item 'key'

        :param key: the item for which you want it's value
        :return: the value of item 'key'

        :raises KeyError: if 'key' is not in the config dictionary

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> config["test"]
        5

        """
        if isinstance(self.__config[key], str):
            try:
                return self.__config[key].decode("utf8")
            except UnicodeDecodeError:
                return self.__config[key]
        else:
            return self.__config[key]

    def register_change_callback(self, callback):
        """
        Registers a callback function that will be called when a value is changed in the config dictionary

        :param callback: the function, callback(key, value)

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_change_callback(cb)

        """
        self.__change_callbacks.append(callback)

    def register_set_function(self, key, function, apply_now=True):
        """
        Register a function to be called when a config value changes

        :param key: the item to monitor for change
        :param function: the function to call when the value changes, f(key, value)
        :keyword apply_now: if True, the function will be called after it's registered

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_set_function("test", cb, apply_now=True)
        test 5

        """
        log.debug("Registering function for %s key..", key)
        if key not in self.__set_functions:
            self.__set_functions[key] = []

        self.__set_functions[key].append(function)

        # Run the function now if apply_now is set
        if apply_now:
            function(key, self.__config[key])
        return

    def apply_all(self):
        """
        Calls all set functions

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_set_function("test", cb, apply_now=False)
        >>> config.apply_all()
        test 5

        """
        log.debug("Calling all set functions..")
        for key, value in self.__set_functions.iteritems():
            for func in value:
                func(key, self.__config[key])

    def apply_set_functions(self, key):
        """
        Calls set functions for `:param:key`.

        :param key: str, the config key

        """
        log.debug("Calling set functions for key %s..", key)
        if key in self.__set_functions:
            for func in self.__set_functions[key]:
                func(key, self.__config[key])

    def load(self, filename=None):
        """
        Load a config file

        :param filename: if None, uses filename set in object initialization


        """
        if not filename:
            filename = self.__config_file

        try:
            data = open(filename, "rb").read()
        except IOError, e:
            log.warning("Unable to open config file %s: %s", filename, e)
            return

        objects = find_json_objects(data)

        if not len(objects):
            # No json objects found, try depickling it
            try:
                self.__config.update(pickle.loads(data))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
Example #25
0
        objects = find_json_objects(data)

        if not len(objects):
            # No json objects found, try depickling it
            try:
                self.__config.update(pickle.loads(data))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
        elif len(objects) == 1:
            start, end = objects[0]
            try:
                self.__config.update(json.loads(data[start:end]))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
        elif len(objects) == 2:
            try:
                start, end = objects[0]
                self.__version.update(json.loads(data[start:end]))
                start, end = objects[1]
                self.__config.update(json.loads(data[start:end]))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)

        log.debug("Config %s version: %s.%s loaded: %s", filename,
                  self.__version["format"], self.__version["file"],
                  self.__config)
Example #26
0
            try:
                method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
                auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
                if auth_level < method_auth_requirement:
                    # This session is not allowed to call this method
                    log.debug("Session %s is trying to call a method it is not authorized to call!", self.transport.sessionno)
                    raise NotAuthorizedError("Auth level too low: %s < %s" % (auth_level, method_auth_requirement))
                # Set the session_id in the factory so that methods can know
                # which session is calling it.
                self.factory.session_id = self.transport.sessionno
                ret = self.factory.methods[method](*args, **kwargs)
            except Exception, e:
                sendError()
                # Don't bother printing out DelugeErrors, because they are just for the client
                if not isinstance(e, DelugeError):
                    log.exception("Exception calling RPC request: %s", e)
            else:
                # Check if the return value is a deferred, since we'll need to
                # wait for it to fire before sending the RPC_RESPONSE
                if isinstance(ret, defer.Deferred):
                    def on_success(result):
                        self.sendData((RPC_RESPONSE, request_id, result))
                        return result

                    def on_fail(failure):
                        try:
                            failure.raiseException()
                        except Exception, e:
                            sendError()
                        return failure
Example #27
0
 def __init__(self, args):
     component.Component.__init__(self, "IPCInterface")
     ipc_dir = deluge.configmanager.get_config_dir("ipc")
     if not os.path.exists(ipc_dir):
         os.makedirs(ipc_dir)
     socket = os.path.join(ipc_dir, "deluge-gtk")
     if deluge.common.windows_check():
         # If we're on windows we need to check the global mutex to see if deluge is
         # already running.
         import win32event
         import win32api
         import winerror
         self.mutex = win32event.CreateMutex(None, False, "deluge")
         if win32api.GetLastError() != winerror.ERROR_ALREADY_EXISTS:
             # Create listen socket
             self.factory = Factory()
             self.factory.protocol = IPCProtocolServer
             import random
             port = random.randrange(20000, 65535)
             reactor.listenTCP(port, self.factory)
             # Store the port number in the socket file
             open(socket, "w").write(str(port))
             # We need to process any args when starting this process
             process_args(args)
         else:
             # Send to existing deluge process
             port = int(open(socket, "r").readline())
             self.factory = ClientFactory()
             self.factory.args = args
             self.factory.protocol = IPCProtocolClient
             reactor.connectTCP("127.0.0.1", port, self.factory)
             reactor.run()
             sys.exit(0)
     else:
         # Find and remove any restart tempfiles
         old_tempfile = glob(os.path.join(ipc_dir, 'tmp*deluge'))
         for f in old_tempfile:
             os.remove(f)
         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
             reactor.listenUNIX(socket, self.factory, wantPID=True)
         except twisted.internet.error.CannotListenError, e:
             log.info("Deluge is already running! Sending arguments to running instance...")
             self.factory = IPCClientFactory()
             self.factory.args = args
             reactor.connectUNIX(socket, self.factory, checkPID=True)
             reactor.run()
             if self.factory.stop:
                 log.info("Success sending arguments to running Deluge.")
                 import gtk
                 gtk.gdk.notify_startup_complete()
                 sys.exit(0)
             else:
                 if old_tempfile:
                     log.error("Deluge restart failed: %s", e)
                     sys.exit(1)
                 else:
                     log.warning('Restarting Deluge... (%s)', e)
                     # Create a tempfile to keep track of restart
                     mkstemp('deluge', dir=ipc_dir)
                     os.execv(sys.argv[0], sys.argv)
Example #28
0
class Client(object):
    """
    This class is used to connect to a daemon process and issue RPC requests.
    """

    __event_handlers = {}

    def __init__(self):
        self._daemon_proxy = None
        self.disconnect_callback = None
        self.__started_in_classic = False

    def connect(self, host="127.0.0.1", port=58846, username="", password=""):
        """
        Connects to a daemon process.

        :param host: str, the hostname of the daemon
        :param port: int, the port of the daemon
        :param username: str, the username to login with
        :param password: str, the password to login with

        :returns: a Deferred object that will be called once the connection
            has been established or fails
        """
        if not username and host in ("127.0.0.1", "localhost"):
            # No username was provided and it's the localhost, so we can try
            # to grab the credentials from the auth file.
            import common
            username, password = common.get_localhost_auth()

        self._daemon_proxy = DaemonSSLProxy(dict(self.__event_handlers))
        self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
        d = self._daemon_proxy.connect(host, port, username, password)

        def on_connect_fail(result):
            log.debug("on_connect_fail: %s", result)
            self.disconnect()
            return result

        d.addErrback(on_connect_fail)
        return d

    def disconnect(self):
        """
        Disconnects from the daemon.
        """
        if self._daemon_proxy:
            return self._daemon_proxy.disconnect()

    def start_classic_mode(self):
        """
        Starts a daemon in the same process as the client.
        """
        self._daemon_proxy = DaemonClassicProxy(self.__event_handlers)
        self.__started_in_classic = True

    def start_daemon(self, port, config):
        """
        Starts a daemon process.

        :param port: the port for the daemon to listen on
        :type port: int
        :param config: the path to the current config folder
        :type config: str
        :returns: True if started, False if not
        :rtype: bool

        :raises OSError: received from subprocess.call()

        """
        try:
            if deluge.common.windows_check():
                subprocess.Popen(
                    ["deluged",
                     "--port=%s" % port,
                     "--config=%s" % config])
            elif deluge.common.osx_check():
                subprocess.call([
                    "nohup", "deluged",
                    "--port=%s" % port,
                    "--config=%s" % config
                ])
            else:
                subprocess.call(
                    ["deluged",
                     "--port=%s" % port,
                     "--config=%s" % config])
        except OSError, e:
            from errno import ENOENT
            if e.errno == ENOENT:
                log.error(
                    _("Deluge cannot find the 'deluged' executable, it is likely \
that you forgot to install the deluged package or it's not in your PATH."))
            else:
                log.exception(e)
            raise e
        except Exception, e:
            log.error("Unable to start daemon!")
            log.exception(e)
            return False
Example #29
0
 def __init__(self, args):
     component.Component.__init__(self, "IPCInterface")
     ipc_dir = deluge.configmanager.get_config_dir("ipc")
     if not os.path.exists(ipc_dir):
         os.makedirs(ipc_dir)
     socket = os.path.join(ipc_dir, "deluge-gtk")
     if deluge.common.windows_check():
         # If we're on windows we need to check the global mutex to see if deluge is
         # already running.
         import win32event
         import win32api
         import winerror
         self.mutex = win32event.CreateMutex(None, False, "deluge")
         if win32api.GetLastError() != winerror.ERROR_ALREADY_EXISTS:
             # Create listen socket
             self.factory = Factory()
             self.factory.protocol = IPCProtocolServer
             import random
             port = random.randrange(20000, 65535)
             reactor.listenTCP(port, self.factory)
             # Store the port number in the socket file
             open(socket, "w").write(str(port))
             # We need to process any args when starting this process
             process_args(args)
         else:
             # Send to existing deluge process
             port = int(open(socket, "r").readline())
             self.factory = ClientFactory()
             self.factory.args = args
             self.factory.protocol = IPCProtocolClient
             reactor.connectTCP("127.0.0.1", port, self.factory)
             reactor.run()
             sys.exit(0)
     else:
         # Find and remove any restart tempfiles
         old_tempfile = glob(os.path.join(ipc_dir, 'tmp*deluge'))
         for f in old_tempfile:
             os.remove(f)
         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
             reactor.listenUNIX(socket, self.factory, wantPID=True)
         except twisted.internet.error.CannotListenError, e:
             log.info(
                 "Deluge is already running! Sending arguments to running instance..."
             )
             self.factory = IPCClientFactory()
             self.factory.args = args
             reactor.connectUNIX(socket, self.factory, checkPID=True)
             reactor.run()
             if self.factory.stop:
                 log.info("Success sending arguments to running Deluge.")
                 import gtk
                 gtk.gdk.notify_startup_complete()
                 sys.exit(0)
             else:
                 if old_tempfile:
                     log.error("Deluge restart failed: %s", e)
                     sys.exit(1)
                 else:
                     log.warning('Restarting Deluge... (%s)', e)
                     # Create a tempfile to keep track of restart
                     mkstemp('deluge', dir=ipc_dir)
                     os.execv(sys.argv[0], sys.argv)
Example #30
0
 def disable(self):
     try:
         self.plugin.disable()
     except Exception, e:
         log.error("Unable to disable plugin!")
         log.exception(e)
Example #31
0
# Initialize gettext
try:
    locale.setlocale(locale.LC_ALL, '')
    if hasattr(locale, "bindtextdomain"):
        locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
    if hasattr(locale, "textdomain"):
        locale.textdomain("deluge")
    gettext.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
    gettext.textdomain("deluge")
    gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n"))
    gtk.glade.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
    gtk.glade.textdomain("deluge")
except Exception, e:
    log.error("Unable to initialize gettext/locale!")
    log.exception(e)
    import __builtin__
    __builtin__.__dict__["_"] = lambda x: x

import deluge.component as component
from deluge.ui.client import client
from mainwindow import MainWindow
from menubar import MenuBar
from toolbar import ToolBar
from torrentview import TorrentView
from torrentdetails import TorrentDetails
from sidebar import SideBar
from filtertreeview import FilterTreeView
from preferences import Preferences
from systemtray import SystemTray
from statusbar import StatusBar
Example #32
0
                    # This session is not allowed to call this method
                    log.debug(
                        "Session %s is trying to call a method it is not authorized to call!",
                        self.transport.sessionno)
                    raise NotAuthorizedError(
                        "Auth level too low: %s < %s" %
                        (auth_level, method_auth_requirement))
                # Set the session_id in the factory so that methods can know
                # which session is calling it.
                self.factory.session_id = self.transport.sessionno
                ret = self.factory.methods[method](*args, **kwargs)
            except Exception, e:
                sendError()
                # Don't bother printing out DelugeErrors, because they are just for the client
                if not isinstance(e, DelugeError):
                    log.exception("Exception calling RPC request: %s", e)
            else:
                # Check if the return value is a deferred, since we'll need to
                # wait for it to fire before sending the RPC_RESPONSE
                if isinstance(ret, defer.Deferred):

                    def on_success(result):
                        self.sendData((RPC_RESPONSE, request_id, result))
                        return result

                    def on_fail(failure):
                        try:
                            failure.raiseException()
                        except Exception, e:
                            sendError()
                        return failure