2013-08-06 86 views
1

我正在爲現有軟件編寫一個插件,它將使用雙絞線與Denon AV接收器進行通信。我在協議中創建了一個方法powerDenonOff,用於關閉設備,並在應用程序通過runConcurrentThread啓動時讓反應堆在一個線程中啓動。我有另一種方法,powerOff,當用戶選擇在軟件中關閉設備時將會調用這個方法。我很難搞清楚如何在Plugin類的協議中調用我的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

不能調用超過一次reactor.run多,所以在runConcurrentThread循環將無法工作。您需要每個流程僅啓動一次反應器。您可以撥打connectTCP任意多次,只要反應堆在某個時刻開始運行,它們就會工作。

如果在非主線程中調用了runConcurrentThread,則還需要啓動反應器而不支持子進程(子進程僅在主線程中運行時支持)。

如果stopConcurrentThread在與runConcurrentThread相同的線程中調用,那麼它不需要使用reactor.callFromThread。但是,如果runConcurrentThread應該阻塞直到插件完成,那麼在同一個線程中不能調用stopConcurrentThread,因此使用reactor.callFromThread必須是正確的。

reactor.run永遠不會提高StopThread。它會回來。

至於如何在協議實例「from」插件上調用方法,這只是一個關於在Python中管理引用的問題。回想一下,協議實例被賦予對其工廠的引用(您的工廠不這樣做,但它可以),而您的插件類是創建工廠的代碼。這意味着您應該能夠編寫通過工廠引用協議的插件代碼。

但是,您也可以使用更方便的API之一 - 例如,終點:

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

這僅僅是一種可能的方法 - 我不知道什麼樣的連接管理的有意義的你應用。如果您想維護一個長期連接,那麼您可以保存參考以供以後使用,而不是呼叫powerDenonOff,然後斷開連接。我懷疑,因爲這裏的方法是關閉電源,但連接可能不會長得多,雖然...

鉤針將幫助你做大部分更無聊和finnicky部分。我建議儘快看看它,而不是晚些時候。

其餘的,你只需要非常清楚在哪個線程中運行的代碼。唯一允許在與reactor.run不同的線程中使用的Twisted API被調用的是reactor.callFromThread。您可以使用它來調用反應器線程中的其他Twisted API。另外請記住,每個進程只能運行一個反應器,並且只能運行一次。其餘的只是跟蹤你需要使用的對象的引用。

+0

這需要您在運行之前告訴反應堆,在運行命令之前需要等待多長時間,不是嗎? –

+0

爲了進一步闡明:我無法知道什麼時候將來我需要打開設備。我需要讓reactor已經運行,因爲我想監聽它的狀態何時更新以更新UI。由於我不知道在將來用戶想要運行命令(或者即使它將被調用),我也不知道如何扭曲來處理它。 –

+0

你原來的問題聽起來像你想要基於時間的事件。看起來情況並非如此,您需要基於GUI的事件? –