Добавление методов на простой RPC-сервер чистым и разделенным способом

1

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

Это очень просто: сервер получает запрос JCON 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.

Мне все равно, если мне нужно перезапустить сервер каждый раз, когда будет зарегистрирован новый метод, но очевидный плюс будет, если у меня тоже нет:).

Спасибо.

Теги:
architecture
twisted
network-protocols
json-rpc

1 ответ

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 __init__() method:
self.methods = {}

И метод регистрации.

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

.. изменить 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), безусловно, будет ключевой частью вашего решение.

  • 0
    Большое спасибо за ваш ответ. Я не знаю, чем я в конечном итоге буду заниматься, но ваш подход гениален и ставит меня на правильный путь.
  • 0
    Пока ваш ответ работает очень хорошо. Большое спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню