2013-01-11 228 views
6

我正在嘗試使用Python庫來使用Objective-C中的Ubutu One API。這裏是我的源代碼: https://github.com/JoseExposito/U1-Finder-Plugin/blob/master/U1FinderLib/U1FinderLib.py在一個線程中執行Twisted reactor.run()?

我需要對API進行多次調用,爲此我需要讓反應器運行一次而不是運行它並停止它,就像在Ubuntu One文檔的示例中一樣: https://one.ubuntu.com/developer/files/store_files/syncdaemontool

因爲無法運行兩次反應堆......而且我需要在線程中執行reactor.run(),因爲我無法阻止使用該庫的應用程序!

有可能這樣做嗎?我無法在一個線程中運行反應堆並調用Ubuntu One API同步。

編輯:

我使用這個簡單的源代碼,以驗證這一想法:

#!/usr/bin/env python 
import objc 
import thread 
import os 
import time 
from twisted.internet import reactor, defer 
from ubuntuone.platform.tools import (SyncDaemonTool, is_already_running) 
from threading import Thread 
NSObject = objc.lookUpClass('NSObject') 

## 
# Variable to get the result of the calls to the Sync Daemon. 
# The result is a JSON string stored in returned_value[0]. 
returned_value = [''] 

## 
# Objective-C facade to the methods of the U1FinderLib. 
class U1FinderLib(NSObject): 

    def init(self): 
     self = super(U1FinderLib, self).init() 
     self.sync_daemon_tool = SyncDaemonTool(None) 
     Thread(target=reactor.run, args=(False,)).start() 
     return self 

    @objc.typedSelector('@@:') 
    def volumeList(self): 
     print "Begin volumeList" 
     reactor.callLater(0, run_command, "volume_list", [], self.sync_daemon_tool) 
     print "End volumeList" 
     return returned_value[0] 

## 
# Auxiliar functions to call to the sync daemon. 
@defer.inlineCallbacks 
def run_command(action, params, sync_daemon_tool): 
    print "run_command" 
    running = yield is_already_running() 
    print "After is_already_running" 
    try: 
     if not running: 
      returned_value[0] = '{ type:"error" reason:"Sync Daemon is not running" }' 
     else: 
      print "Before run_action" 
      yield run_action(action, params, sync_daemon_tool) 
      print "After run_action" 
    except Exception, e: 
     returned_value[0] = '{ type:"error" reason:"Exception: %s" }' % e 

@defer.inlineCallbacks 
def run_action(action, params, sync_daemon_tool): 
    if action == "volume_list": 
     d = sync_daemon_tool.get_folders() 
     returned_value[0] = yield d.addCallback(lambda r: volume_list(r)) 

# Volume List 
def volume_list(folders): 
    volumes_json = '{ type:"volume_list" volumes: { \n\t{ volume:"' + os.path.expanduser('~/Ubuntu One') + '" subscribed:"YES" }' 
    for folder in folders: 
     volumes_json += ',\n\t{ volume:"' + folder['path'] + '" subscribed:"' + ('YES' if bool(folder['subscribed']) else 'NO') + '" }' 
    volumes_json += '\n} }' 
    return volumes_json 

if __name__ == '__main__': 
    py = U1FinderLib.alloc().init() 
    print py.volumeList() 
    print "EXIT" 

這是該程序的輸出:

Begin volumeList 
End volumeList 

EXIT 

的問題是, 「run_command」函數永遠不會被調用

+0

你可以隨時註冊你的功能作爲deferands,通過反應堆發射他們# –

+0

你能解釋一下嗎?我是一個Python完全noob(實際上這是我的第一個Python代碼) – user1204395

+0

首次在Python中編程並直接跳到Twisted?祝你好運...... :) –

回答

15

不是在一個線程中運行反應器,而是應該使用與您想要使用它的應用程序集成在一起的反應器。例如,也許您想使用CoreFoundation reactor(因爲您的應用程序使用Obj-C並且在名稱中具有「Finder」)。如果你真的不能這麼做(例如,如果Ubuntu One需要不同的反應器 - 我不知道是否是這種情況),那麼你可能可以在一個線程中運行該反應器。大多數反應堆都支持這一點,儘管如果Ubuntu One需要特定的反應堆,該反應堆可能不支持線程化使用。

你實際上沒有解釋當你嘗試在一個線程中運行reactor時你有什麼問題,所以我不能幫你理解爲什麼它不起作用。但是,這應該很容易。剛:

from twisted.internet import reactor 
from threading import Thread 

Thread(target=reactor.run, args=(False,)).start() 

請記住,一旦你選擇在一個線程中運行的反應堆,你可能只使用扭曲的API在線程。

如果這不起作用,請提供有關在問題中不起作用的更多詳細信息。

+0

非常感謝您的幫助。 我在我的問題中添加了示例源代碼。 如果我嘗試使用CFReactor,我有一個「No module named CFNetwork」錯誤。我必須說我的應用程序是我在Finder進程中注入的一個包,以改變它們的行爲,並且我不能使用許多功能。 – user1204395

+0

你的包中有CFNetwork嗎? –

+0

解決了,核心基礎反應堆是正確的解決方案。非常感謝你!! – user1204395

相關問題