2010-07-07 173 views
1

我創建了一個簡單的RPC服務器來執行某些我們團隊通用的任務,但是這些任務是從不同的網絡調用的。服務器看起來是這樣的(我不包括爲簡潔的錯誤處理):以簡潔明瞭的方式向簡單的RPC服務器添加方法

from twisted.internet.protocol import Protocol, Factory 
from twisted.internet import reactor 
import json 

class MyProtocol(Protocol): 
    def dataReceived(self, data): 
     req = json.loads(data) # create a dictionary from JSON string 
     method = getattr(self, req['method']) # get the method 
     method(req['params']) # call the method 

    def add(self, params): 
     result = {} # initialize a dictionary to convert later to JSON 
     result['result'] = sum(params) 
     result['error'] = None 
     result['id'] = 1 
     self.transport.write(json.dumps(result)) # return a JSON string 
     self.transport.loseConnection() # close connection 

factory = Factory() 
factory.protocol = MyProtocol 
reactor.listenTCP(8080, factory) 
reactor.run() 

這是非常簡單的:服務器接收來自客戶端的JSON RPC請求,查找的方法,並調用該方法通過參數。該方法本身是返回JSON RPC響應的方法。對於不太熟悉,一JSON RPC看起來大約是這樣的:

request: 
{"method":"my_method", "params":[1,2,3], "id":"my_id"} 
response: 
{"result":"my_result", "error":null, "id":"my_id"} 

因爲我有我的服務宗旨電流很好的RPC服務器(你可以想像,我的任務很簡單)。但隨着任務複雜性的增加,我需要繼續添加方法。

我不想打開主文件並添加另一個def method3(...),兩週後添加def method4(...)等等;代碼會變得太快,維護將變得越來越困難。

所以,我的問題是:我怎麼可以創建一個架構,讓我寄存器方法到服務器。一個好處是可以有一個單獨的文件夾,每個方法都有一個文件,這樣他們可以很容易地被共享和維護。不管他們對Twisted的理解如何,這個「架構」也會讓我推遲某些方法的維護。

我不在乎是否需要在每次註冊新方法時重新啓動服務器,但一個明顯的優點是如果我也有:)。

謝謝。

回答

1

一個相當大的順序的位;),但這裏有一些你的初始步驟(非常嚴重嘲弄式,在例子中省略扭曲的細節):

# your twisted imports... 
import json 

class MyProtocol(object): # Would be Protocol instead of object in real code 

    def dataReceived(self, data): 
     req = json.loads(data) # create a dictionary from JSON string 
     modname, funcname = req['method'].split('.') 
     m = __import__(modname) 
     method = getattr(m, funcname) # get the method 
     method(self, req['params']) # call the method 

假設你嘗試一下,就好像我們執行這樣的:

mp = MyProtocol() 
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}') 

您爾德有一個模塊somemod.py在同一個目錄中包含以下內容的例子(鏡像你上面的例子方法.add()):

import json 

def add(proto, params): 
    result = {} # initialize a dictionary to convert later to JSON 
    result['result'] = sum(params) 
    result['error'] = None 
    result['id'] = 1 
    proto.transport.write(json.dumps(result)) # return a JSON string 
    proto.transport.loseConnection() # close connection 

這允許您爲每個方法提供一個模塊。上面的method(..調用將始終將您的MyProtocol實例傳遞給可調用的服務。 (如果你確實需要實例方法,下面是如何使用python添加方法的說明):

你將需要添加大量的錯誤處理。例如,您需要在dataReceived()的第2行的split()調用上進行大量的錯誤檢查。

使用此功能,您可以爲每種需要支持的方法創建單獨的文件,其中包含一個功能。絕不是一個完整的例子,但它可能會讓你走,因爲你要找的東西非常複雜。

對於一個比較正式的登記,我會在MyProtocol推薦dict與您支持的方法名稱,沿着線:

# in MyProtocol's __init__() method: 
self.methods = {} 

和寄存器方法..

def register(self, name, callable): 
    self.methods[name] = callable 

..modify dataReceived() ..

def dataReceived(self, data): 
    # ... 
    modname, funcname = self.methods.get(req['method'], False) 
    # ..continue along the lines of the dataReceived() method above 

Q uick總結一個太長的帖子:__import__函數(http://docs.python.org/library/functions.html)肯定會是您解決方案的關鍵部分。

+0

非常感謝您的回答。我不知道我最終會做什麼,但你的方法是巧妙的,並使我走上正軌。 – Escualo 2010-07-07 22:12:46

+0

目前,您的答案功能非常好。非常感謝! – Escualo 2010-07-12 23:08:36