创建“按需”活动?

时间:2013-08-06 11:25:39

标签: twisted

我正在为现有软件编写一个插件,该插件将使用twisted与Denon AV接收器进行通信。我在我的协议中创建了一个方法powerDenonOff来关闭设备,并在应用程序通过runConcurrentThread启动时让反应器在一个线程中启动。我有另一种方法powerOff,当用户选择在软件中关闭设备时将调用该方法。我无法弄清楚如何从插件类中调用协议中的powerDenonOff方法。

from twisted.internet.protocol import Factory, Protocol
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class DenonProtocol(LineReceiver):
    delimiter='\r'

    def lineReceived(self, line):
        pass

    def connectionMade(self):
        pass

    def powerDenonOff(self):
        self.transport.write("PWSTANDBY")

    def __call__(self):
        pass

class DenonFactory(Factory):

    def __init__(self):
        pass

    def startedConnecting(self, connector):
        pass

    def clientConnectionFailed(self, one, two):
        pass

    def connectionMade(self):
        pass

    def buildProtocol(self, addr):
        return DenonProtocol()

class Plugin(software.PluginClass):

    def powerOff(self):
        reactor.callInThread(powerDenonOff) #I think this may need to be callFromThread but
                                            #but I left it since that was where the poorly
                                            #worded version of my question left off.

    def runConcurrentThread(self):
        try:
            while True:
                #hardcoded for testing
                port = 23
                host = "111.11.11.11"

                denon=DenonFactory()
                reactor.connectTCP(host, port, denon)
                reactor.run()
        except self.StopThread:
            pass

    def stopConcurrentThread(self):
        reactor.callFromThread(reactor.stop)

如何在协议类中找到该方法?有没有更好的方法来实现这一目标?

由于

1 个答案:

答案 0 :(得分:1)

您不能多次拨打reactor.run,因此runConcurrentThread中的循环无效。每个过程需要启动一次反应器。您可以多次拨打connectTCP,只要反应堆在某个时刻启动,它们就会起作用。

如果在非主线程中调用runConcurrentThread,那么您还需要在没有子进程支持的情况下启动reactor(只有在主线程中运行reactor时才支持子进程)。

如果在与stopConcurrentThread相同的帖子中调用runConcurrentThread,则无需使用reactor.callFromThread。但是,如果runConcurrentThread应该在插件完成之前阻塞,那么就无法在同一个线程中调用stopConcurrentThread,因此reactor.callFromThread的使用必须正确。

reactor.run永远不会提升StopThread。它会回来。

至于如何从“插件”调用协议实例上的方法,这只是关于在Python中管理引用的问题。回想一下,协议实例给出了对它们工厂的引用(你的工厂没有这样做,但它可以),你的插件类是创建工厂的代码。这意味着您应该能够编写通过工厂引用协议的插件代码。

但是,您也可以使用一种更方便的API - 例如,端点:

endpoint = TCP4ClientEndpoint(reactor, host, port)
factory = ...
d = endpoint.connect(factory)
def connected(protocol):
    protocol.powerDenonOff()
    protocol.transport.loseConnection()
d.addCallback(connected)

这只是一种可能的方法 - 我不知道哪种连接管理对您的应用程序有意义。如果要维护单个长期连接,则可以保存protocol引用以供以后使用,而不是调用powerDenonOff然后断开连接。我怀疑,由于这里的方法是关闭电源,所以连接可能不会持续更长时间,但是......

钩针编织将帮助你完成大部分更无聊和更有趣的部分。我建议尽早看一下。

对于其他人,您只需要非常清楚什么代码在什么线程中运行。允许在reactor.run以外的其他线程中使用的唯一Twisted API是reactor.callFromThread。您可以使用它来调用reactor线程中的其他Twisted API。还要记住,每个进程只能运行一个反应器,并且只能运行一次。其余的只是跟踪您需要使用的对象的引用。