mirror of
https://github.com/codex-storage/deluge.git
synced 2025-02-26 18:10:43 +00:00
Extend RPC Protocol.
While adding the multiuser auth related stuff, RPC_AUTH_EVENT was added, simply to not touch how RPC_ERROR was handled. It was created to allow recreating the exception on the client side. Instead of adding another rpc event type, extend RPC_ERROR to send the proper data to recreate the exception on the client side.
This commit is contained in:
parent
e383187796
commit
9b812a4eec
@ -57,13 +57,12 @@ 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)
|
AUTH_LEVEL_ADMIN)
|
||||||
from deluge.error import (DelugeError, NotAuthorizedError, _PassthroughError,
|
from deluge.error import (DelugeError, NotAuthorizedError,
|
||||||
IncompatibleClient)
|
_ClientSideRecreateError, IncompatibleClient)
|
||||||
|
|
||||||
RPC_RESPONSE = 1
|
RPC_RESPONSE = 1
|
||||||
RPC_ERROR = 2
|
RPC_ERROR = 2
|
||||||
RPC_EVENT = 3
|
RPC_EVENT = 3
|
||||||
RPC_EVENT_EXCEPTION = 4
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -247,13 +246,13 @@ class DelugeRPCProtocol(Protocol):
|
|||||||
Sends an error response with the contents of the exception that was raised.
|
Sends an error response with the contents of the exception that was raised.
|
||||||
"""
|
"""
|
||||||
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
|
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
|
||||||
|
|
||||||
self.sendData((
|
self.sendData((
|
||||||
RPC_ERROR,
|
RPC_ERROR,
|
||||||
request_id,
|
request_id,
|
||||||
(exceptionType.__name__,
|
exceptionType.__name__,
|
||||||
exceptionValue.args[0] if len(exceptionValue.args) == 1 else "",
|
exceptionValue._args,
|
||||||
"".join(traceback.format_tb(exceptionTraceback)))
|
exceptionValue._kwargs,
|
||||||
|
"".join(traceback.format_tb(exceptionTraceback))
|
||||||
))
|
))
|
||||||
|
|
||||||
if method == "daemon.info":
|
if method == "daemon.info":
|
||||||
@ -273,14 +272,8 @@ class DelugeRPCProtocol(Protocol):
|
|||||||
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
||||||
self.factory.session_protocols[self.transport.sessionno] = self
|
self.factory.session_protocols[self.transport.sessionno] = self
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if isinstance(e, _PassthroughError):
|
|
||||||
self.sendData(
|
|
||||||
(RPC_EVENT_EXCEPTION, request_id,
|
|
||||||
e.__class__.__name__,
|
|
||||||
e._args, e._kwargs, args[0])
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
sendError()
|
sendError()
|
||||||
|
if not isinstance(e, _ClientSideRecreateError):
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
else:
|
else:
|
||||||
self.sendData((RPC_RESPONSE, request_id, (ret)))
|
self.sendData((RPC_RESPONSE, request_id, (ret)))
|
||||||
|
@ -36,7 +36,21 @@
|
|||||||
|
|
||||||
|
|
||||||
class DelugeError(Exception):
|
class DelugeError(Exception):
|
||||||
pass
|
def _get_message(self):
|
||||||
|
return self._message
|
||||||
|
def _set_message(self, message):
|
||||||
|
self._message = message
|
||||||
|
message = property(_get_message, _set_message)
|
||||||
|
del _get_message, _set_message
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.message
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
inst = super(DelugeError, cls).__new__(cls, *args, **kwargs)
|
||||||
|
inst._args = args
|
||||||
|
inst._kwargs = kwargs
|
||||||
|
return inst
|
||||||
|
|
||||||
class NoCoreError(DelugeError):
|
class NoCoreError(DelugeError):
|
||||||
pass
|
pass
|
||||||
@ -50,30 +64,18 @@ class InvalidTorrentError(DelugeError):
|
|||||||
class InvalidPathError(DelugeError):
|
class InvalidPathError(DelugeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class _PassthroughError(DelugeError):
|
class _ClientSideRecreateError(DelugeError):
|
||||||
|
pass
|
||||||
|
|
||||||
def _get_message(self):
|
class IncompatibleClient(_ClientSideRecreateError):
|
||||||
return self._message
|
|
||||||
def _set_message(self, message):
|
|
||||||
self._message = message
|
|
||||||
message = property(_get_message, _set_message)
|
|
||||||
del _get_message, _set_message
|
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
inst = super(_PassthroughError, cls).__new__(cls, *args, **kwargs)
|
|
||||||
inst._args = args
|
|
||||||
inst._kwargs = kwargs
|
|
||||||
return inst
|
|
||||||
|
|
||||||
class IncompatibleClient(_PassthroughError):
|
|
||||||
def __init__(self, daemon_version):
|
def __init__(self, daemon_version):
|
||||||
self.daemon_version = daemon_version
|
self.daemon_version = daemon_version
|
||||||
self.message = _(
|
self.message = _(
|
||||||
"Your deluge client is not compatible with the daemon. "
|
"Your deluge client is not compatible with the daemon. "
|
||||||
"Please upgrade your client to %(daemon_version)s"
|
"Please upgrade your client to %(daemon_version)s"
|
||||||
) % {'daemon_version': self.daemon_version}
|
) % dict(daemon_version=self.daemon_version)
|
||||||
|
|
||||||
class NotAuthorizedError(_PassthroughError):
|
class NotAuthorizedError(_ClientSideRecreateError):
|
||||||
|
|
||||||
def __init__(self, current_level, required_level):
|
def __init__(self, current_level, required_level):
|
||||||
self.message = _(
|
self.message = _(
|
||||||
@ -84,7 +86,7 @@ class NotAuthorizedError(_PassthroughError):
|
|||||||
self.required_level = required_level
|
self.required_level = required_level
|
||||||
|
|
||||||
|
|
||||||
class _UsernameBasedPasstroughError(_PassthroughError):
|
class _UsernameBasedPasstroughError(_ClientSideRecreateError):
|
||||||
|
|
||||||
def _get_username(self):
|
def _get_username(self):
|
||||||
return self._username
|
return self._username
|
||||||
|
@ -56,39 +56,12 @@ else:
|
|||||||
RPC_RESPONSE = 1
|
RPC_RESPONSE = 1
|
||||||
RPC_ERROR = 2
|
RPC_ERROR = 2
|
||||||
RPC_EVENT = 3
|
RPC_EVENT = 3
|
||||||
RPC_EVENT_EXCEPTION = 4
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def format_kwargs(kwargs):
|
def format_kwargs(kwargs):
|
||||||
return ", ".join([key + "=" + str(value) for key, value in kwargs.items()])
|
return ", ".join([key + "=" + str(value) for key, value in kwargs.items()])
|
||||||
|
|
||||||
class DelugeRPCError(object):
|
|
||||||
"""
|
|
||||||
This object is passed to errback handlers in the event of a RPCError from the
|
|
||||||
daemon.
|
|
||||||
"""
|
|
||||||
def __init__(self, method, args, kwargs, exception_type, exception_msg, traceback):
|
|
||||||
self.method = method
|
|
||||||
self.args = args
|
|
||||||
self.kwargs = kwargs
|
|
||||||
self.exception_type = exception_type
|
|
||||||
self.exception_msg = exception_msg
|
|
||||||
self.traceback = traceback
|
|
||||||
|
|
||||||
def logable(self):
|
|
||||||
# Create a delugerpcrequest to print out a nice RPCRequest string
|
|
||||||
r = DelugeRPCRequest()
|
|
||||||
r.method = self.method
|
|
||||||
r.args = self.args
|
|
||||||
r.kwargs = self.kwargs
|
|
||||||
msg = "RPCError Message Received!"
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
msg += "\n" + "RPCRequest: " + r.__repr__()
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
msg += "\n" + self.traceback + "\n" + self.exception_type + ": " + self.exception_msg
|
|
||||||
msg += "\n" + "-" * 80
|
|
||||||
return msg
|
|
||||||
|
|
||||||
class DelugeRPCRequest(object):
|
class DelugeRPCRequest(object):
|
||||||
"""
|
"""
|
||||||
@ -204,17 +177,29 @@ class DelugeRPCProtocol(Protocol):
|
|||||||
if message_type == RPC_RESPONSE:
|
if message_type == RPC_RESPONSE:
|
||||||
# Run the callbacks registered with this Deferred object
|
# Run the callbacks registered with this Deferred object
|
||||||
d.callback(request[2])
|
d.callback(request[2])
|
||||||
elif message_type == RPC_EVENT_EXCEPTION:
|
|
||||||
# Recreate exception and errback'it
|
|
||||||
d.errback(getattr(error, request[2])(*request[3], **request[4]))
|
|
||||||
elif message_type == RPC_ERROR:
|
elif message_type == RPC_ERROR:
|
||||||
# Create the DelugeRPCError to pass to the errback
|
# Recreate exception and errback'it
|
||||||
r = self.__rpc_requests[request_id]
|
exception_cls = getattr(error, request[2])
|
||||||
e = DelugeRPCError(r.method, r.args, r.kwargs, request[2][0],
|
exception = exception_cls(*request[3], **request[4])
|
||||||
request[2][1], request[2][2])
|
|
||||||
# Run the errbacks registered with this Deferred object
|
|
||||||
d.errback(e)
|
|
||||||
|
|
||||||
|
r = self.__rpc_requests[request_id]
|
||||||
|
msg = "RPCError Message Received!"
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
msg += "\n" + "RPCRequest: " + r.__repr__()
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
msg += "\n" + request[5] + "\n" + request[2] + ": "
|
||||||
|
msg += str(exception)
|
||||||
|
msg += "\n" + "-" * 80
|
||||||
|
|
||||||
|
if not isinstance(exception, error._ClientSideRecreateError):
|
||||||
|
# Let's log these as errors
|
||||||
|
log.error(msg)
|
||||||
|
else:
|
||||||
|
# The rest just get's logged in debug level, just to log
|
||||||
|
# what's happending
|
||||||
|
log.debug(msg)
|
||||||
|
|
||||||
|
d.errback(exception)
|
||||||
del self.__rpc_requests[request_id]
|
del self.__rpc_requests[request_id]
|
||||||
|
|
||||||
def send_request(self, request):
|
def send_request(self, request):
|
||||||
@ -347,7 +332,6 @@ class DaemonSSLProxy(DaemonProxy):
|
|||||||
# Create a Deferred object to return and add a default errback to print
|
# Create a Deferred object to return and add a default errback to print
|
||||||
# the error.
|
# the error.
|
||||||
d = defer.Deferred()
|
d = defer.Deferred()
|
||||||
d.addErrback(self.__rpcError)
|
|
||||||
|
|
||||||
# Store the Deferred until we receive a response from the daemon
|
# Store the Deferred until we receive a response from the daemon
|
||||||
self.__deferred[self.__request_counter] = d
|
self.__deferred[self.__request_counter] = d
|
||||||
@ -405,27 +389,6 @@ class DaemonSSLProxy(DaemonProxy):
|
|||||||
if event in self.__factory.event_handlers and handler in self.__factory.event_handlers[event]:
|
if event in self.__factory.event_handlers and handler in self.__factory.event_handlers[event]:
|
||||||
self.__factory.event_handlers[event].remove(handler)
|
self.__factory.event_handlers[event].remove(handler)
|
||||||
|
|
||||||
def __rpcError(self, error_data):
|
|
||||||
"""
|
|
||||||
Prints out a RPCError message to the error log. This includes the daemon
|
|
||||||
traceback.
|
|
||||||
|
|
||||||
:param error_data: this is passed from the deferred errback with error.value
|
|
||||||
containing a `:class:DelugeRPCError` object.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if isinstance(error_data.value, error.NotAuthorizedError):
|
|
||||||
# Still log these errors
|
|
||||||
log.error(error_data.value.logable())
|
|
||||||
return error_data
|
|
||||||
if isinstance(error_data.value, error._PassthroughError):
|
|
||||||
return error_data
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
log.error(error_data.value.logable())
|
|
||||||
return error_data
|
|
||||||
|
|
||||||
def __on_connect(self, result):
|
def __on_connect(self, result):
|
||||||
log.debug("__on_connect called")
|
log.debug("__on_connect called")
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
from twisted.internet import defer, reactor
|
from twisted.internet import defer, reactor
|
||||||
import deluge.component as component
|
import deluge.component as component
|
||||||
|
from deluge.error import DelugeError
|
||||||
from deluge.ui.client import client
|
from deluge.ui.client import client
|
||||||
from deluge.ui.console import UI_PATH
|
from deluge.ui.console import UI_PATH
|
||||||
from colors import strip_colors
|
from colors import strip_colors
|
||||||
@ -128,12 +129,11 @@ class Commander:
|
|||||||
self.console.started_deferred.addCallback(on_started)
|
self.console.started_deferred.addCallback(on_started)
|
||||||
component.start().addCallback(on_started)
|
component.start().addCallback(on_started)
|
||||||
|
|
||||||
def on_connect_fail(result):
|
def on_connect_fail(reason):
|
||||||
from deluge.ui.client import DelugeRPCError
|
if reason.check(DelugeError):
|
||||||
if isinstance(result.value,DelugeRPCError):
|
rm = reason.value.message
|
||||||
rm = result.value.exception_msg
|
|
||||||
else:
|
else:
|
||||||
rm = result.getErrorMessage()
|
rm = reason.getErrorMessage()
|
||||||
print "Could not connect to: %s:%d\n %s"%(host,port,rm)
|
print "Could not connect to: %s:%d\n %s"%(host,port,rm)
|
||||||
self.do_command("quit")
|
self.do_command("quit")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user