From c00d20361f637047bf53d1e9394ba5b3a2b9c9eb Mon Sep 17 00:00:00 2001 From: Zooko O'Whielacronx Date: Wed, 31 Dec 2008 14:28:30 -0700 Subject: [PATCH] rrefutil: generically wrap any errback from callRemote() in a ServerFailure instance This facilitates client code to easily catch ServerFailures without also catching exceptions arising from client-side code. See also: http://foolscap.lothar.com/trac/ticket/105 # make it easy to distinguish server-side failures/exceptions from client-side --- src/allmydata/util/rrefutil.py | 35 +++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/allmydata/util/rrefutil.py b/src/allmydata/util/rrefutil.py index 9a567ebb..d39f1d6a 100644 --- a/src/allmydata/util/rrefutil.py +++ b/src/allmydata/util/rrefutil.py @@ -1,15 +1,33 @@ +import exceptions from foolscap.tokens import Violation -class VersionedRemoteReference: - """I wrap a RemoteReference, and add a .version attribute.""" +from twisted.python import failure - def __init__(self, original, version): +class ServerFailure(exceptions.Exception): + # If the server returns a Failure instead of the normal response to a protocol, then this + # exception will be raised, with the Failure that the server returned as its .remote_failure + # attribute. + def __init__(self, remote_failure): + self.remote_failure = remote_failure + def __repr__(self): + return repr(self.remote_failure) + def __str__(self): + return str(self.remote_failure) + +def _wrap_server_failure(f): + raise ServerFailure(f) + +class WrappedRemoteReference(object): + """I intercept any errback from the server and wrap it in a ServerFailure.""" + + def __init__(self, original): self.rref = original - self.version = version def callRemote(self, *args, **kwargs): - return self.rref.callRemote(*args, **kwargs) + d = self.rref.callRemote(*args, **kwargs) + d.addErrback(_wrap_server_failure) + return d def callRemoteOnly(self, *args, **kwargs): return self.rref.callRemoteOnly(*args, **kwargs) @@ -17,6 +35,13 @@ class VersionedRemoteReference: def notifyOnDisconnect(self, *args, **kwargs): return self.rref.notifyOnDisconnect(*args, **kwargs) +class VersionedRemoteReference(WrappedRemoteReference): + """I wrap a RemoteReference, and add a .version attribute. I also intercept any errback from + the server and wrap it in a ServerFailure.""" + + def __init__(self, original, version): + WrappedRemoteReference.__init__(self, original) + self.version = version def get_versioned_remote_reference(rref, default): """I return a Deferred that fires with a VersionedRemoteReference""" -- 2.45.2