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