2010-07-07 6 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: http://irrepupavel.com/documents/python/instancemethod/)

Вам понадобится много обработки ошибок. Например, вам необходимо пройти проверку ошибок по телефону split() по строке 2 из dataReceived().

С этим вы можете иметь отдельные файлы с одной функцией в них для каждого метода, который необходимо поддерживать. Ни в коем случае не полный пример, но это может вас заинтересовать, поскольку то, что вы ищете, довольно сложно.

Для более формальной регистрации я бы рекомендовал dict в MyProtocol с именами методов, которые поддерживают, по линиям:

# 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

+0

На данный момент ваш ответ работает очень хорошо. Большое спасибо! – Escualo

Смежные вопросы