• 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     internal::LockGuard lock(internal::rpc_lock());
62     return {server.OpenContext<kMethod, MethodType::kBidirectionalStreaming>(
63         channel_id,
64         service,
65         internal::MethodLookup::GetRawMethod<
66             ServiceImpl,
67             internal::MethodInfo<kMethod>::kMethodId>())};
68   }
69 
70   using internal::Call::active;
71   using internal::Call::channel_id;
72 
73   // Functions for setting the callbacks.
74   using internal::Call::set_on_error;
75   using internal::Call::set_on_next;
76   using internal::ServerCall::set_on_client_stream_end;
77 
78   // Sends a response packet with the given raw payload.
79   using internal::Call::Write;
80 
81   Status Finish(Status status = OkStatus()) {
82     return CloseAndSendResponse(status);
83   }
84 
85   // Allow use as a generic RPC Writer.
86   using internal::Call::operator Writer&;
87   using internal::Call::operator const Writer&;
88 
89  protected:
90   RawServerReaderWriter(const internal::CallContext& context,
91                         MethodType type = MethodType::kBidirectionalStreaming)
ServerCall(context,type)92       : internal::ServerCall(context, type) {}
93 
94   using internal::Call::CloseAndSendResponse;
95 
96  private:
97   friend class internal::RawMethod;  // Needed to construct
98 
99   template <typename, typename, uint32_t>
100   friend class internal::test::InvocationContext;
101 };
102 
103 // The RawServerReader is used to receive messages and send a response in a
104 // raw client streaming RPC.
105 class RawServerReader : private RawServerReaderWriter {
106  public:
107   // Creates a RawServerReader that is ready to send a response to a particular
108   // RPC. This can be used for testing or to finish an RPC that has not been
109   // started by the client.
110   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)111   [[nodiscard]] static RawServerReader Open(Server& server,
112                                             uint32_t channel_id,
113                                             ServiceImpl& service) {
114     internal::LockGuard lock(internal::rpc_lock());
115     return {server.OpenContext<kMethod, MethodType::kClientStreaming>(
116         channel_id,
117         service,
118         internal::MethodLookup::GetRawMethod<
119             ServiceImpl,
120             internal::MethodInfo<kMethod>::kMethodId>())};
121   }
122 
123   constexpr RawServerReader() = default;
124 
125   RawServerReader(RawServerReader&&) = default;
126   RawServerReader& operator=(RawServerReader&&) = default;
127 
128   using RawServerReaderWriter::active;
129   using RawServerReaderWriter::channel_id;
130 
131   using RawServerReaderWriter::set_on_client_stream_end;
132   using RawServerReaderWriter::set_on_error;
133   using RawServerReaderWriter::set_on_next;
134 
135   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
136     return CloseAndSendResponse(response, status);
137   }
138 
139  private:
140   friend class internal::RawMethod;  // Needed for conversions from ReaderWriter
141 
142   template <typename, typename, uint32_t>
143   friend class internal::test::InvocationContext;
144 
RawServerReader(const internal::CallContext & context)145   RawServerReader(const internal::CallContext& context)
146       : RawServerReaderWriter(context, MethodType::kClientStreaming) {}
147 };
148 
149 // The RawServerWriter is used to send responses in a raw server streaming RPC.
150 class RawServerWriter : private RawServerReaderWriter {
151  public:
152   // Creates a RawServerWriter that is ready to send responses for a particular
153   // RPC. This can be used for testing or to send responses to an RPC that has
154   // not been started by a client.
155   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)156   [[nodiscard]] static RawServerWriter Open(Server& server,
157                                             uint32_t channel_id,
158                                             ServiceImpl& service) {
159     internal::LockGuard lock(internal::rpc_lock());
160     return {server.OpenContext<kMethod, MethodType::kServerStreaming>(
161         channel_id,
162         service,
163         internal::MethodLookup::GetRawMethod<
164             ServiceImpl,
165             internal::MethodInfo<kMethod>::kMethodId>())};
166   }
167 
168   constexpr RawServerWriter() = default;
169 
170   RawServerWriter(RawServerWriter&&) = default;
171   RawServerWriter& operator=(RawServerWriter&&) = default;
172 
173   using RawServerReaderWriter::active;
174   using RawServerReaderWriter::channel_id;
175 
176   using RawServerReaderWriter::set_on_error;
177 
178   using RawServerReaderWriter::Finish;
179   using RawServerReaderWriter::Write;
180 
181   // Allow use as a generic RPC Writer.
182   using internal::Call::operator Writer&;
183   using internal::Call::operator const Writer&;
184 
185  private:
186   template <typename, typename, uint32_t>
187   friend class internal::test::InvocationContext;
188 
189   friend class internal::RawMethod;
190 
RawServerWriter(const internal::CallContext & context)191   RawServerWriter(const internal::CallContext& context)
192       : RawServerReaderWriter(context, MethodType::kServerStreaming) {}
193 };
194 
195 // The RawUnaryResponder is used to send a response in a raw unary RPC.
196 class RawUnaryResponder : private RawServerReaderWriter {
197  public:
198   // Creates a RawUnaryResponder that is ready to send responses for a
199   // particular RPC. This can be used for testing or to send responses to an RPC
200   // that has not been started by a client.
201   template <auto kMethod, typename ServiceImpl>
Open(Server & server,uint32_t channel_id,ServiceImpl & service)202   [[nodiscard]] static RawUnaryResponder Open(Server& server,
203                                               uint32_t channel_id,
204                                               ServiceImpl& service) {
205     internal::LockGuard lock(internal::rpc_lock());
206     return {server.OpenContext<kMethod, MethodType::kUnary>(
207         channel_id,
208         service,
209         internal::MethodLookup::GetRawMethod<
210             ServiceImpl,
211             internal::MethodInfo<kMethod>::kMethodId>())};
212   }
213 
214   constexpr RawUnaryResponder() = default;
215 
216   RawUnaryResponder(RawUnaryResponder&&) = default;
217   RawUnaryResponder& operator=(RawUnaryResponder&&) = default;
218 
219   using RawServerReaderWriter::active;
220   using RawServerReaderWriter::channel_id;
221 
222   using RawServerReaderWriter::set_on_error;
223 
224   Status Finish(ConstByteSpan response, Status status = OkStatus()) {
225     return CloseAndSendResponse(response, status);
226   }
227 
228  private:
229   template <typename, typename, uint32_t>
230   friend class internal::test::InvocationContext;
231 
232   friend class internal::RawMethod;
233 
RawUnaryResponder(const internal::CallContext & context)234   RawUnaryResponder(const internal::CallContext& context)
235       : RawServerReaderWriter(context, MethodType::kUnary) {}
236 };
237 
238 }  // namespace pw::rpc
239