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