Добавление методов на простой RPC-сервер чистым и разделенным способом - PullRequest
1 голос
/ 07 июля 2010

Я создал простой 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 Ответ

1 голос
/ 08 июля 2010

Немного сложный порядок;) но вот несколько начальных шагов для вас (очень сильно смоделированные, искаженные особенности, опущенные в примерах):

# 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

Краткий обзор слишком длинного поста: функция __import__ (http://docs.python.org/library/functions.html) наверняка станет ключевой частью вашего решения.

...