xref: /aosp_15_r20/external/pigweed/pw_rpc/raw/public/pw_rpc/raw/server_reader_writer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // This file defines the ServerReaderWriter, ServerReader, and ServerWriter
16 // classes for the raw RPC interface. These classes are used for bidirectional,
17 // client, and server streaming RPCs.
18 #pragma once
19 
20 #include "pw_bytes/span.h"
21 #include "pw_rpc/channel.h"
22 #include "pw_rpc/internal/method_info.h"
23 #include "pw_rpc/internal/method_lookup.h"
24 #include "pw_rpc/internal/server_call.h"
25 #include "pw_rpc/server.h"
26 #include "pw_rpc/writer.h"
27 #include "pw_status/status_with_size.h"
28 
29 namespace pw::rpc {
30 namespace internal {
31 
32 // Forward declarations for internal classes needed in friend statements.
33 class RawMethod;
34 
35 namespace test {
36 
37 template <typename, typename, uint32_t>
38 class InvocationContext;
39 
40 }  // namespace test
41 }  // namespace internal
42 
43 class RawServerReader;
44 class RawServerWriter;
45 
46 // The RawServerReaderWriter is used to send and receive messages in a raw
47 // bidirectional streaming RPC.
48 class RawServerReaderWriter : private internal::ServerCall {
49  public:
50   constexpr RawServerReaderWriter() = default;
51 
52   RawServerReaderWriter(RawServerReaderWriter&&) = default;
53   RawServerReaderWriter& operator=(RawServerReaderWriter&&) = default;
54 
55   // Creates a RawServerReaderWriter that is ready to send responses for a
56   // particular RPC. This can be used for testing or to send responses to an RPC
57   // that has not been started by a client.
58   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)59   [[nodiscard]] static RawServerReaderWriter Open(Server& server,
60                                                   uint32_t channel_id,
61                                                   ServiceImpl& service)
62       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
63     return server.OpenCall<RawServerReaderWriter,
64                            kMethod,
65                            MethodType::kBidirectionalStreaming>(
66         channel_id,
67         service,
68         internal::MethodLookup::GetRawMethod<
69             ServiceImpl,
70             internal::MethodInfo<kMethod>::kMethodId>());
71   }
72 
73   using internal::Call::active;
74   using internal::Call::channel_id;
75 
76   // Functions for setting the callbacks.
77   using internal::Call::set_on_error;
78   using internal::Call::set_on_next;
79   using internal::ServerCall::set_on_completion_requested;
80   using internal::ServerCall::set_on_completion_requested_if_enabled;
81 
82   // Sends a response packet with the given raw payload.
83   using internal::Call::Write;
84 
85   Status Finish(Status status = OkStatus()) {
86     return CloseAndSendResponse(status);
87   }
88 
89   Status TryFinish(Status status = OkStatus()) {
90     return TryCloseAndSendResponse(status);
91   }
92 
93   // Allow use as a generic RPC Writer.
94   using internal::Call::as_writer;
95 
96  protected:
RawServerReaderWriter(const internal::LockedCallContext & context,MethodType type)97   RawServerReaderWriter(const internal::LockedCallContext& context,
98                         MethodType type)
99       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
100       : internal::ServerCall(
101             context,
102             internal::CallProperties(
103                 type, internal::kServerCall, internal::kRawProto)) {}
104 
105   using internal::Call::CloseAndSendResponse;
106   using internal::Call::TryCloseAndSendResponse;
107 
108   using internal::Call::CloseAndSendResponseCallback;
109   using internal::Call::TryCloseAndSendResponseCallback;
110 
111  private:
112   friend class internal::RawMethod;  // Needed to construct
113   friend class Server;
114 
115   template <typename, typename, uint32_t>
116   friend class internal::test::InvocationContext;
117 
118   // Private constructor for test use
RawServerReaderWriter(const internal::LockedCallContext & context)119   RawServerReaderWriter(const internal::LockedCallContext& context)
120       : RawServerReaderWriter(context, MethodType::kBidirectionalStreaming) {}
121 };
122 
123 // The RawServerReader is used to receive messages and send a response in a
124 // raw client streaming RPC.
125 class RawServerReader : private RawServerReaderWriter {
126  public:
127   // Creates a RawServerReader that is ready to send a response to a particular
128   // RPC. This can be used for testing or to finish an RPC that has not been
129   // started by the client.
130   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)131   [[nodiscard]] static RawServerReader Open(Server& server,
132                                             uint32_t channel_id,
133                                             ServiceImpl& service)
134       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
135     return server
136         .OpenCall<RawServerReader, kMethod, MethodType::kClientStreaming>(
137             channel_id,
138             service,
139             internal::MethodLookup::GetRawMethod<
140                 ServiceImpl,
141                 internal::MethodInfo<kMethod>::kMethodId>());
142   }
143 
144   constexpr RawServerReader() = default;
145 
146   RawServerReader(RawServerReader&&) = default;
147   RawServerReader& operator=(RawServerReader&&) = default;
148 
149   using RawServerReaderWriter::active;
150   using RawServerReaderWriter::channel_id;
151 
152   using RawServerReaderWriter::set_on_completion_requested;
153   using RawServerReaderWriter::set_on_completion_requested_if_enabled;
154   using RawServerReaderWriter::set_on_error;
155   using RawServerReaderWriter::set_on_next;
156 
157   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
158     return CloseAndSendResponse(response, status);
159   }
160 
161   Status TryFinish(ConstByteSpan response, Status status = OkStatus()) {
162     return TryCloseAndSendResponse(response, status);
163   }
164 
165  private:
166   friend class internal::RawMethod;  // Needed for conversions from ReaderWriter
167   friend class Server;
168 
169   template <typename, typename, uint32_t>
170   friend class internal::test::InvocationContext;
171 
172   RawServerReader(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())173       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
174       : RawServerReaderWriter(context, MethodType::kClientStreaming) {}
175 };
176 
177 // The RawServerWriter is used to send responses in a raw server streaming RPC.
178 class RawServerWriter : private RawServerReaderWriter {
179  public:
180   // Creates a RawServerWriter that is ready to send responses for a particular
181   // RPC. This can be used for testing or to send responses to an RPC that has
182   // not been started by a client.
183   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)184   [[nodiscard]] static RawServerWriter Open(Server& server,
185                                             uint32_t channel_id,
186                                             ServiceImpl& service)
187       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
188     return server
189         .OpenCall<RawServerWriter, kMethod, MethodType::kServerStreaming>(
190             channel_id,
191             service,
192             internal::MethodLookup::GetRawMethod<
193                 ServiceImpl,
194                 internal::MethodInfo<kMethod>::kMethodId>());
195   }
196 
197   constexpr RawServerWriter() = default;
198 
199   RawServerWriter(RawServerWriter&&) = default;
200   RawServerWriter& operator=(RawServerWriter&&) = default;
201 
202   using RawServerReaderWriter::active;
203   using RawServerReaderWriter::channel_id;
204 
205   using RawServerReaderWriter::set_on_completion_requested;
206   using RawServerReaderWriter::set_on_completion_requested_if_enabled;
207   using RawServerReaderWriter::set_on_error;
208 
209   using RawServerReaderWriter::Finish;
210   using RawServerReaderWriter::TryFinish;
211 
212   using RawServerReaderWriter::Write;
213 
214   // Allow use as a generic RPC Writer.
215   using internal::Call::as_writer;
216 
217  private:
218   friend class internal::RawMethod;
219   friend class Server;
220 
221   template <typename, typename, uint32_t>
222   friend class internal::test::InvocationContext;
223 
224   RawServerWriter(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())225       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
226       : RawServerReaderWriter(context, MethodType::kServerStreaming) {}
227 };
228 
229 // The RawUnaryResponder is used to send a response in a raw unary RPC.
230 class RawUnaryResponder : private RawServerReaderWriter {
231  public:
232   // Creates a RawUnaryResponder that is ready to send responses for a
233   // particular RPC. This can be used for testing or to send responses to an RPC
234   // that has not been started by a client.
235   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)236   [[nodiscard]] static RawUnaryResponder Open(Server& server,
237                                               uint32_t channel_id,
238                                               ServiceImpl& service)
239       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
240     return server.OpenCall<RawUnaryResponder, kMethod, MethodType::kUnary>(
241         channel_id,
242         service,
243         internal::MethodLookup::GetRawMethod<
244             ServiceImpl,
245             internal::MethodInfo<kMethod>::kMethodId>());
246   }
247 
248   constexpr RawUnaryResponder() = default;
249 
250   RawUnaryResponder(RawUnaryResponder&&) = default;
251   RawUnaryResponder& operator=(RawUnaryResponder&&) = default;
252 
253   using RawServerReaderWriter::active;
254   using RawServerReaderWriter::channel_id;
255 
256   using RawServerReaderWriter::set_on_error;
257 
258   /// Completes the RPC call with the provided response and status.
259   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
260     return CloseAndSendResponse(response, status);
261   }
262 
263   /// Completes the RPC call with the provided status, invoking a callback with
264   /// the response payload buffer into which the response can be encoded.
265   Status FinishCallback(const Function<StatusWithSize(ByteSpan)>& callback,
266                         Status status = OkStatus()) {
267     return CloseAndSendResponseCallback(callback, status);
268   }
269 
270   Status TryFinish(ConstByteSpan response, Status status = OkStatus()) {
271     return TryCloseAndSendResponse(response, status);
272   }
273 
274   Status TryFinishCallback(const Function<StatusWithSize(ByteSpan)>& callback,
275                            Status status = OkStatus()) {
276     return TryCloseAndSendResponseCallback(callback, status);
277   }
278 
279  private:
280   friend class internal::RawMethod;
281   friend class Server;
282 
283   template <typename, typename, uint32_t>
284   friend class internal::test::InvocationContext;
285 
286   RawUnaryResponder(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())287       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
288       : RawServerReaderWriter(context, MethodType::kUnary) {}
289 };
290 
291 }  // namespace pw::rpc
292