Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- # # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me> # # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. #
""" This object is created whenever there is a RPCRequest to be sent to the daemon. It is generally only used by the DaemonProxy's call method. """
""" Returns a string of the RPCRequest in the following form: method(arg, kwarg=foo, ...) """
""" Returns a properly formatted RPCRequest based on the properties. Will raise a TypeError if the properties haven't been set yet.
:returns: a properly formated RPCRequest """ raise TypeError("You must set the properties of this object before calling format_message!")
# Set the protocol in the daemon so it can send data # Get the address of the daemon that we've connected to
""" This method is called whenever we receive a message from the daemon.
:param request: a tuple that should be either a RPCResponse, RCPError or RPCSignal
""" log.debug("Received invalid message: type is not tuple") return log.debug("Received invalid message: number of items in " "response is %s", len(request)) return
event = request[1] # log.debug("Received RPCEvent: %s", event) # A RPCEvent was received from the daemon so run any handlers # associated with it. if event in self.factory.event_handlers: for handler in self.factory.event_handlers[event]: reactor.callLater(0, handler, *request[2]) return
# We get the Deferred object for this request_id to either run the # callbacks or the errbacks dependent on the response from the daemon.
# Run the callbacks registered with this Deferred object # Recreate exception and errback'it # The exception class is located in deluge.error except TypeError: log.warn("Received invalid RPC_ERROR (Old daemon?): %s", request[2]) return
# Ideally we would chain the deferreds instead of instance # checking just to log them. But, that would mean that any # errback on the fist deferred should returns it's failure # so it could pass back to the 2nd deferred on the chain. But, # that does not always happen. # So, just do some instance checking and just log rpc error at # diferent levels. msg += "\n" + exception.type + "\n" + exception.message + ": " msg += exception.traceback else:
# Let's log these as errors log.error(msg) else: # The rest just get's logged in debug level, just to log # what's happening except: import traceback log.error("Failed to handle RPC_ERROR (Old daemon?): %s\nLocal error: %s", request[2], traceback.format_exc())
""" Sends a RPCRequest to the server.
:param request: RPCRequest
""" # Store the DelugeRPCRequest object just in case a RPCError is sent in # response to this request. We use the extra information when printing # out the error for debugging purposes. # log.debug("Sending RPCRequest %s: %s", request.request_id, request) # Send the request in a tuple because multiple requests can be sent at once except Exception as ex: log.warn("Error occurred when sending message: %s", ex)
connector.host, connector.port)
log.warning("Connection to daemon at \"%s:%s\" failed: %s", connector.host, connector.port, reason.value) self.daemon.connect_deferred.errback(reason)
connector.host, connector.port, reason.value)
# This is set when a connection is made to the daemon
# This is set when a connection is made
""" Connects to a daemon at host:port
:param host: str, the host to connect to :param port: int, the listening port on the daemon
:returns: twisted.Deferred
""" self.__factory, ssl.ClientContextFactory())
# Upon connect we do a 'daemon.login' RPC
""" Makes a RPCRequest to the daemon. All methods should be in the form of 'component.method'.
:params method: str, the method to call in the form of 'component.method' :params args: the arguments to call the remote method with :params kwargs: the keyword arguments to call the remote method with
:return: a twisted.Deferred object that will be activated when a RPCResponse or RPCError is received from the daemon
""" # Create the DelugeRPCRequest to pass to protocol.send_request() # Send the request to the server # Create a Deferred object to return and add a default errback to print # the error.
# Store the Deferred until we receive a response from the daemon
# Increment the request counter since we don't want to use the same one # before a response is received.
""" Pops a Deferred object. This is generally called once we receive the reply we were waiting on from the server.
:param request_id: the request_id of the Deferred to pop :type request_id: int
"""
""" Registers a handler function to be called when `:param:event` is received from the daemon.
:param event: the name of the event to handle :type event: str :param handler: the function to be called when `:param:event` is emitted from the daemon :type handler: function
""" if event not in self.__factory.event_handlers: # This is a new event to handle, so we need to tell the daemon # that we're interested in receiving this type of event self.__factory.event_handlers[event] = [] if self.connected: self.call("daemon.set_event_interest", [event])
# Only add the handler if it's not already registered if handler not in self.__factory.event_handlers[event]: self.__factory.event_handlers[event].append(handler)
""" Deregisters a event handler.
:param event: the name of the event :type event: str :param handler: the function registered :type handler: function
""" if event in self.__factory.event_handlers and handler in self.__factory.event_handlers[event]: self.__factory.event_handlers[event].remove(handler)
log.debug("Failed to get info from daemon") log.exception(reason) self.daemon_info_deferred.errback(reason)
self.daemon_info_deferred.errback(reason)
client_version=deluge.common.get_version())
# We need to tell the daemon what events we're interested in receiving self.call("daemon.set_event_interest", self.__factory.event_handlers.keys())
self.call("core.get_auth_levels_mappings").addCallback( self.__on_auth_levels_mappings )
auth_levels_mapping, auth_levels_mapping_reverse = result self.auth_levels_mapping = auth_levels_mapping self.auth_levels_mapping_reverse = auth_levels_mapping_reverse
""" Set a function to be called when the connection to the daemon is lost for any reason. """
return self.protocol.get_bytes_recv()
return self.protocol.get_bytes_sent()
if event_handlers is None: event_handlers = {} import deluge.core.daemon self.__daemon = deluge.core.daemon.Daemon(classic=True) log.debug("daemon created!") self.connected = True self.host = "localhost" self.port = 58846 # Running in classic mode, it's safe to import auth level from deluge.core.authmanager import (AUTH_LEVEL_ADMIN, AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE) self.username = "localclient" self.authentication_level = AUTH_LEVEL_ADMIN self.auth_levels_mapping = AUTH_LEVELS_MAPPING self.auth_levels_mapping_reverse = AUTH_LEVELS_MAPPING_REVERSE # Register the event handlers for event in event_handlers: for handler in event_handlers[event]: self.__daemon.core.eventmanager.register_event_handler(event, handler)
self.connected = False self.__daemon = None
# log.debug("call: %s %s %s", method, args, kwargs)
import copy
try: m = self.__daemon.rpcserver.get_object_method(method) except Exception as ex: log.exception(ex) return defer.fail(ex) else: return defer.maybeDeferred( m, *copy.deepcopy(args), **copy.deepcopy(kwargs) )
""" Registers a handler function to be called when `:param:event` is received from the daemon.
:param event: the name of the event to handle :type event: str :param handler: the function to be called when `:param:event` is emitted from the daemon :type handler: function
""" self.__daemon.core.eventmanager.register_event_handler(event, handler)
""" Deregisters a event handler.
:param event: the name of the event :type event: str :param handler: the function registered :type handler: function
""" self.__daemon.core.eventmanager.deregister_event_handler(event, handler)
""" This is used for dotted name calls to client """
raise Exception("You must make calls in the form of 'component.method'!")
return RemoteMethod(self.daemon, self.base + "." + name)
""" This is used when something like 'client.core.get_something()' is attempted. """ return self.daemon.call(self.base, *args, **kwargs)
""" This class is used to connect to a daemon process and issue RPC requests. """
}
skip_authentication=False): """ 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 """
self.disconnect() return reason
daemon_version)
# No username provided and it's localhost, so attempt to get credentials from auth file.
""" Disconnects from the daemon. """ self._daemon_proxy.disconnect() self.stop_classic_mode() return
""" Starts a daemon in the same process as the client. """ self._daemon_proxy = DaemonClassicProxy(self.__event_handlers) self.__started_in_classic = True
""" Stops the daemon process in the client. """ self._daemon_proxy = None self.__started_in_classic = False
""" 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()
""" # subprocess.popen does not work with unicode args (with non-ascii characters) on windows config = config.encode(sys.getfilesystemencoding()) try: subprocess.Popen(["deluged", "--port=%s" % port, "--config=%s" % config]) except OSError as ex: from errno import ENOENT if ex.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(ex) raise ex except Exception as ex: log.error("Unable to start daemon!") log.exception(ex) return False else: return True
""" Checks if the current connected host is a localhost or not.
:returns: bool, True if connected to a localhost
""" if (self._daemon_proxy and self._daemon_proxy.host in ("127.0.0.1", "localhost") or isinstance(self._daemon_proxy, DaemonClassicProxy)): return True return False
""" Checks to see if the client has been started in classic mode.
:returns: bool, True if in classic mode
"""
""" Check to see if connected to a daemon.
:returns: bool, True if connected
""" return self._daemon_proxy.connected if self._daemon_proxy else False
""" Get some info about the connection or return None if not connected.
:returns: a tuple of (host, port, username) or None if not connected """ if self.connected(): return (self._daemon_proxy.host, self._daemon_proxy.port, self._daemon_proxy.username)
return None
""" Registers a handler that will be called when an event is received from the daemon.
:params event: str, the event to handle :params handler: func, the handler function, f(args) """ if event not in self.__event_handlers: self.__event_handlers[event] = [] self.__event_handlers[event].append(handler) # We need to replicate this in the daemon proxy if self._daemon_proxy: self._daemon_proxy.register_event_handler(event, handler)
""" Deregisters a event handler.
:param event: str, the name of the event :param handler: function, the function registered
""" if event in self.__event_handlers and handler in self.__event_handlers[event]: self.__event_handlers[event].remove(handler) if self._daemon_proxy: self._daemon_proxy.deregister_event_handler(event, handler)
# no-op for now.. we'll see if we need this in the future pass
""" Set a function to be called whenever the client is disconnected from the daemon for any reason. """ self.disconnect_callback = cb
self.disconnect_callback()
""" Returns the number of bytes received from the daemon.
:returns: the number of bytes received :rtype: int """ return self._daemon_proxy.get_bytes_recv()
""" Returns the number of bytes sent to the daemon.
:returns: the number of bytes sent :rtype: int """ return self._daemon_proxy.get_bytes_sent()
""" Returns the current authenticated username.
:returns: the authenticated username :rtype: str """ return self._daemon_proxy.username
""" Returns the authentication level the daemon returned upon authentication.
:returns: the authentication level :rtype: int """
def auth_levels_mapping(self): return self._daemon_proxy.auth_levels_mapping
def auth_levels_mapping_reverse(self): return self._daemon_proxy.auth_levels_mapping_reverse
# This is the object clients will use |