为什么pb.Viewable中的perspective参数作为None传递?

时间:2013-11-18 01:49:21

标签: python twisted perspective-broker

我试图了解如何找出如何让服务器知道哪个客户端在twisted的透视代理中发出远程请求。我想我应该使用twisted.spread.pb.Viewable,但是当我尝试Viewable的view_*方法中的perspective参数是None时。

我运行此服务器

import twisted.spread.pb as pb
import twisted.internet.reactor as reactor

class Server(pb.Root):
    def __init__(self):
        self.v = MyViewable()

    def remote_getViewable(self):
        return self.v

class MyViewable(pb.Viewable):
    def view_foo(self, perspective):
        print ("Perspective %s"%perspective)


if __name__ == "__main__":
    reactor.listenTCP(54321, pb.PBServerFactory(Server()))
    print("Starting reactor")
    reactor.run()

和这个客户

import twisted.spread.pb as pb
import twisted.internet.reactor as reactor
from twisted.internet.defer import inlineCallbacks

@inlineCallbacks
def gotRoot(root):
    v1 = yield root.callRemote("getViewable")
    v2 = yield root.callRemote("getViewable")
    print(v1)
    print(v2)
    yield v1.callRemote("foo")
    yield v2.callRemote("foo")

factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 54321, factory)
d = factory.getRootObject()
d.addCallback(gotRoot)
reactor.run()

服务器的输出是

Starting reactor
Perspective None
Perspective None

为什么透视参数为None?

1 个答案:

答案 0 :(得分:0)

通过实验,我相信我已经确定了答案。

为了在pb.Viewable上远程调用view_ *方法以正确接收透视参数,必须获取客户端持有的Viewable的引用作为来自于调用的perspective_ *方法的返回值。 pb.Avatar(或子类)的实例。传递给view_ *方法的透视参数然后对应于最初为客户端提供对Viewable的引用的头像。

原始发布中的示例代码无法正常工作,因为对Viewable的远程引用从pb.Root传递到客户端,而不是作为pb.Avatar上的perspective_ *方法的返回值。

我在这里注意到虽然examples in the official documents的编写方式暗示了这些信息,但似乎没有明确说明。

编辑:我已经找到正确的方式来执行此操作。 Realm的requstAvatar方法的一个参数是用户的mind。您所要做的就是将mind.perspective设置为新的Avatar实例,并且所有后续远程调用都会按照您的预期运行。例如:

class SimpleRealm:
implements(IRealm)

def requestAvatar(self, avatarId, mind, *interfaces):
    avatar = MyAvatarSubclass()
    mind.perspective = avatar
    return pb.IPerspective, avatar, avatar.logout

OLD EDIT :实现此工作的一种(糟糕的)方法是显式构造pb.ViewPoint并将其作为参数传递给远程客户端。例如,如果p是Avatar子类的实例,而v是可在服务器端查看的,我们可以在服务器上执行此操作

referenceToClient.callRemote("take", ViewPoint(p, v))

在客户端,我们有类似

的东西
def remote_take(self, objToReceive):
    self.myView = objToReceive

客户端对self.myView.callRemote(...)的后续调用将正常工作