سؤال

لقد خلقت بسيطة 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 مثال على التقديم القابل للاستدعاء. (إذا كنت تريد حقًا طرق المثيل ، فإليك إرشادات حول كيفية إضافة طرق باستخدام Python: http://irrepupavel.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.python.org/library/functions.html ) بالتأكيد سيكون جزءًا رئيسيًا من الحل الخاص بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top