Ticket #1 (closed enhancement: fixed)

Opened 1 year ago

Last modified 1 year ago

IRemoteReference(localobj) should provide something with .callRemote

Reported by: warner Assigned to: warner
Priority: major Milestone: 0.1.5
Component: introduction Version: 0.1.4
Keywords: Cc:

Description

robk ran into this problem: you have a central introducer and a bunch of clients, and the clients are introducing themselves to each other (to create a fully-connected mesh), and the introductions are using live references (i.e. (their-reference) sequences), then when a specific client learns about itself from the introducer, that client will receive a local object instead of a RemoteReference?. Each client will wind up with n-1 RemoteReferences? and a single local object.

which is a drag because really you'd like to treat the list of clients as a uniform array of RemoteReferences?. But on the other hand, the roundtrip behavior (which turns local objects into RemoteReferences? and back into local objects again) is awfully useful, since it lets you do EQ.

(E solves this by allowing EQ between NearReferences? and FarReferences?, but we don't have that luxury here).

Note that if the introduction is done by FURL instead of by a live reference, this is not a problem, since the client will always be performing a tub.getReference(furl) and thus will always receive a RemoteReference?, even if that furl points back to the client's own tub.

So the proposal is that we establish an interface named IRemoteReference, which contains the callRemote and callRemoteOnly methods, and create an adapter that wraps non-RemoteReference? objects in some code which provides a callRemote that looks something like this:

def callRemote(self, methname, *args, **kwargs):
    def _try():
        meth = getattr(self.original, "remote_" + methname)
        return meth(*args, **kwargs)
    return defer.maybeDeferred(_try)

and maybe even an eventual() in there for good measure.

Then the introducer code that robk uses can just do:

for peer in peers:
    d = IRemoteReference(peer).callRemote(stuff)

and not have to worry about whether 'peer' might be a local object.

Change History

07/18/07 18:25:03 changed by evilrob

since callRemote on an rref always returns asynchronously, I'd argue that there should definitely be an 'eventually' in there. e.g.

def callRemote(self, methname, *args, **kwargs):
    def _try(junk):
        meth = getattr(self.original, "remote_" + methname)
        return meth(*args, **kwargs)
    d = fireEventually()
    d.addCallback(_try)
    return d

07/27/07 00:39:52 changed by warner

  • status changed from new to closed.
  • resolution set to fixed.

Done, in [213], exactly as you suggested. The wrapper also implements notifyOnDisconnect and dontNotifyOnDisconnect.

To use it, do:

from foolscap.ipb import IRemoteReference

IRemoteReference(t).callRemote("methname", args)