def slice(self, streamable, protocol): broker = self.requireBroker(protocol) puid = ipb.IReferenceable(self.obj).processUniqueID() tracker = broker.getTrackerForMyReference(puid, self.obj) if broker.remote_broker: # emit a my-reference sequence yield b'my-reference' yield tracker.clid firstTime = tracker.send() if firstTime: # this is the first time the Referenceable has crossed this # wire. In addition to the clid, send the interface name (if # any), and any URL this reference might be known by iname = ipb.IRemotelyCallable(self.obj).getInterfaceName() yield iname or '' url = tracker.getURL() if url: yield url else: # when we're serializing to data, rather than to a live # connection, all of my Referenceables are turned into # their-reference sequences, to prompt the eventual recipient to # create a new connection for this object. # a big note on object lifetimes: obviously, the data cannot keep # the Referenceable alive. Use tub.registerReference() on any # Referenceable that you want to include in the serialized data, # and take steps to make sure that later incarnations of this Tub # will do the same. yield b'their-reference' yield 0 # giftID==0 tells the recipient to not try to ack it yield tracker.getURL()
def _doCall(self, delivery): # our ordering rules require that the order in which each # remote_foo() method gets control is exactly the same as the order # in which the original caller invoked callRemote(). To insure this, # _startCall() is not allowed to insert additional delays before it # runs doRemoteCall() on the target object. obj = delivery.obj args = delivery.allargs.args kwargs = delivery.allargs.kwargs for i in args + kwargs.values(): assert not isinstance(i, defer.Deferred) if delivery.methodSchema: # we asked about each argument on the way in, but ask again so # they can look for missing arguments. TODO: see if we can remove # the redundant per-argument checks. delivery.methodSchema.checkAllArgs(args, kwargs, True) # interesting case: if the method completes successfully, but # our schema prohibits us from sending the result (perhaps the # method returned an int but the schema insists upon a string). # TODO: move the return-value schema check into # Referenceable.doRemoteCall, so the exception's traceback will be # attached to the object that caused it if delivery.methodname is None: assert callable(obj) return obj(*args, **kwargs) else: obj = ipb.IRemotelyCallable(obj) return obj.doRemoteCall(delivery.methodname, args, kwargs)