Добавление методов простым сервером RPC в чистоте и разделенном виде
-
02-10-2019 - |
Вопрос
Я создал простой 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(...)
и так далее; Код будет расти слишком быстро, и обслуживание будет сложнее и сложнее.
Итак, мой вопрос: Как я могу создать архитектуру, которая позволяет мне регистр Методы на сервер. Отказ Бонус будет иметь отдельную папку, удерживающую один файл на метод, чтобы они могли легко обделить и поддерживать. Эта «архитектура» также позволит мне отложить поддержание некоторых методов для кого-то другого, независимо от их понимания скрученных.
Мне все равно, если мне нужно будет перезапустить сервер каждый раз, когда новый метод зарегистрирован, но очевидный плюс будет, если я нет есть тоже :).
Спасибо.
Решение
Немного вкусного порядка;) Но вот несколько начальных шагов для вас (очень сильно издевается, витая специфики, отмените в примерах):
# 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
экземпляр для обслуживания Callable. (Если вы действительно хотите методы экземпляра, вот инструкции о том, как добавить методы с помощью Python: http://rirepupavel.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
..Модифицировать 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.cython.org/library/functions.html. ) наверняка будет ключевой частью вашего решения.