• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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