クリーンで分離された方法でシンプルなRPCサーバーにメソッドを追加する
-
02-10-2019 - |
質問
シンプルを作成しました RPC チームに共通の特定のタスクを実行するサーバーがありますが、これは異なるネットワークから呼び出されます。サーバーはこのように見えます(Brevityのためにエラー処理を含めません):
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応答を返すものです。あまり馴染みのない場合、a 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(...)
そして、2週間後、追加 def method4(...)
など。コードが速すぎて、メンテナンスはますます難しくなります。
だから、私の質問は次のとおりです。 どうすればできるようにするアーキテクチャを作成できますか 登録 サーバーへのメソッド. 。ボーナスは、メソッドごとに1つのファイルを保持している別のフォルダーを使用して、簡単に共有および維持できるようにすることです。この「アーキテクチャ」は、ねじれの理解に関係なく、他の誰かにいくつかの方法の維持を延期することもできます。
新しい方法が登録されるたびにサーバーを再起動する必要があるかどうかは気にしませんが、明らかなプラスは私が しないでください 持っている:)。
ありがとう。
解決
ちょっとした秩序;)しかし、ここにあなたのためのいくつかの最初の手順があります(非常にひどくock笑され、ねじれた詳細を例に掲げています):
# 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
これにより、メソッドごとに1つのモジュールを提供できます。 method(..
上記のコールは常にあなたを渡します MyProtocol
サービングコール可能なインスタンス。 (本当にインスタンスメソッドが必要な場合は、Pythonを使用してメソッドを追加する方法に関する指示を次に示します。 http://irrepupavel.com/documents/python/instancemethod/ )
多くのエラー処理が追加される必要があります。たとえば、で多くのエラーチェックが必要です split()
の2行目に電話してください dataReceived()
.
これを使用すると、サポートする必要があるすべての方法に対して1つの関数を含む個別のファイルを使用できます。決して完全な例ではありませんが、あなたが探しているものが非常に複雑であるため、あなたを動かすかもしれません。
より正式な登録には、aをお勧めします 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
長すぎる投稿のクイックサマリー:the __import__
働き ( http://docs.python.org/library/functions.html )あなたのソリューションの重要な部分になるでしょう。