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