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