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 #pragma once 15 16 #include <cstdint> 17 18 #include "pw_bytes/span.h" 19 #include "pw_function/function.h" 20 #include "pw_rpc/internal/call.h" 21 #include "pw_rpc/internal/endpoint.h" 22 #include "pw_rpc/internal/lock.h" 23 24 namespace pw::rpc::internal { 25 26 // A Call object, as used by an RPC client. 27 class ClientCall : public Call { 28 public: ~ClientCall()29 ~ClientCall() PW_LOCKS_EXCLUDED(rpc_lock()) { Abandon(); } 30 id()31 uint32_t id() const PW_LOCKS_EXCLUDED(rpc_lock()) { 32 RpcLockGuard lock; 33 return Call::id(); 34 } 35 36 protected: 37 // Initializes CallProperties for a struct-based client call impl. StructCallProps(MethodType type)38 static constexpr CallProperties StructCallProps(MethodType type) { 39 return CallProperties(type, kClientCall, kProtoStruct); 40 } 41 42 // Initializes CallProperties for a raw client call. RawCallProps(MethodType type)43 static constexpr CallProperties RawCallProps(MethodType type) { 44 return CallProperties(type, kClientCall, kRawProto); 45 } 46 47 constexpr ClientCall() = default; 48 ClientCall(LockedEndpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,CallProperties properties)49 ClientCall(LockedEndpoint& client, 50 uint32_t channel_id, 51 uint32_t service_id, 52 uint32_t method_id, 53 CallProperties properties) PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) 54 : Call(client, channel_id, service_id, method_id, properties) {} 55 56 // Public function that closes a call client-side without cancelling it on the 57 // server. Abandon()58 void Abandon() PW_LOCKS_EXCLUDED(rpc_lock()) { 59 RpcLockGuard lock; 60 CloseClientCall(); 61 } 62 63 // Sends CLIENT_STREAM_END if applicable and marks the call as closed. 64 void CloseClientCall() PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()); 65 66 void MoveClientCallFrom(ClientCall& other) 67 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()); 68 }; 69 70 // Unary response client calls receive both a payload and the status in their 71 // on_completed callback. The on_next callback is not used. 72 class UnaryResponseClientCall : public ClientCall { 73 public: 74 // Start call for raw unary response RPCs. 75 template <typename CallType> Start(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,Function<void (ConstByteSpan,Status)> && on_completed,Function<void (Status)> && on_error,ConstByteSpan request)76 static CallType Start(Endpoint& client, 77 uint32_t channel_id, 78 uint32_t service_id, 79 uint32_t method_id, 80 Function<void(ConstByteSpan, Status)>&& on_completed, 81 Function<void(Status)>&& on_error, 82 ConstByteSpan request) PW_LOCKS_EXCLUDED(rpc_lock()) { 83 rpc_lock().lock(); 84 CallType call(client.ClaimLocked(), channel_id, service_id, method_id); 85 call.set_on_completed_locked(std::move(on_completed)); 86 call.set_on_error_locked(std::move(on_error)); 87 88 call.SendInitialClientRequest(request); 89 client.CleanUpCalls(); 90 return call; 91 } 92 93 void HandleCompleted(ConstByteSpan response, Status status) 94 PW_UNLOCK_FUNCTION(rpc_lock()); 95 96 protected: 97 constexpr UnaryResponseClientCall() = default; 98 UnaryResponseClientCall(LockedEndpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,CallProperties properties)99 UnaryResponseClientCall(LockedEndpoint& client, 100 uint32_t channel_id, 101 uint32_t service_id, 102 uint32_t method_id, 103 CallProperties properties) 104 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) 105 : ClientCall(client, channel_id, service_id, method_id, properties) {} 106 UnaryResponseClientCall(UnaryResponseClientCall && other)107 UnaryResponseClientCall(UnaryResponseClientCall&& other) { 108 *this = std::move(other); 109 } 110 111 UnaryResponseClientCall& operator=(UnaryResponseClientCall&& other) PW_LOCKS_EXCLUDED(rpc_lock ())112 PW_LOCKS_EXCLUDED(rpc_lock()) { 113 RpcLockGuard lock; 114 MoveUnaryResponseClientCallFrom(other); 115 return *this; 116 } 117 MoveUnaryResponseClientCallFrom(UnaryResponseClientCall & other)118 void MoveUnaryResponseClientCallFrom(UnaryResponseClientCall& other) 119 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) { 120 MoveClientCallFrom(other); 121 on_completed_ = std::move(other.on_completed_); 122 } 123 set_on_completed(Function<void (ConstByteSpan,Status)> && on_completed)124 void set_on_completed(Function<void(ConstByteSpan, Status)>&& on_completed) 125 PW_LOCKS_EXCLUDED(rpc_lock()) { 126 RpcLockGuard lock; 127 set_on_completed_locked(std::move(on_completed)); 128 } 129 set_on_completed_locked(Function<void (ConstByteSpan,Status)> && on_completed)130 void set_on_completed_locked( 131 Function<void(ConstByteSpan, Status)>&& on_completed) 132 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) { 133 on_completed_ = std::move(on_completed); 134 } 135 136 private: 137 using internal::ClientCall::set_on_next; // Not used in unary response calls. 138 139 Function<void(ConstByteSpan, Status)> on_completed_ PW_GUARDED_BY(rpc_lock()); 140 }; 141 142 // Stream response client calls only receive the status in their on_completed 143 // callback. Payloads are sent through the on_next callback. 144 class StreamResponseClientCall : public ClientCall { 145 public: 146 // Start call for raw stream response RPCs. 147 template <typename CallType> Start(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,Function<void (ConstByteSpan)> && on_next,Function<void (Status)> && on_completed,Function<void (Status)> && on_error,ConstByteSpan request)148 static CallType Start(Endpoint& client, 149 uint32_t channel_id, 150 uint32_t service_id, 151 uint32_t method_id, 152 Function<void(ConstByteSpan)>&& on_next, 153 Function<void(Status)>&& on_completed, 154 Function<void(Status)>&& on_error, 155 ConstByteSpan request) { 156 rpc_lock().lock(); 157 CallType call(client.ClaimLocked(), channel_id, service_id, method_id); 158 159 call.set_on_next_locked(std::move(on_next)); 160 call.set_on_completed_locked(std::move(on_completed)); 161 call.set_on_error_locked(std::move(on_error)); 162 163 call.SendInitialClientRequest(request); 164 client.CleanUpCalls(); 165 return call; 166 } 167 168 void HandleCompleted(Status status) PW_UNLOCK_FUNCTION(rpc_lock()); 169 170 protected: 171 constexpr StreamResponseClientCall() = default; 172 StreamResponseClientCall(LockedEndpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,CallProperties properties)173 StreamResponseClientCall(LockedEndpoint& client, 174 uint32_t channel_id, 175 uint32_t service_id, 176 uint32_t method_id, 177 CallProperties properties) 178 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) 179 : ClientCall(client, channel_id, service_id, method_id, properties) {} 180 StreamResponseClientCall(StreamResponseClientCall && other)181 StreamResponseClientCall(StreamResponseClientCall&& other) { 182 *this = std::move(other); 183 } 184 185 StreamResponseClientCall& operator=(StreamResponseClientCall&& other) PW_LOCKS_EXCLUDED(rpc_lock ())186 PW_LOCKS_EXCLUDED(rpc_lock()) { 187 RpcLockGuard lock; 188 MoveStreamResponseClientCallFrom(other); 189 return *this; 190 } 191 MoveStreamResponseClientCallFrom(StreamResponseClientCall & other)192 void MoveStreamResponseClientCallFrom(StreamResponseClientCall& other) 193 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) { 194 MoveClientCallFrom(other); 195 on_completed_ = std::move(other.on_completed_); 196 } 197 set_on_completed(Function<void (Status)> && on_completed)198 void set_on_completed(Function<void(Status)>&& on_completed) 199 PW_LOCKS_EXCLUDED(rpc_lock()) { 200 RpcLockGuard lock; 201 set_on_completed_locked(std::move(on_completed)); 202 } 203 set_on_completed_locked(Function<void (Status)> && on_completed)204 void set_on_completed_locked(Function<void(Status)>&& on_completed) 205 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) { 206 on_completed_ = std::move(on_completed); 207 } 208 209 private: 210 Function<void(Status)> on_completed_ PW_GUARDED_BY(rpc_lock()); 211 }; 212 213 } // namespace pw::rpc::internal 214