Adición de métodos a un servidor de RPC simple en una manera limpia y separada
-
02-10-2019 - |
Pregunta
He creado un simple RPC servidor para realizar ciertas tareas comunes a nuestros equipos, pero que son llamados de diferentes redes. Las miradas servidor de esta manera (no incluyo el manejo de errores por razones de brevedad):
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()
Esto es muy simple: el servidor recibe una solicitud JSON RPC desde el cliente, busca el método, y llama al método de pasar los parámetros. El método en sí mismo es el que devolver la respuesta JSON RPC. Para los menos familiar, un JSON RPC ve aproximadamente así:
request:
{"method":"my_method", "params":[1,2,3], "id":"my_id"}
response:
{"result":"my_result", "error":null, "id":"my_id"}
El servidor RPC ya que tengo que sirve a mis propósitos actuales muy bien (como se puede imaginar, mi tarea es muy simple). Pero voy a tener que seguir añadiendo métodos como la complejidad de los aumentos de trabajo.
No quiero abrir el archivo principal y añadir otro def method3(...)
y, dos semanas después, añadir def method4(...)
y así sucesivamente; el código crecería demasiado rápido y el mantenimiento sería más difícil.
Por lo tanto, mi pregunta es: ¿Cómo puedo crear una arquitectura que me permite registrar métodos en el servidor . Una ventaja sería tener una carpeta separada sosteniendo un archivo por cada método, por lo que fácilmente se pueden compartir y mantenidos. Esta "arquitectura" sería también me permitirá aplazar el mantenimiento de algunos métodos a otra persona, independientemente de su comprensión de trenzado.
No me importa si tengo que reiniciar el servidor cada vez que se ha registrado un nuevo método, sino una obvia ventaja sería si No tener demasiados:.)
Gracias.
Solución
Un poco de un orden bastante grande;) pero aquí hay algunos pasos iniciales para usted (muy fuertemente burlado arriba, detalles trenzados omite, en los ejemplos):
# 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
Si se asume que lo pruebe como si ejecutamos la siguiente:
mp = MyProtocol()
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}')
Wold tiene un somemod.py
módulo en el mismo directorio que el ejemplo con el siguiente contenido (que reflejan el ejemplo del método .add()
arriba):
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
Esto le permite tener un módulo por el método servido. La llamada method(..
anterior pasará siempre la instancia MyProtocol
exigible a la que sirve. (Si realmente quiere métodos de instancia, aquí hay instrucciones sobre cómo agregar métodos que utilizan Python: http: // irrepupavel .com / documentos / Python / instancemethod / )
Se necesitará una gran cantidad de control de errores añadido. Por ejemplo, usted necesita una gran cantidad de comprobación de errores en la llamada split()
en la línea 2 de dataReceived()
.
Con esto usted puede tener archivos separados con una sola función en ellos por todos los medios que necesita para el apoyo. De ninguna manera un ejemplo completo, pero puede ser que consiga que va, ya que lo que Your'e buscando es bastante complejo.
En un registro más formal, lo recomiendo un dict
en MyProtocol
con los nombres de los métodos que usted apoya, a lo largo de las líneas de:
# in MyProtocol's __init__() method:
self.methods = {}
Y un método de registro ..
def register(self, name, callable):
self.methods[name] = callable
.. modificar dataReceived()
..
def dataReceived(self, data):
# ...
modname, funcname = self.methods.get(req['method'], False)
# ..continue along the lines of the dataReceived() method above
Resumen rápido de un demasiado largo mensaje: la función __import__
( http: //docs.python .org / biblioteca / functions.html ) con toda seguridad, será una parte clave de su solución.