1
2
3from zope.interface import interface
4Interface = interface.Interface
5
6# TODO: move these here
7from foolscap.tokens import ISlicer, IRootSlicer, IUnslicer
8_ignored = [ISlicer, IRootSlicer, IUnslicer] # hush pyflakes
9
10class InvalidHintError(Exception):
11    """The hint was malformed and could not be used."""
12
13class IConnectionHintHandler(Interface):
14    def hint_to_endpoint(hint, reactor, update_status):
15        """Return (endpoint, hostname), or a Deferred that fires with the
16        same, where endpoint is an IStreamClientEndpoint object, and hostname
17        is a string (for use in the HTTP headers during negotiation). The
18        endpoint, once connected, must be capable of handling .startTLS().
19        Hints are strings which always start with 'TYPE:', and handlers are
20        registered for specific types (and will not be called with hints of
21        other types). update_status() can be called (with a string) to report
22        progress, and should typically be set just before waiting for some
23        connections step (e.g. connecting to a Tor daemon). Raise
24        InvalidHintError (or return a Deferred that errbacks with one) if the
25        hint could not be parsed or otherwise turned into an Endpoint. Set an
26        attribute named 'foolscap_connection_handler_error' on the exception
27        object to have `ConnectionInfo.connectorStatuses()` report that
28        string instead of an exception-class -based status message."""
29
30    def describe():
31        """Return a short string describing this handler, like 'tcp' or
32        'tor'. If this method is not implemented, the handler's repr will be
33        used."""
34
35class DeadReferenceError(Exception):
36    """The RemoteReference is dead, Jim."""
37    def __init__(self, why=None, remote_tubid=None, request=None):
38        self.why = why
39        self.remote_tubid = remote_tubid
40        self.request = request
41
42    def __str__(self):
43        args = []
44        if self.why:
45            args.append(self.why)
46        if self.remote_tubid:
47            args.append("(to tubid=%s)" % self.remote_tubid)
48        if self.request:
49            iname, mname = self.request.getMethodNameInfo()
50            args.append("(during method=%s:%s)" % (iname, mname))
51        return " ".join([str(a) for a in args])
52
53
54class IReferenceable(Interface):
55    """This object is remotely referenceable. This means it is represented to
56    remote systems as an opaque identifier, and that round-trips preserve
57    identity.
58    """
59
60    def processUniqueID():
61        """Return a unique identifier (scoped to the process containing the
62        Referenceable). Most objects can just use C{id(self)}, but objects
63        which should be indistinguishable to a remote system may want
64        multiple objects to map to the same PUID."""
65
66class IRemotelyCallable(Interface):
67    """This object is remotely callable. This means it defines some remote_*
68    methods and may have a schema which describes how those methods may be
69    invoked.
70    """
71
72    def getInterfaceNames():
73        """Return a list of RemoteInterface names to which this object knows
74        how to respond."""
75
76    def doRemoteCall(methodname, args, kwargs):
77        """Invoke the given remote method. This method may raise an
78        exception, return normally, or return a Deferred."""
79
80class ITub(Interface):
81    """This marks a Tub."""
82
83class IBroker(Interface):
84    """This marks a broker."""
85
86class IRemoteReference(Interface):
87    """This marks a RemoteReference."""
88
89    def notifyOnDisconnect(callback, *args, **kwargs):
90        """Register a callback to run when we lose this connection.
91
92        The callback will be invoked with whatever extra arguments you
93        provide to this function. For example::
94
95         def my_callback(name, number):
96             print name, number+4
97         cookie = rref.notifyOnDisconnect(my_callback, 'bob', number=3)
98
99        This function returns an opaque cookie. If you want to cancel the
100        notification, pass this same cookie back to dontNotifyOnDisconnect::
101
102         rref.dontNotifyOnDisconnect(cookie)
103
104        Note that if the Tub is shutdown (via stopService), all
105        notifyOnDisconnect handlers are cancelled.
106        """
107
108    def dontNotifyOnDisconnect(cookie):
109        """Deregister a callback that was registered with notifyOnDisconnect.
110        """
111
112    def callRemote(name, *args, **kwargs):
113        """Invoke a method on the remote object with which I am associated.
114
115        I always return a Deferred. This will fire with the results of the
116        method when and if the remote end finishes. It will errback if any of
117        the following things occur::
118
119         the arguments do not match the schema I believe is in use by the
120         far end (causes a Violation exception)
121
122         the connection to the far end has been lost (DeadReferenceError)
123
124         the arguments are not accepted by the schema in use by the far end
125         (Violation)
126
127         the method executed by the far end raises an exception (arbitrary)
128
129         the return value of the remote method is not accepted by the schema
130         in use by the far end (Violation)
131
132         the connection is lost before the response is returned
133         (ConnectionLost)
134
135         the return value is not accepted by the schema I believe is in use
136         by the far end (Violation)
137        """
138
139    def callRemoteOnly(name, *args, **kwargs):
140        """Invoke a method on the remote object with which I am associated.
141
142        This form is for one-way messages that do not require results or even
143        acknowledgement of completion. I do not wait for the method to finish
144        executing. The remote end will be instructed to not send any
145        response. There is no way to know whether the method was successfully
146        delivered or not.
147
148        I always return None.
149        """
150
151