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