Ajout de méthodes à un simple serveur RPC de manière propre et séparée
-
02-10-2019 - |
Question
Je créé simple serveur RPC pour effectuer certaines tâches communes à nos équipes, mais qui sont appelés à partir de différents réseaux. Les regards du serveur comme celui-ci (je ne comprends pas le traitement des erreurs par souci de concision):
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()
Ceci est très simple: le serveur reçoit une demande JSON RPC du client, recherche la méthode, et appelle la méthode passer les paramètres. Le procédé lui-même est l'une de retourner la réponse JSON RPC. Pour les moins familiers, un JSON RPC ressemble à peu près comme ceci:
request:
{"method":"my_method", "params":[1,2,3], "id":"my_id"}
response:
{"result":"my_result", "error":null, "id":"my_id"}
Le serveur RPC comme je l'ai sert très bien mes actuels fins (comme vous pouvez l'imaginer, ma tâche est très simple). Mais je vais devoir continuer à ajouter des méthodes comme la complexité de la tâche augmente.
Je ne veux pas ouvrir le fichier principal et ajouter une autre def method3(...)
et, deux semaines plus tard, ajouter def method4(...)
et ainsi de suite; le code grandirait trop rapidement et l'entretien serait plus difficile et plus dur.
Alors, ma question est: Comment puis-je créer une architecture qui me permet de enregistrer méthodes dans le serveur . Un bonus serait d'avoir un dossier distinct tenant un fichier par méthode, de sorte qu'ils peuvent facilement être partagés et entretenus. Cette « architecture » me permettrait également de reporter l'entretien de certaines méthodes à quelqu'un d'autre, quelle que soit leur compréhension de Twisted.
Je ne se soucient pas si je dois redémarrer le serveur à chaque fois est enregistré une nouvelle méthode, mais une évidence, plus serait si je ne pas ont trop:).
Merci.
La solution
Un peu d'un ordre assez grand;) mais voici quelques premières étapes pour vous (très fortement moqué-up, les spécificités tordues ommited dans les exemples):
# 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
En supposant que vous l'essayer comme si nous avons exécuté ceci:
mp = MyProtocol()
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}')
Wold ont un somemod.py
de module dans le même répertoire que l'exemple avec le contenu suivant (Mirroring ci-dessus votre exemple méthode .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
Cela vous permet d'avoir un module par méthode servi. Ce qui précède appel method(..
toujours passer votre instance de MyProtocol
à la appelable servir. (Si vous voulez vraiment des méthodes d'instance, voici des instructions sur la façon d'ajouter des méthodes à l'aide de python: http: // irrepupavel .com / documents / python / instancemethod / )
Vous aurez besoin de beaucoup de traitement des erreurs ajouté. Par exemple, vous avez besoin de beaucoup de contrôle d'erreur à l'appel split()
sur la ligne 2 de dataReceived()
.
Avec cela, vous pouvez avoir des fichiers séparés avec une fonction en eux pour toutes les méthodes dont vous avez besoin au soutien. En aucun cas, un exemple complet, mais il peut vous aider à aller, puisque ce your'e recherche est assez complexe.
Pour un enregistrement plus formel, je vous recommande un dict
en MyProtocol
avec les noms des méthodes que vous soutenez, le long des lignes de:
# in MyProtocol's __init__() method:
self.methods = {}
Et une méthode de registre ..
def register(self, name, callable):
self.methods[name] = callable
.. modifier dataReceived()
..
def dataReceived(self, data):
# ...
modname, funcname = self.methods.get(req['method'], False)
# ..continue along the lines of the dataReceived() method above
Résumé rapide d'un poste trop longtemps: la fonction __import__
( http: //docs.python .org / bibliothèque / functions.html ) sera très certainement un élément clé de votre solution.