Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_rpc / nanopb / docs.rst
1 .. _module-pw_rpc_nanopb:
2
3 ------
4 nanopb
5 ------
6 ``pw_rpc`` can generate services which encode/decode RPC requests and responses
7 as nanopb message structs.
8
9 Usage
10 =====
11 To enable nanopb code generation, the build argument
12 ``dir_pw_third_party_nanopb`` must be set to point to a local nanopb
13 installation.
14
15 Define a ``pw_proto_library`` containing the .proto file defining your service
16 (and optionally other related protos), then depend on the ``nanopb_rpc``
17 version of that library in the code implementing the service.
18
19 .. code::
20
21   # chat/BUILD.gn
22
23   import("$dir_pw_build/target_types.gni")
24   import("$dir_pw_protobuf_compiler/proto.gni")
25
26   pw_proto_library("chat_protos") {
27     sources = [ "chat_protos/chat_service.proto" ]
28   }
29
30   # Library that implements the ChatService.
31   pw_source_set("chat_service") {
32     sources = [
33       "chat_service.cc",
34       "chat_service.h",
35     ]
36     public_deps = [ ":chat_protos.nanopb_rpc" ]
37   }
38
39 A C++ header file is generated for each input .proto file, with the ``.proto``
40 extension replaced by ``.rpc.pb.h``. For example, given the input file
41 ``chat_protos/chat_service.proto``, the generated header file will be placed
42 at the include path ``"chat_protos/chat_service.rpc.pb.h"``.
43
44 Generated code API
45 ==================
46 Take the following RPC service as an example.
47
48 .. code:: protobuf
49
50   // chat/chat_protos/chat_service.proto
51
52   syntax = "proto3";
53
54   service ChatService {
55     // Returns information about a chatroom.
56     rpc GetRoomInformation(RoomInfoRequest) returns (RoomInfoResponse) {}
57
58     // Lists all of the users in a chatroom. The response is streamed as there
59     // may be a large amount of users.
60     rpc ListUsersInRoom(ListUsersRequest) returns (stream ListUsersResponse) {}
61
62     // Uploads a file, in chunks, to a chatroom.
63     rpc UploadFile(stream UploadFileRequest) returns (UploadFileResponse) {}
64
65     // Sends messages to a chatroom while receiving messages from other users.
66     rpc Chat(stream ChatMessage) returns (stream ChatMessage) {}
67   }
68
69 Server-side
70 -----------
71 A C++ class is generated for each service in the .proto file. The class is
72 located within a special ``generated`` sub-namespace of the file's package.
73
74 The generated class is a base class which must be derived to implement the
75 service's methods. The base class is templated on the derived class.
76
77 .. code:: c++
78
79   #include "chat_protos/chat_service.rpc.pb.h"
80
81   class ChatService final : public generated::ChatService<ChatService> {
82    public:
83     // Implementations of the service's RPC methods; see below.
84   };
85
86 Unary RPC
87 ^^^^^^^^^
88 A unary RPC is implemented as a function which takes in the RPC's request struct
89 and populates a response struct to send back, with a status indicating whether
90 the request succeeded.
91
92 .. code:: c++
93
94   pw::Status GetRoomInformation(pw::rpc::ServerContext& ctx,
95                                 const RoomInfoRequest& request,
96                                 RoomInfoResponse& response);
97
98 Server streaming RPC
99 ^^^^^^^^^^^^^^^^^^^^
100 A server streaming RPC receives the client's request message alongside a
101 ``ServerWriter``, used to stream back responses.
102
103 .. code:: c++
104
105   void ListUsersInRoom(pw::rpc::ServerContext& ctx,
106                        const ListUsersRequest& request,
107                        pw::rpc::ServerWriter<ListUsersResponse>& writer);
108
109 The ``ServerWriter`` object is movable, and remains active until it is manually
110 closed or goes out of scope. The writer has a simple API to return responses:
111
112 .. cpp:function:: Status ServerWriter::Write(const T& response)
113
114   Writes a single response message to the stream. The returned status indicates
115   whether the write was successful.
116
117 .. cpp:function:: void ServerWriter::Finish(Status status = OkStatus())
118
119   Closes the stream and sends back the RPC's overall status to the client.
120
121 Once a ``ServerWriter`` has been closed, all future ``Write`` calls will fail.
122
123 .. attention::
124
125   Make sure to use ``std::move`` when passing the ``ServerWriter`` around to
126   avoid accidentally closing it and ending the RPC.
127
128 Client streaming RPC
129 ^^^^^^^^^^^^^^^^^^^^
130 .. attention::
131
132   ``pw_rpc`` does not yet support client streaming RPCs.
133
134 Bidirectional streaming RPC
135 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
136 .. attention::
137
138   ``pw_rpc`` does not yet support bidirectional streaming RPCs.
139
140 Client-side
141 -----------
142 A corresponding client class is generated for every service defined in the proto
143 file. Like the service class, it is placed under the ``generated`` namespace.
144 The class is named after the service, with a ``Client`` suffix. For example, the
145 ``ChatService`` would create a ``generated::ChatServiceClient``.
146
147 The client class contains static methods to call each of the service's methods.
148 It is not meant to be instantiated. The signatures for the methods all follow
149 the same format, taking a channel through which to communicate, the initial
150 request struct, and a response handler.
151
152 .. code-block:: c++
153
154   static NanopbClientCall<UnaryResponseHandler<RoomInfoResponse>>
155   GetRoomInformation(Channel& channel,
156                      const RoomInfoRequest& request,
157                      UnaryResponseHandler<RoomInfoResponse> handler);
158
159 The ``NanopbClientCall`` object returned by the RPC invocation stores the active
160 RPC's context. For more information on ``ClientCall`` objects, refer to the
161 :ref:`core RPC documentation <module-pw_rpc-making-calls>`.
162
163 Response handlers
164 ^^^^^^^^^^^^^^^^^
165 RPC responses are sent back to the caller through a response handler object.
166 These are classes with virtual callback functions implemented by the RPC caller
167 to handle RPC events.
168
169 There are two types of response handlers: unary and server-streaming, which are
170 used depending whether the method's responses are a stream or not.
171
172 Unary / client streaming RPC
173 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174 A ``UnaryResponseHandler`` is used by methods where the server returns a single
175 response. It contains a callback for the response, which is only called once.
176
177 .. code-block:: c++
178
179   template <typename Response>
180   class UnaryResponseHandler {
181    public:
182     virtual ~UnaryResponseHandler() = default;
183
184     // Called when the response is received from the server with the method's
185     // status and the deserialized response struct.
186     virtual void ReceivedResponse(Status status, const Response& response) = 0;
187
188     // Called when an error occurs internally in the RPC client or server.
189     virtual void RpcError(Status) {}
190   };
191
192 .. cpp:class:: template <typename Response> UnaryResponseHandler
193
194   A handler for RPC methods which return a single response (i.e. unary and
195   client streaming).
196
197 .. cpp:function:: virtual void UnaryResponseHandler::ReceivedResponse(Status status, const Response& response)
198
199   Callback invoked when the response is recieved from the server. Guaranteed to
200   only be called once.
201
202 .. cpp:function:: virtual void UnaryResponseHandler::RpcError(Status status)
203
204   Callback invoked if an internal error occurs in the RPC system. Optional;
205   defaults to a no-op.
206
207 **Example implementation**
208
209 .. code-block:: c++
210
211   class RoomInfoHandler : public UnaryResponseHandler<RoomInfoResponse> {
212    public:
213     void ReceivedResponse(Status status,
214                           const RoomInfoResponse& response) override {
215       if (status.ok()) {
216         response_ = response;
217       }
218     }
219
220     constexpr RoomInfoResponse& response() { return response_; }
221
222    private:
223     RoomInfoResponse response_;
224   };
225
226 Server streaming / bidirectional streaming RPC
227 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228 For methods which return a response stream, a ``ServerStreamingResponseHandler``
229 is used.
230
231 .. code:: c++
232
233   class ServerStreamingResponseHandler {
234    public:
235     virtual ~ServerStreamingResponseHandler() = default;
236
237     // Called on every response received from the server with the deserialized
238     // response struct.
239     virtual void ReceivedResponse(const Response& response) = 0;
240
241     // Called when the server ends the stream with the overall RPC status.
242     virtual void Complete(Status status) = 0;
243
244     // Called when an error occurs internally in the RPC client or server.
245     virtual void RpcError(Status) {}
246   };
247
248 .. cpp:class:: template <typename Response> ServerStreamingResponseHandler
249
250   A handler for RPC methods which return zero or more responses (i.e. server
251   and bidirectional streaming).
252
253 .. cpp:function:: virtual void ServerStreamingResponseHandler::ReceivedResponse(const Response& response)
254
255   Callback invoked whenever a response is received from the server.
256
257 .. cpp:function:: virtual void ServerStreamingResponseHandler::Complete(Status status)
258
259   Callback invoked when the server ends the stream, with the overall status for
260   the RPC.
261
262 .. cpp:function:: virtual void ServerStreamingResponseHandler::RpcError(Status status)
263
264   Callback invoked if an internal error occurs in the RPC system. Optional;
265   defaults to a no-op.
266
267 **Example implementation**
268
269 .. code-block:: c++
270
271   class ChatHandler : public UnaryResponseHandler<ChatMessage> {
272    public:
273     void ReceivedResponse(const ChatMessage& response) override {
274       gui_.RenderChatMessage(response);
275     }
276
277     void Complete(Status status) override {
278       client_.Exit(status);
279     }
280
281    private:
282     ChatGui& gui_;
283     ChatClient& client_;
284   };
285
286 Example usage
287 ~~~~~~~~~~~~~
288 The following example demonstrates how to call an RPC method using a nanopb
289 service client and receive the response.
290
291 .. code-block:: c++
292
293   #include "chat_protos/chat_service.rpc.pb.h"
294
295   namespace {
296     MyChannelOutput output;
297     pw::rpc::Channel channels[] = {pw::rpc::Channel::Create<0>(&output)};
298     pw::rpc::Client client(channels);
299   }
300
301   void InvokeSomeRpcs() {
302     RoomInfoHandler handler;
303
304     // The RPC will remain active as long as `call` is alive.
305     auto call = ChatServiceClient::GetRoomInformation(channels[0],
306                                                       {.room = "pigweed"},
307                                                       handler);
308
309     // For simplicity, block here. An actual implementation would likely
310     // std::move the call somewhere to keep it active while doing other work.
311     while (call.active()) {
312       Wait();
313     }
314
315     DoStuff(handler.response());
316   }