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
|
||||
from deluge.core.authmanager import (AUTH_LEVEL_NONE, AUTH_LEVEL_DEFAULT,
|
||||
AUTH_LEVEL_ADMIN)
|
||||
from deluge.error import (DelugeError, NotAuthorizedError, _PassthroughError,
|
||||
IncompatibleClient)
|
||||
from deluge.error import (DelugeError, NotAuthorizedError,
|
||||
_ClientSideRecreateError, IncompatibleClient)
|
||||
|
||||
RPC_RESPONSE = 1
|
||||
RPC_ERROR = 2
|
||||
RPC_EVENT = 3
|
||||
RPC_EVENT_EXCEPTION = 4
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -247,13 +246,13 @@ class DelugeRPCProtocol(Protocol):
|
||||
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)))
|
||||
exceptionType.__name__,
|
||||
exceptionValue._args,
|
||||
exceptionValue._kwargs,
|
||||
"".join(traceback.format_tb(exceptionTraceback))
|
||||
))
|
||||
|
||||
if method == "daemon.info":
|
||||
@ -273,14 +272,8 @@ class DelugeRPCProtocol(Protocol):
|
||||
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
||||
self.factory.session_protocols[self.transport.sessionno] = self
|
||||
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)
|
||||
else:
|
||||
self.sendData((RPC_RESPONSE, request_id, (ret)))
|
||||
|
@ -36,7 +36,21 @@
|
||||
|
||||
|
||||
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):
|
||||
pass
|
||||
@ -50,30 +64,18 @@ class InvalidTorrentError(DelugeError):
|
||||
class InvalidPathError(DelugeError):
|
||||
pass
|
||||
|
||||
class _PassthroughError(DelugeError):
|
||||
class _ClientSideRecreateError(DelugeError):
|
||||
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 __new__(cls, *args, **kwargs):
|
||||
inst = super(_PassthroughError, cls).__new__(cls, *args, **kwargs)
|
||||
inst._args = args
|
||||
inst._kwargs = kwargs
|
||||
return inst
|
||||
|
||||
class IncompatibleClient(_PassthroughError):
|
||||
class IncompatibleClient(_ClientSideRecreateError):
|
||||
def __init__(self, daemon_version):
|
||||
self.daemon_version = daemon_version
|
||||
self.message = _(
|
||||
"Your deluge client is not compatible with the daemon. "
|
||||
"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):
|
||||
self.message = _(
|
||||
@ -84,7 +86,7 @@ class NotAuthorizedError(_PassthroughError):
|
||||
self.required_level = required_level
|
||||
|
||||
|
||||
class _UsernameBasedPasstroughError(_PassthroughError):
|
||||
class _UsernameBasedPasstroughError(_ClientSideRecreateError):
|
||||
|
||||
def _get_username(self):
|
||||
return self._username
|
||||
|
@ -56,39 +56,12 @@ else:
|
||||
RPC_RESPONSE = 1
|
||||
RPC_ERROR = 2
|
||||
RPC_EVENT = 3
|
||||
RPC_EVENT_EXCEPTION = 4
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def format_kwargs(kwargs):
|
||||
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):
|
||||
"""
|
||||
@ -204,17 +177,29 @@ class DelugeRPCProtocol(Protocol):
|
||||
if message_type == RPC_RESPONSE:
|
||||
# Run the callbacks registered with this Deferred object
|
||||
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:
|
||||
# Create the DelugeRPCError to pass to the errback
|
||||
r = self.__rpc_requests[request_id]
|
||||
e = DelugeRPCError(r.method, r.args, r.kwargs, request[2][0],
|
||||
request[2][1], request[2][2])
|
||||
# Run the errbacks registered with this Deferred object
|
||||
d.errback(e)
|
||||
# Recreate exception and errback'it
|
||||
exception_cls = getattr(error, request[2])
|
||||
exception = exception_cls(*request[3], **request[4])
|
||||
|
||||
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]
|
||||
|
||||
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
|
||||
# the error.
|
||||
d = defer.Deferred()
|
||||
d.addErrback(self.__rpcError)
|
||||
|
||||
# Store the Deferred until we receive a response from the daemon
|
||||
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]:
|
||||
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):
|
||||
log.debug("__on_connect called")
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
from twisted.internet import defer, reactor
|
||||
import deluge.component as component
|
||||
from deluge.error import DelugeError
|
||||
from deluge.ui.client import client
|
||||
from deluge.ui.console import UI_PATH
|
||||
from colors import strip_colors
|
||||
@ -51,7 +52,7 @@ class Commander:
|
||||
self.interactive = interactive
|
||||
|
||||
def write(self,line):
|
||||
print(strip_colors(line))
|
||||
print(strip_colors(line))
|
||||
|
||||
def do_command(self, cmd):
|
||||
"""
|
||||
@ -128,12 +129,11 @@ class Commander:
|
||||
self.console.started_deferred.addCallback(on_started)
|
||||
component.start().addCallback(on_started)
|
||||
|
||||
def on_connect_fail(result):
|
||||
from deluge.ui.client import DelugeRPCError
|
||||
if isinstance(result.value,DelugeRPCError):
|
||||
rm = result.value.exception_msg
|
||||
def on_connect_fail(reason):
|
||||
if reason.check(DelugeError):
|
||||
rm = reason.value.message
|
||||
else:
|
||||
rm = result.getErrorMessage()
|
||||
rm = reason.getErrorMessage()
|
||||
print "Could not connect to: %s:%d\n %s"%(host,port,rm)
|
||||
self.do_command("quit")
|
||||
|
||||
@ -143,4 +143,4 @@ class Commander:
|
||||
d = client.connect()
|
||||
d.addCallback(on_connect)
|
||||
d.addErrback(on_connect_fail)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user