Domanda

Ho creato un semplice RPC server per eseguire alcuni compiti comuni ai nostri team, ma che sono chiamati da reti diverse. L'aspetto del server come questo (non includo la gestione degli errori per brevità):

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()

Questo è molto semplice: il server riceve una richiesta JSON RPC dal client, sguardi per il metodo, e chiama il metodo passando i parametri. Il metodo stesso è quello restituendo la risposta JSON RPC. Per i meno familiare, un JSON RPC sembra approssimativamente in questo modo:

request:
{"method":"my_method", "params":[1,2,3], "id":"my_id"}
response:
{"result":"my_result", "error":null, "id":"my_id"}

Il server RPC, come ce l'ho serve i miei scopi attuali molto bene (come si può immaginare, il mio compito è molto semplice). Ma ho bisogno di continuare ad aggiungere metodi come la complessità degli aumenti di attività.

Non voglio aprire il file principale e aggiungere ancora un altro def method3(...) e, due settimane più tardi, aggiungere def method4(...) e così via; il codice sarebbe cresciuta troppo in fretta e la manutenzione sarebbe più difficile.

Quindi, la mia domanda è: come posso creare un'architettura che mi permette di register metodi nel server . Un bonus sarebbe di avere una cartella separata tenendo un file per il metodo, in modo che possano essere facilmente condivisi e mantenuti. Questa "architettura" avrebbe inoltre mi permette di rinviare la manutenzione di alcuni metodi a qualcun altro, a prescindere dalla loro comprensione di Twisted.

Non mi importa se ho bisogno di riavviare il server ogni volta che un nuovo metodo è registrato, ma un evidente vantaggio sarebbe se io non avere troppo:.)

Grazie.

È stato utile?

Soluzione

Un po 'di ordine abbastanza grande;) ma ecco alcuni passi iniziali per voi (molto pesantemente deriso-up, specifiche contorte ommited negli esempi):

# 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

Supponendo di provarlo come se abbiamo eseguito in questo modo:

mp = MyProtocol()
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}')

È Wold hanno un somemod.py modulo nella stessa directory come l'esempio con i seguenti contenuti (mirroring il metodo di esempio .add() sopra):

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

Questo vi permette di avere un modulo per il metodo servito. La chiamata method(.. sopra sarà sempre passare l'istanza MyProtocol al callable servire. (Se si vuole veramente metodi di istanza, ecco le istruzioni su come aggiungere metodi che utilizzano pitone: http: // irrepupavel .com / documenti / python / instancemethod / )

Si avrà bisogno di un sacco di gestione degli errori aggiunto. Per esempio avete bisogno di un sacco di controllo degli errori al call split() sulla linea 2 della dataReceived().

Con questo si può avere file separati con una funzione in loro per ogni metodo è necessario il supporto. In nessun modo un esempio completo ma potrebbe farti andare, poiché ciò che your'e cercando è piuttosto complesso.

Per una registrazione più formale, mi consiglia un dict in MyProtocol con i nomi di metodi che sostenete, lungo le linee di:

# in MyProtocol's __init__() method:
self.methods = {}

E un metodo di registro ..

def register(self, name, callable):
    self.methods[name] = callable

.. modificare dataReceived() ..

def dataReceived(self, data):
    # ...
    modname, funcname = self.methods.get(req['method'], False)
    # ..continue along the lines of the dataReceived() method above

Rapido riepilogo di un troppo lungo post: la funzione __import__ ( http: //docs.python .org / library / functions.html ) sarà certamente una parte fondamentale della soluzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top