• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
28 namespace pw::rpc {
29 namespace internal {
30 
31 // Forward declarations for internal classes needed in friend statements.
32 class RawMethod;
33 
34 namespace test {
35 
36 template <typename, typename, uint32_t>
37 class InvocationContext;
38 
39 }  // namespace test
40 }  // namespace internal
41 
42 class RawServerReader;
43 class RawServerWriter;
44 
45 // The RawServerReaderWriter is used to send and receive messages in a raw
46 // bidirectional streaming RPC.
47 class RawServerReaderWriter : private internal::ServerCall {
48  public:
49   constexpr RawServerReaderWriter() = default;
50 
51   RawServerReaderWriter(RawServerReaderWriter&&) = default;
52   RawServerReaderWriter& operator=(RawServerReaderWriter&&) = default;
53 
54   // Creates a RawServerReaderWriter that is ready to send responses for a
55   // particular RPC. This can be used for testing or to send responses to an RPC
56   // that has not been started by a client.
57   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)58   [[nodiscard]] static RawServerReaderWriter Open(Server& server,
59                                                   uint32_t channel_id,
60                                                   ServiceImpl& service)
61       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
62     return server.OpenCall<RawServerReaderWriter,
63                            kMethod,
64                            MethodType::kBidirectionalStreaming>(
65         channel_id,
66         service,
67         internal::MethodLookup::GetRawMethod<
68             ServiceImpl,
69             internal::MethodInfo<kMethod>::kMethodId>());
70   }
71 
72   using internal::Call::active;
73   using internal::Call::channel_id;
74 
75   // Functions for setting the callbacks.
76   using internal::Call::set_on_error;
77   using internal::Call::set_on_next;
78   using internal::ServerCall::set_on_completion_requested;
79   using internal::ServerCall::set_on_completion_requested_if_enabled;
80 
81   // Sends a response packet with the given raw payload.
82   using internal::Call::Write;
83 
84   Status Finish(Status status = OkStatus()) {
85     return CloseAndSendResponse(status);
86   }
87 
88   Status TryFinish(Status status = OkStatus()) {
89     return TryCloseAndSendResponse(status);
90   }
91 
92   // Allow use as a generic RPC Writer.
93   using internal::Call::as_writer;
94 
95  protected:
RawServerReaderWriter(const internal::LockedCallContext & context,MethodType type)96   RawServerReaderWriter(const internal::LockedCallContext& context,
97                         MethodType type)
98       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
99       : internal::ServerCall(
100             context,
101             internal::CallProperties(
102                 type, internal::kServerCall, internal::kRawProto)) {}
103 
104   using internal::Call::CloseAndSendResponse;
105   using internal::Call::TryCloseAndSendResponse;
106 
107  private:
108   friend class internal::RawMethod;  // Needed to construct
109   friend class Server;
110 
111   template <typename, typename, uint32_t>
112   friend class internal::test::InvocationContext;
113 
114   // Private constructor for test use
RawServerReaderWriter(const internal::LockedCallContext & context)115   RawServerReaderWriter(const internal::LockedCallContext& context)
116       : RawServerReaderWriter(context, MethodType::kBidirectionalStreaming) {}
117 };
118 
119 // The RawServerReader is used to receive messages and send a response in a
120 // raw client streaming RPC.
121 class RawServerReader : private RawServerReaderWriter {
122  public:
123   // Creates a RawServerReader that is ready to send a response to a particular
124   // RPC. This can be used for testing or to finish an RPC that has not been
125   // started by the client.
126   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)127   [[nodiscard]] static RawServerReader Open(Server& server,
128                                             uint32_t channel_id,
129                                             ServiceImpl& service)
130       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
131     return server
132         .OpenCall<RawServerReader, kMethod, MethodType::kClientStreaming>(
133             channel_id,
134             service,
135             internal::MethodLookup::GetRawMethod<
136                 ServiceImpl,
137                 internal::MethodInfo<kMethod>::kMethodId>());
138   }
139 
140   constexpr RawServerReader() = default;
141 
142   RawServerReader(RawServerReader&&) = default;
143   RawServerReader& operator=(RawServerReader&&) = default;
144 
145   using RawServerReaderWriter::active;
146   using RawServerReaderWriter::channel_id;
147 
148   using RawServerReaderWriter::set_on_completion_requested;
149   using RawServerReaderWriter::set_on_completion_requested_if_enabled;
150   using RawServerReaderWriter::set_on_error;
151   using RawServerReaderWriter::set_on_next;
152 
153   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
154     return CloseAndSendResponse(response, status);
155   }
156 
157   Status TryFinish(ConstByteSpan response, Status status = OkStatus()) {
158     return TryCloseAndSendResponse(response, status);
159   }
160 
161  private:
162   friend class internal::RawMethod;  // Needed for conversions from ReaderWriter
163   friend class Server;
164 
165   template <typename, typename, uint32_t>
166   friend class internal::test::InvocationContext;
167 
168   RawServerReader(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())169       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
170       : RawServerReaderWriter(context, MethodType::kClientStreaming) {}
171 };
172 
173 // The RawServerWriter is used to send responses in a raw server streaming RPC.
174 class RawServerWriter : private RawServerReaderWriter {
175  public:
176   // Creates a RawServerWriter that is ready to send responses for a particular
177   // RPC. This can be used for testing or to send responses to an RPC that has
178   // not been started by a client.
179   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)180   [[nodiscard]] static RawServerWriter Open(Server& server,
181                                             uint32_t channel_id,
182                                             ServiceImpl& service)
183       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
184     return server
185         .OpenCall<RawServerWriter, kMethod, MethodType::kServerStreaming>(
186             channel_id,
187             service,
188             internal::MethodLookup::GetRawMethod<
189                 ServiceImpl,
190                 internal::MethodInfo<kMethod>::kMethodId>());
191   }
192 
193   constexpr RawServerWriter() = default;
194 
195   RawServerWriter(RawServerWriter&&) = default;
196   RawServerWriter& operator=(RawServerWriter&&) = default;
197 
198   using RawServerReaderWriter::active;
199   using RawServerReaderWriter::channel_id;
200 
201   using RawServerReaderWriter::set_on_completion_requested;
202   using RawServerReaderWriter::set_on_completion_requested_if_enabled;
203   using RawServerReaderWriter::set_on_error;
204 
205   using RawServerReaderWriter::Finish;
206   using RawServerReaderWriter::TryFinish;
207 
208   using RawServerReaderWriter::Write;
209 
210   // Allow use as a generic RPC Writer.
211   using internal::Call::as_writer;
212 
213  private:
214   friend class internal::RawMethod;
215   friend class Server;
216 
217   template <typename, typename, uint32_t>
218   friend class internal::test::InvocationContext;
219 
220   RawServerWriter(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())221       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
222       : RawServerReaderWriter(context, MethodType::kServerStreaming) {}
223 };
224 
225 // The RawUnaryResponder is used to send a response in a raw unary RPC.
226 class RawUnaryResponder : private RawServerReaderWriter {
227  public:
228   // Creates a RawUnaryResponder that is ready to send responses for a
229   // particular RPC. This can be used for testing or to send responses to an RPC
230   // that has not been started by a client.
231   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)232   [[nodiscard]] static RawUnaryResponder Open(Server& server,
233                                               uint32_t channel_id,
234                                               ServiceImpl& service)
235       PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
236     return server.OpenCall<RawUnaryResponder, kMethod, MethodType::kUnary>(
237         channel_id,
238         service,
239         internal::MethodLookup::GetRawMethod<
240             ServiceImpl,
241             internal::MethodInfo<kMethod>::kMethodId>());
242   }
243 
244   constexpr RawUnaryResponder() = default;
245 
246   RawUnaryResponder(RawUnaryResponder&&) = default;
247   RawUnaryResponder& operator=(RawUnaryResponder&&) = default;
248 
249   using RawServerReaderWriter::active;
250   using RawServerReaderWriter::channel_id;
251 
252   using RawServerReaderWriter::set_on_error;
253 
254   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
255     return CloseAndSendResponse(response, status);
256   }
257 
258   Status TryFinish(ConstByteSpan response, Status status = OkStatus()) {
259     return TryCloseAndSendResponse(response, status);
260   }
261 
262  private:
263   friend class internal::RawMethod;
264   friend class Server;
265 
266   template <typename, typename, uint32_t>
267   friend class internal::test::InvocationContext;
268 
269   RawUnaryResponder(const internal::LockedCallContext& context)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock ())270       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
271       : RawServerReaderWriter(context, MethodType::kUnary) {}
272 };
273 
274 }  // namespace pw::rpc
275