Viam C++ SDK current
Loading...
Searching...
No Matches
client_helper.hpp
1#pragma once
2
4#include <viam/sdk/common/grpc_fwd.hpp>
5#include <viam/sdk/common/private/utils.hpp>
6#include <viam/sdk/common/proto_value.hpp>
7
8namespace viam {
9namespace sdk {
10
11namespace client_helper_details {
12
13[[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status*) noexcept;
14
15// Helper function to test equality of status with grpc::StatusCode::CANCELLED.
16bool isStatusCancelled(int status) noexcept;
17
18} // namespace client_helper_details
19
20// the authority on a grpc::ClientContext is sometimes set to an invalid uri on mac, causing
21// `rust-utils` to fail to process gRPC requests. This class provides a convenience wrapper around a
22// grpc ClientContext that allows us to make any necessary modifications to authority or else where
23// to avoid runtime issues.
24// For more details, see https://viam.atlassian.net/browse/RSDK-5194.
26 public:
29
30 void try_cancel();
31
32 operator GrpcClientContext*();
33 operator const GrpcClientContext*() const;
34
35 void set_debug_key(const std::string& debug_key);
36
37 private:
38 void set_client_ctx_authority_();
39 void add_viam_client_version_();
40 std::unique_ptr<GrpcClientContext> wrapped_context_;
41};
42
43// Method type for a gRPC call that returns a response message type.
44template <typename StubType, typename RequestType, typename ResponseType>
45using SyncMethodType = ::grpc::Status (StubType::*)(GrpcClientContext*,
46 const RequestType&,
47 ResponseType*);
48
49// Method type for a gRPC call that returns a stream of response message type.
50template <typename StubType, typename RequestType, typename ResponseType>
51using StreamingMethodType = std::unique_ptr<GrpcClientReaderInterface<ResponseType>> (StubType::*)(
52 GrpcClientContext*, const RequestType&);
53
54template <typename ClientType,
55 typename StubType,
56 typename RequestType,
57 typename ResponseType,
58 typename MethodType>
60 static void default_rsc_(RequestType&) {}
61 static void default_rhc_(const ResponseType&) {}
62 static void default_ehc_(const ::grpc::Status* status) {
63 throw GRPCException(status);
64 }
65
66 public:
67 explicit ClientHelper(ClientType* client, StubType* stub, MethodType pfn)
68 : client_(client), stub_(stub), pfn_(pfn) {}
69
70 ClientHelper& with(const ProtoStruct& extra) {
71 return with(extra, default_rsc_);
72 }
73
74 template <typename RequestSetupCallable>
75 ClientHelper& with(RequestSetupCallable&& rsc) {
76 std::forward<RequestSetupCallable>(rsc)(request_);
77 return *this;
78 }
79
80 template <typename RequestSetupCallable>
81 ClientHelper& with(const ProtoStruct& extra, RequestSetupCallable&& rsc) {
82 auto key = extra.find(impl::debug_map_key);
83 if (key != extra.end()) {
84 ProtoValue value = key->second;
85 debug_key_ = *value.get<std::string>();
86 }
87
88 proto_convert_details::to_proto_impl<ProtoStruct>{}(extra, request_.mutable_extra());
89 return with(std::forward<RequestSetupCallable>(rsc));
90 }
91
92 template <typename ResponseHandlerCallable = decltype(default_rhc_)>
93 auto invoke(ResponseHandlerCallable&& rhc = default_rhc_) {
94 return invoke(std::forward<ResponseHandlerCallable>(rhc), default_ehc_);
95 }
96
97 template <typename ResponseHandlerCallable, typename ErrorHandlerCallable>
98 auto invoke(ResponseHandlerCallable&& rhc, ErrorHandlerCallable&& ehc) {
99 *request_.mutable_name() = client_->name();
100 ClientContext ctx;
101
102 if (debug_key_ != "") {
103 ctx.set_debug_key(debug_key_);
104 }
105 const auto result = (stub_->*pfn_)(ctx, request_, &response_);
106 if (result.ok()) {
107 return std::forward<ResponseHandlerCallable>(rhc)(
108 const_cast<const ResponseType&>(response_));
109 }
110
111 std::forward<ErrorHandlerCallable>(ehc)(&result);
112 client_helper_details::errorHandlerReturnedUnexpectedly(&result);
113 }
114
115 // A version of invoke for gRPC calls returning `(stream ResponseType)`.
116 // ResponseHandlerCallable will be called for every response in the reader, and should return
117 // false to indicate it is no longer interested in the stream.
118 template <typename ResponseHandlerCallable,
119 typename ErrorHandlerCallable = decltype(default_ehc_)>
120 auto invoke_stream(ResponseHandlerCallable rhc, ErrorHandlerCallable&& ehc = default_ehc_) {
121 *request_.mutable_name() = client_->name();
122 ClientContext ctx;
123
124 auto reader = (stub_->*pfn_)(ctx, request_);
125
126 bool cancelled_by_handler = false;
127
128 while (reader->Read(&response_)) {
129 if (!rhc(response_)) {
130 cancelled_by_handler = true;
131 ctx.try_cancel();
132 break;
133 }
134 }
135
136 const auto result = reader->Finish();
137
138 if (result.ok() || (cancelled_by_handler &&
139 client_helper_details::isStatusCancelled(result.error_code()))) {
140 return;
141 }
142
143 std::forward<ErrorHandlerCallable>(ehc)(&result);
144 client_helper_details::errorHandlerReturnedUnexpectedly(&result);
145 }
146
147 private:
148 ClientType* client_;
149 StubType* stub_;
150 std::string debug_key_;
151 MethodType pfn_;
152 RequestType request_;
153 ResponseType response_;
154};
155
156template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
157auto make_client_helper(ClientType* client,
158 StubType& stub,
159 SyncMethodType<StubType, RequestType, ResponseType> method) {
160 return ClientHelper<ClientType,
161 StubType,
162 RequestType,
163 ResponseType,
164 SyncMethodType<StubType, RequestType, ResponseType>>(client, &stub, method);
165}
166
167template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
168auto make_client_helper(ClientType* client,
169 StubType& stub,
170 StreamingMethodType<StubType, RequestType, ResponseType> method) {
171 return ClientHelper<ClientType,
172 StubType,
173 RequestType,
174 ResponseType,
175 StreamingMethodType<StubType, RequestType, ResponseType>>(
176 client, &stub, method);
177}
178
179} // namespace sdk
180} // namespace viam
Definition client_helper.hpp:25
Definition client_helper.hpp:59
Defines an exception from a gRPC interaction.
Definition exception.hpp:57
Type-erased value for storing google::protobuf::Value types. A ProtoValue can be nullptr,...
Definition proto_value.hpp:55
T * get()
Return a T pointer if this is_a<T>(), else return nullptr.
Definition proto_value.hpp:395
Defines custom exceptions for the SDK.