Création de nouveaux messages#

Voici un guide simple pour créer un nouveau type de message entre le serveur et les clients dans Flower.

Supposons que nous ayons les fonctions suivantes dans server.py et numpy_client.py

Côté serveur :

def example_request(self, client: ClientProxy) -> Tuple[str, int]:
    question = "Could you find the sum of the list, Bob?"
    l = [1, 2, 3]
    return client.request(question, l)

Côté client :

def example_response(self, question: str, l: List[int]) -> Tuple[str, int]:
    response = "Here you go Alice!"
    answer = sum(question)
    return response, answer

Voyons maintenant ce que nous devons mettre en œuvre pour que cette simple fonction entre le serveur et le client fonctionne !

Types de messages pour les tampons de protocole#

The first thing we need to do is to define a message type for the RPC system in transport.proto. Note that we have to do it for both the request and response messages. For more details on the syntax of proto3, please see the official documentation.

Dans le bloc ServerMessage :

message ExampleIns{
    string question=1;
    repeated int64 l=2;
}
oneof msg {
    ReconnectIns reconnect_ins = 1;
    GetPropertiesIns get_properties_ins = 2;
    GetParametersIns get_parameters_ins = 3;
    FitIns fit_ins = 4;
    EvaluateIns evaluate_ins = 5;
    ExampleIns example_ins = 6;
}

Dans le bloc ClientMessage :

message ExampleRes{
    string response = 1;
    int64 answer = 2;
}

oneof msg {
    DisconnectRes disconnect_res = 1;
    GetPropertiesRes get_properties_res = 2;
    GetParametersRes get_parameters_res = 3;
    FitRes fit_res = 4;
    EvaluateRes evaluate_res = 5;
    ExampleRes examples_res = 6;
}

Veille à ajouter également un champ du type de message nouvellement créé dans oneof msg.

Une fois que c’est fait, nous compilerons le fichier avec :

$ python -m flwr_tool.protoc

S’il se compile avec succès, tu devrais voir le message suivant :

Writing mypy to flwr/proto/transport_pb2.pyi
Writing mypy to flwr/proto/transport_pb2_grpc.pyi

Fonctions de sérialisation et de désérialisation#

La prochaine étape consiste à ajouter des fonctions pour sérialiser et désérialiser les types de données Python vers ou à partir des types de messages RPC définis. Tu dois ajouter ces fonctions dans serde.py.

Les quatre fonctions :

def example_msg_to_proto(question: str, l: List[int]) -> ServerMessage.ExampleIns:
    return ServerMessage.ExampleIns(question=question, l=l)


def example_msg_from_proto(msg: ServerMessage.ExampleIns) -> Tuple[str, List[int]]:
    return msg.question, msg.l


def example_res_to_proto(response: str, answer: int) -> ClientMessage.ExampleRes:
    return ClientMessage.ExampleRes(response=response, answer=answer)


def example_res_from_proto(res: ClientMessage.ExampleRes) -> Tuple[str, int]:
    return res.response, res.answer

Envoi du message à partir du serveur#

Écris maintenant la fonction de demande dans ta classe Client Proxy (par exemple, grpc_client_proxy.py) en utilisant les fonctions serde que tu viens de créer :

def request(self, question: str, l: List[int]) -> Tuple[str, int]:
    request_msg = serde.example_msg_to_proto(question, l)
    client_msg: ClientMessage = self.bridge.request(
        ServerMessage(example_ins=request_msg)
    )
    response, answer = serde.example_res_from_proto(client_msg.examples_res)
    return response, answer

Réception du message par le client#

Dernière étape ! Modifie le code dans message_handler.py pour vérifier le champ de ton message et appeler la fonction example_response. N’oublie pas d’utiliser les fonctions serde !

Dans le cadre de la fonction de poignée :

if server_msg.HasField("example_ins"):
    return _example_response(client, server_msg.example_ins), 0, True

Et ajoute une nouvelle fonction :

def _example_response(client: Client, msg: ServerMessage.ExampleIns) -> ClientMessage:
    question,l = serde.evaluate_ins_from_proto(msg)
    response, answer = client.example_response(question,l)
    example_res = serde.example_res_to_proto(response,answer)
    return ClientMessage(examples_res=example_res)

Avec un peu de chance, lorsque tu exécuteras ton programme, tu obtiendras le résultat escompté !

('Here you go Alice!', 6)