Move deluge errors to the errors module, they will be reused later on other parts of code.
Now, calling connect on client has two behaviours, if username/password is passed the client connects, authenticates and returns daemon info, if username/password is not passed, only the daemon info is returned. This might change a bit later on though.
This commit is contained in:
parent
e17c035521
commit
b2a16a0240
|
@ -198,6 +198,8 @@ class Daemon(object):
|
||||||
|
|
||||||
:returns: str, the version number
|
:returns: str, the version number
|
||||||
"""
|
"""
|
||||||
|
print '\n\ndaemon.info called\n\n'
|
||||||
|
|
||||||
return deluge.common.get_version()
|
return deluge.common.get_version()
|
||||||
|
|
||||||
@export()
|
@export()
|
||||||
|
|
|
@ -55,7 +55,8 @@ except ImportError:
|
||||||
|
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
import deluge.configmanager
|
import deluge.configmanager
|
||||||
from deluge.core.authmanager import AUTH_LEVEL_NONE, AUTH_LEVEL_DEFAULT
|
from deluge.core.authmanager import AUTH_LEVEL_NONE, AUTH_LEVEL_DEFAULT, AUTH_LEVEL_ADMIN
|
||||||
|
from deluge.error import DelugeError, NotAuthorizedError
|
||||||
|
|
||||||
RPC_RESPONSE = 1
|
RPC_RESPONSE = 1
|
||||||
RPC_ERROR = 2
|
RPC_ERROR = 2
|
||||||
|
@ -117,12 +118,6 @@ def format_request(call):
|
||||||
else:
|
else:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
class DelugeError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class NotAuthorizedError(DelugeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ServerContextFactory(object):
|
class ServerContextFactory(object):
|
||||||
def getContext(self):
|
def getContext(self):
|
||||||
"""
|
"""
|
||||||
|
@ -253,24 +248,10 @@ class DelugeRPCProtocol(Protocol):
|
||||||
"".join(traceback.format_tb(exceptionTraceback)))
|
"".join(traceback.format_tb(exceptionTraceback)))
|
||||||
))
|
))
|
||||||
|
|
||||||
if method == "daemon.peek":
|
if method == "daemon.info":
|
||||||
# This is a special case and used in the initial connection process
|
# This is a special case and used in the initial connection process
|
||||||
# We need to peek the user here in order to get an auth level back
|
self.sendData((RPC_RESPONSE, request_id, deluge.common.get_version()))
|
||||||
# and see if the user exists.
|
return
|
||||||
try:
|
|
||||||
ret = component.get("AuthManager").peek(*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:
|
|
||||||
return
|
|
||||||
elif method == "daemon.login":
|
elif method == "daemon.login":
|
||||||
# This is a special case and used in the initial connection process
|
# This is a special case and used in the initial connection process
|
||||||
# We need to authenticate the user here
|
# We need to authenticate the user here
|
||||||
|
@ -374,6 +355,7 @@ class RPCServer(component.Component):
|
||||||
# Holds the interested event list for the sessions
|
# Holds the interested event list for the sessions
|
||||||
self.factory.interested_events = {}
|
self.factory.interested_events = {}
|
||||||
|
|
||||||
|
self.listen = listen
|
||||||
if not listen:
|
if not listen:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -458,6 +440,8 @@ class RPCServer(component.Component):
|
||||||
:rtype: string
|
:rtype: string
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if not self.listen:
|
||||||
|
return "localclient"
|
||||||
session_id = self.get_session_id()
|
session_id = self.get_session_id()
|
||||||
if session_id > -1 and session_id in self.factory.authorized_sessions:
|
if session_id > -1 and session_id in self.factory.authorized_sessions:
|
||||||
return self.factory.authorized_sessions[session_id][1]
|
return self.factory.authorized_sessions[session_id][1]
|
||||||
|
@ -472,6 +456,8 @@ class RPCServer(component.Component):
|
||||||
:returns: the auth level
|
:returns: the auth level
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
|
if not self.listen:
|
||||||
|
return AUTH_LEVEL_ADMIN
|
||||||
return self.factory.authorized_sessions[self.get_session_id()][0]
|
return self.factory.authorized_sessions[self.get_session_id()][0]
|
||||||
|
|
||||||
def get_rpc_auth_level(self, rpc):
|
def get_rpc_auth_level(self, rpc):
|
||||||
|
|
|
@ -48,3 +48,14 @@ class InvalidTorrentError(DelugeError):
|
||||||
|
|
||||||
class InvalidPathError(DelugeError):
|
class InvalidPathError(DelugeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class NotAuthorizedError(DelugeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BadLoginError(DelugeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AuthenticationRequired(BadLoginError):
|
||||||
|
def __init__(self, message, username):
|
||||||
|
super(AuthenticationRequired, self).__init__(message)
|
||||||
|
self.username = username
|
||||||
|
|
|
@ -261,27 +261,7 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
self.disconnect_deferred = None
|
self.disconnect_deferred = None
|
||||||
self.disconnect_callback = None
|
self.disconnect_callback = None
|
||||||
|
|
||||||
def peek(self, host, port, username):
|
def connect(self, host, port):
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.__connector = reactor.connectSSL(self.host, self.port, self.__factory, ssl.ClientContextFactory())
|
|
||||||
self.connect_deferred = defer.Deferred()
|
|
||||||
self.peek_deferred = defer.Deferred()
|
|
||||||
|
|
||||||
def on_connect(result, username):
|
|
||||||
self.__login_deferred = self.call("daemon.peek", username)
|
|
||||||
self.__login_deferred.addCallback(self.__on_peek, username)
|
|
||||||
self.__login_deferred.addErrback(self.__on_peek_fail)
|
|
||||||
|
|
||||||
def on_connect_fail(reason):
|
|
||||||
log.debug("connect_fail: %s", reason)
|
|
||||||
self.peek_deferred.errback(reason)
|
|
||||||
|
|
||||||
self.connect_deferred.addCallback(on_connect, username)
|
|
||||||
self.connect_deferred.addErrback(on_connect_fail)
|
|
||||||
return self.peek_deferred
|
|
||||||
|
|
||||||
def connect(self, host, port, username, password):
|
|
||||||
"""
|
"""
|
||||||
Connects to a daemon at host:port
|
Connects to a daemon at host:port
|
||||||
|
|
||||||
|
@ -298,13 +278,13 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.__connector = reactor.connectSSL(self.host, self.port, self.__factory, ssl.ClientContextFactory())
|
self.__connector = reactor.connectSSL(self.host, self.port, self.__factory, ssl.ClientContextFactory())
|
||||||
self.connect_deferred = defer.Deferred()
|
self.connect_deferred = defer.Deferred()
|
||||||
self.login_deferred = defer.Deferred()
|
self.daemon_info_deferred = defer.Deferred()
|
||||||
|
|
||||||
# Upon connect we do a 'daemon.login' RPC
|
# Upon connect we do a 'daemon.login' RPC
|
||||||
self.connect_deferred.addCallback(self.__on_connect, username, password)
|
self.connect_deferred.addCallback(self.__on_connect)
|
||||||
self.connect_deferred.addErrback(self.__on_connect_fail)
|
self.connect_deferred.addErrback(self.__on_connect_fail)
|
||||||
|
|
||||||
return self.login_deferred
|
return self.daemon_info_deferred
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
log.debug("sslproxy.disconnect()")
|
log.debug("sslproxy.disconnect()")
|
||||||
|
@ -418,19 +398,37 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
log.error(msg)
|
log.error(msg)
|
||||||
return error_data
|
return error_data
|
||||||
|
|
||||||
def __on_connect(self, result, username, password):
|
def __on_connect(self, result):
|
||||||
log.debug("__on_connect called")
|
log.debug("__on_connect called")
|
||||||
self.__login_deferred = self.call("daemon.login", username, password)
|
|
||||||
self.__login_deferred.addCallback(self.__on_login, username)
|
def on_info(daemon_info):
|
||||||
self.__login_deferred.addErrback(self.__on_login_fail)
|
self.daemon_info = daemon_info
|
||||||
|
log.debug("Got info from daemon: %s", daemon_info)
|
||||||
|
self.daemon_info_deferred.callback(daemon_info)
|
||||||
|
|
||||||
|
def on_info_fail(reason):
|
||||||
|
log.debug("Failed to get info from daemon: %s", reason)
|
||||||
|
self.daemon_info_deferred.errback(reason)
|
||||||
|
|
||||||
|
self.call("daemon.info").addCallback(on_info).addErrback(on_info_fail)
|
||||||
|
return self.daemon_info_deferred
|
||||||
|
|
||||||
def __on_connect_fail(self, reason):
|
def __on_connect_fail(self, reason):
|
||||||
log.debug("__on_connect_fail called")
|
log.debug("__on_connect_fail called")
|
||||||
log.debug("connect_fail: %s", reason)
|
log.debug("connect_fail: %s", reason)
|
||||||
self.login_deferred.errback(reason)
|
log.exception(reason)
|
||||||
|
self.daemon_info_deferred.errback(reason)
|
||||||
|
|
||||||
|
def authenticate(self, username, password):
|
||||||
|
log.debug("%s.authenticate: %s", self.__class__.__name__, username)
|
||||||
|
self.login_deferred = defer.Deferred()
|
||||||
|
d = self.call("daemon.login", username, password)
|
||||||
|
d.addCallback(self.__on_login, username)
|
||||||
|
d.addErrback(self.__on_login_fail)
|
||||||
|
return self.login_deferred
|
||||||
|
|
||||||
def __on_login(self, result, username):
|
def __on_login(self, result, username):
|
||||||
log.debug("__on_login called")
|
log.debug("__on_login called: %s %s", username, result)
|
||||||
self.username = username
|
self.username = username
|
||||||
# We need to tell the daemon what events we're interested in receiving
|
# We need to tell the daemon what events we're interested in receiving
|
||||||
if self.__factory.event_handlers:
|
if self.__factory.event_handlers:
|
||||||
|
@ -441,15 +439,6 @@ class DaemonSSLProxy(DaemonProxy):
|
||||||
log.debug("_on_login_fail(): %s", result)
|
log.debug("_on_login_fail(): %s", result)
|
||||||
self.login_deferred.errback(result)
|
self.login_deferred.errback(result)
|
||||||
|
|
||||||
def __on_peek(self, result, username):
|
|
||||||
log.debug("__on_peek called. result: %s", result)
|
|
||||||
self.username = username
|
|
||||||
self.peek_deferred.callback(result)
|
|
||||||
|
|
||||||
def __on_peek_fail(self, result):
|
|
||||||
log.debug("__on_peek_fail called. result: %s", result)
|
|
||||||
self.peek_deferred.errback(result)
|
|
||||||
|
|
||||||
def set_disconnect_callback(self, cb):
|
def set_disconnect_callback(self, cb):
|
||||||
"""
|
"""
|
||||||
Set a function to be called when the connection to the daemon is lost
|
Set a function to be called when the connection to the daemon is lost
|
||||||
|
@ -471,7 +460,10 @@ class DaemonClassicProxy(DaemonProxy):
|
||||||
self.connected = True
|
self.connected = True
|
||||||
self.host = "localhost"
|
self.host = "localhost"
|
||||||
self.port = 58846
|
self.port = 58846
|
||||||
|
# Running in classic mode, it's safe to import auth level
|
||||||
|
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
|
||||||
self.username = "localclient"
|
self.username = "localclient"
|
||||||
|
self.authentication_level = AUTH_LEVEL_ADMIN
|
||||||
# Register the event handlers
|
# Register the event handlers
|
||||||
for event in event_handlers:
|
for event in event_handlers:
|
||||||
for handler in event_handlers[event]:
|
for handler in event_handlers[event]:
|
||||||
|
@ -574,32 +566,55 @@ class Client(object):
|
||||||
|
|
||||||
self._daemon_proxy = DaemonSSLProxy(dict(self.__event_handlers))
|
self._daemon_proxy = DaemonSSLProxy(dict(self.__event_handlers))
|
||||||
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
|
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
|
||||||
d = self._daemon_proxy.connect(host, port, username, password)
|
d = self._daemon_proxy.connect(host, port)
|
||||||
def on_connect_fail(result):
|
def on_connect_fail(result):
|
||||||
log.debug("on_connect_fail: %s", result)
|
log.debug("on_connect_fail: %s", result)
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
d.addErrback(on_connect_fail)
|
d.addErrback(on_connect_fail)
|
||||||
|
|
||||||
|
if username or password:
|
||||||
|
auth_deferred = defer.Deferred()
|
||||||
|
|
||||||
|
def on_authenticate(result, daemon_info):
|
||||||
|
log.debug("Authentication sucessfull: %s", result)
|
||||||
|
self.authentication_level = result
|
||||||
|
auth_deferred.callback(daemon_info)
|
||||||
|
|
||||||
|
def on_authenticate_fail(reason):
|
||||||
|
log.debug("Failed to authenticate")
|
||||||
|
log.exception(reason)
|
||||||
|
auth_deferred.errback(reason)
|
||||||
|
|
||||||
|
def on_connected(daemon_version):
|
||||||
|
log.debug("Client.connect.on_connected: %s", daemon_version)
|
||||||
|
print 1234, self._daemon_proxy
|
||||||
|
d = self._daemon_proxy.authenticate(username, password)
|
||||||
|
print 1234, d
|
||||||
|
d.addCallback(on_authenticate, daemon_version)
|
||||||
|
d.addErrback(on_authenticate_fail)
|
||||||
|
# return d
|
||||||
|
|
||||||
|
d.addCallback(on_connected)
|
||||||
|
return auth_deferred
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def peek(self, host="127.0.0.1", port=58846, username=""):
|
|
||||||
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))
|
# def authenticate(self, username="", password=""):
|
||||||
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
|
# if not self.connected():
|
||||||
d = self._daemon_proxy.peek(host, port, username)
|
# raise Exception("You first need to call connect")
|
||||||
def on_connect_fail(result):
|
# if not username and self._daemon_proxy.host in ("127.0.0.1", "localhost"):
|
||||||
log.debug("on_connect_fail: %s", result)
|
# # No username was provided and it's the localhost, so we can try
|
||||||
self.disconnect()
|
# # to grab the credentials from the auth file.
|
||||||
return result
|
# import common
|
||||||
|
# username, password = common.get_localhost_auth()
|
||||||
d.addErrback(on_connect_fail)
|
#
|
||||||
return d
|
# def on_authenticate_fail(reason):
|
||||||
|
# log.debug("Failed to authenticate %s@%s:%s")
|
||||||
|
#
|
||||||
|
# d = self._daemon_proxy.authenticate(username, password)
|
||||||
|
# d.addErrback(on_authenticate_fail)
|
||||||
|
# return d
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
"""
|
"""
|
||||||
|
@ -646,6 +661,10 @@ class Client(object):
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def daemon_info(self):
|
||||||
|
return self._daemon_proxy.daemon_info_deferred
|
||||||
|
return defer.succeed(self._daemon_proxy.daemon_info or None)
|
||||||
|
|
||||||
def is_localhost(self):
|
def is_localhost(self):
|
||||||
"""
|
"""
|
||||||
Checks if the current connected host is a localhost or not.
|
Checks if the current connected host is a localhost or not.
|
||||||
|
|
|
@ -300,6 +300,7 @@ class ConnectionManager(component.Component):
|
||||||
row = self.__get_host_row(host_id)
|
row = self.__get_host_row(host_id)
|
||||||
if row:
|
if row:
|
||||||
row[HOSTLIST_COL_STATUS] = _("Offline")
|
row[HOSTLIST_COL_STATUS] = _("Offline")
|
||||||
|
# row[HOSTLIST_COL_VERSION] = ""
|
||||||
self.__update_buttons()
|
self.__update_buttons()
|
||||||
|
|
||||||
for row in self.liststore:
|
for row in self.liststore:
|
||||||
|
@ -307,22 +308,30 @@ class ConnectionManager(component.Component):
|
||||||
host = row[HOSTLIST_COL_HOST]
|
host = row[HOSTLIST_COL_HOST]
|
||||||
port = row[HOSTLIST_COL_PORT]
|
port = row[HOSTLIST_COL_PORT]
|
||||||
user = row[HOSTLIST_COL_USER]
|
user = row[HOSTLIST_COL_USER]
|
||||||
password = row[HOSTLIST_COL_PASS]
|
|
||||||
|
|
||||||
if client.connected() and \
|
if client.connected() and \
|
||||||
(host, port, "localclient" if not user and host in ("127.0.0.1", "localhost") else user) == client.connection_info():
|
(host, port, "localclient" if not user and host in ("127.0.0.1", "localhost") else user) == client.connection_info():
|
||||||
def on_info(info):
|
def on_info(info):
|
||||||
|
log.debug("\n\nClient connected, query info: %s:%s\n\n", info, self.running)
|
||||||
if not self.running:
|
if not self.running:
|
||||||
return
|
return
|
||||||
row[HOSTLIST_COL_VERSION] = info
|
row[HOSTLIST_COL_VERSION] = info
|
||||||
self.__update_buttons()
|
self.__update_buttons()
|
||||||
|
print row[HOSTLIST_COL_ID], row[HOSTLIST_COL_HOST], row[HOSTLIST_COL_PORT], row[HOSTLIST_COL_USER], row[HOSTLIST_COL_VERSION]
|
||||||
|
|
||||||
|
def on_info_fail(reason):
|
||||||
|
print '\n\n'
|
||||||
|
log.exception(reason)
|
||||||
|
print '\n\n'
|
||||||
|
|
||||||
row[HOSTLIST_COL_STATUS] = _("Connected")
|
row[HOSTLIST_COL_STATUS] = _("Connected")
|
||||||
client.daemon.info().addCallback(on_info)
|
log.debug("\n\nquery daemons info\n\n")
|
||||||
|
client.daemon.info().addCallback(on_info).addErrback(on_info_fail)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Create a new Client instance
|
# Create a new Client instance
|
||||||
c = deluge.ui.client.Client()
|
c = deluge.ui.client.Client()
|
||||||
d = c.peek(host, port, user)
|
d = c.connect(host, port)
|
||||||
d.addCallback(on_connect, c, host_id)
|
d.addCallback(on_connect, c, host_id)
|
||||||
d.addErrback(on_connect_failed, host_id)
|
d.addErrback(on_connect_failed, host_id)
|
||||||
|
|
||||||
|
@ -435,11 +444,11 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
||||||
details=traceback.format_exc(tb[2])).run()
|
details=traceback.format_exc(tb[2])).run()
|
||||||
|
|
||||||
# Signal handlers
|
# Signal handlers
|
||||||
def __connect(self, host_id, host, port, user, password):
|
def __connect(self, host_id, host, port, username, password):
|
||||||
def do_connect(*args):
|
def do_connect(*args):
|
||||||
d = client.connect(host, port, user, password)
|
d = client.connect(host, port, username, password)
|
||||||
d.addCallback(self.__on_connected, host_id)
|
d.addCallback(self.__on_connected, host_id)
|
||||||
d.addErrback(self.__on_connected_failed, host_id, host, port, user)
|
d.addErrback(self.__on_connected_failed, host_id, host, port, username)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
if client.connected():
|
if client.connected():
|
||||||
|
@ -447,16 +456,25 @@ that you forgot to install the deluged package or it's not in your PATH.")).run(
|
||||||
else:
|
else:
|
||||||
return do_connect()
|
return do_connect()
|
||||||
|
|
||||||
def __on_connected(self, connector, host_id):
|
def __on_connected(self, daemon_info, host_id):
|
||||||
log.debug("__on_connected called")
|
# log.debug("__on_connected called for hostid: %s connector: %s",
|
||||||
|
# host_id, daemon_info)
|
||||||
if self.gtkui_config["autoconnect"]:
|
if self.gtkui_config["autoconnect"]:
|
||||||
self.gtkui_config["autoconnect_host_id"] = host_id
|
self.gtkui_config["autoconnect_host_id"] = host_id
|
||||||
|
|
||||||
|
# row = self.__get_host_row(host_id)
|
||||||
|
# row[HOSTLIST_COL_STATUS] = _("Connected")
|
||||||
|
# row[HOSTLIST_COL_VERSION] = daemon_info
|
||||||
|
#
|
||||||
|
# # Update the status of the hosts
|
||||||
|
# self.__update_list()
|
||||||
|
|
||||||
self.connection_manager.response(gtk.RESPONSE_OK)
|
self.connection_manager.response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
component.start()
|
component.start()
|
||||||
|
|
||||||
def __on_connected_failed(self, reason, host_id, host, port, user):
|
def __on_connected_failed(self, reason, host_id, host, port, user):
|
||||||
|
log.exception(reason)
|
||||||
if reason.value.exception_type == "PasswordRequired":
|
if reason.value.exception_type == "PasswordRequired":
|
||||||
log.debug("PasswordRequired exception")
|
log.debug("PasswordRequired exception")
|
||||||
dialog = dialogs.AuthenticationDialog(reason.value.exception_msg)
|
dialog = dialogs.AuthenticationDialog(reason.value.exception_msg)
|
||||||
|
|
Loading…
Reference in New Issue