Hinzufügen von Methoden zu einem einfachen RPC-Server in einem sauberen und getrennten Wegen
-
02-10-2019 - |
Frage
habe ich eine einfache RPC Server bestimmte Aufgaben gemeinsam unsere Teams erfüllen, aber die werden aus verschiedenen Netzwerken genannt. Der Server sieht wie folgt aus (I enthalten keine Fehlerbehandlung der Kürze halber):
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()
Das ist sehr einfach: der Server eine JSON-RPC-Anforderung von dem Client, sucht nach der Methode empfängt, und ruft die Methode die Parameter übergeben. Das Verfahren selbst ist die, die JSON RPC-Antwort zurück. Für die weniger vertraut, ein JSON-RPC sieht etwa wie folgt aus:
request:
{"method":"my_method", "params":[1,2,3], "id":"my_id"}
response:
{"result":"my_result", "error":null, "id":"my_id"}
Der RPC-Server, wie ich habe es sehr gut meine aktuellen Zwecken dient (wie man sich vorstellen kann, ist meine Aufgabe sehr einfach). Aber ich werde auch weiterhin brauchen, um Methoden wie die Komplexität der Aufgabe erhöht hinzuzufügen.
Ich will nicht die Haupt-Datei öffnen, und fügen Sie noch eine weitere def method3(...)
und zwei Wochen später, fügen def method4(...)
und so weiter; der Code würde zu schnell wachsen und die Wartung schwieriger und schwieriger wäre.
Also, meine Frage ist: Wie kann ich eine Architektur schaffen, die mir erlaubt, zu registrieren Methoden in den Server . Ein Bonus wäre, einen separaten Ordner haben, eine Datei pro Methode zu halten, so dass sie leicht ausgetauscht werden können und gepflegt. Diese „Architektur“ würde mir erlauben, auch aufzuschieben Wartung einiger Methoden an jemand anderen, unabhängig von ihrem Verständnis von Verdrehte.
ist mir egal, wenn ich brauche den Server jedes Mal eine neue Methode zum Neustart registriert ist, aber ein deutliches Plus wäre, wenn ich nicht haben auch:).
Danke.
Lösung
Bit A eine largish Ordnung;) aber hier einige ersten Schritte für Sie (sehr stark verspottet-up, verdrehte Besonderheiten in den Beispielen ommited):
# 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
Angenommen, Sie probieren Sie es aus, als ob wir diese ausgeführt:
mp = MyProtocol()
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}')
Sie Wold ein Modul somemod.py
im selben Verzeichnis wie das Beispiel mit dem folgenden Inhalt haben (Mirroring Ihr Beispiel Methode .add()
oben):
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
Auf diese Weise können Sie ein Modul pro Methode bedient haben. Der method(..
Anruf oben wird immer Ihre MyProtocol
Instanz an die versorgende aufrufbar passieren. (Wenn Sie wirklich Instanzmethoden wollen, ist hier Anweisungen, wie Methoden hinzufügen Python mit: http: // irrepupavel .com / documents / python / instancemethod / )
Sie werden eine Menge von Fehlerbehandlung benötigen hinzugefügt. Zum Beispiel müssen Sie eine Menge von Fehlerprüfung an der split()
Anruf auf Leitung 2 von dataReceived()
.
Mit diesem können Sie verfügen über separate Dateien mit einer Funktion in ihnen für jede Methode, die Sie Unterstützung benötigen. Keineswegs ein vollständiges Beispiel, aber es könnte loslegen Sie, da das, was suchen your'e für recht komplex ist.
Für eine formelle Registrierung, würde ich einen dict
in MyProtocol
mit Namen von Methoden empfehlen, dass Sie unterstützen, entlang der Linien von:
# in MyProtocol's __init__() method:
self.methods = {}
Und ein Register Methode ..
def register(self, name, callable):
self.methods[name] = callable
.. ändern dataReceived()
..
def dataReceived(self, data):
# ...
modname, funcname = self.methods.get(req['method'], False)
# ..continue along the lines of the dataReceived() method above
Kurze Zusammenfassung eines zu langen Beitrag: die __import__
Funktion ( http: //docs.python .org / library / functions.html ) wird mit Sicherheit ein wichtiger Teil Ihrer Lösung sein.