2010-07-07 177 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