Viam C++ SDK current
Loading...
Searching...
No Matches
client_helper.hpp
1#pragma once
2
3#include <grpcpp/client_context.h>
4#include <grpcpp/support/sync_stream.h>
5
7#include <viam/sdk/common/private/utils.hpp>
8#include <viam/sdk/common/proto_value.hpp>
9#include <viam/sdk/common/utils.hpp>
10
11namespace viam {
12namespace sdk {
13
14namespace client_helper_details {
15[[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status&) noexcept;
16} // namespace client_helper_details
17
18// Method type for a gRPC call that returns a response message type.
19template <typename StubType, typename RequestType, typename ResponseType>
20using SyncMethodType = ::grpc::Status (StubType::*)(::grpc::ClientContext*,
21 const RequestType&,
22 ResponseType*);
23
24// Method type for a gRPC call that returns a stream of response message type.
25template <typename StubType, typename RequestType, typename ResponseType>
26using StreamingMethodType = std::unique_ptr<::grpc::ClientReaderInterface<ResponseType>> (
27 StubType::*)(::grpc::ClientContext*, const RequestType&);
28
29template <typename ClientType,
30 typename StubType,
31 typename RequestType,
32 typename ResponseType,
33 typename MethodType>
35 static void default_rsc_(RequestType&) {}
36 static void default_rhc_(const ResponseType&) {}
37 static void default_ehc_(const ::grpc::Status& status) {
38 throw GRPCException(status);
39 }
40
41 public:
42 explicit ClientHelper(ClientType* client, StubType* stub, MethodType pfn)
43 : client_(client), stub_(stub), pfn_(pfn) {}
44
45 ClientHelper& with(const ProtoStruct& extra) {
46 return with(extra, default_rsc_);
47 }
48
49 template <typename RequestSetupCallable>
50 ClientHelper& with(RequestSetupCallable&& rsc) {
51 std::forward<RequestSetupCallable>(rsc)(request_);
52 return *this;
53 }
54
55 template <typename RequestSetupCallable>
56 ClientHelper& with(const ProtoStruct& extra, RequestSetupCallable&& rsc) {
57 auto key = extra.find(impl::debug_map_key);
58 if (key != extra.end()) {
59 ProtoValue value = key->second;
60 debug_key_ = *value.get<std::string>();
61 }
62 *request_.mutable_extra() = map_to_struct(extra);
63 return with(std::forward<RequestSetupCallable>(rsc));
64 }
65
66 template <typename ResponseHandlerCallable = decltype(default_rhc_)>
67 auto invoke(ResponseHandlerCallable&& rhc = default_rhc_) {
68 return invoke(std::forward<ResponseHandlerCallable>(rhc), default_ehc_);
69 }
70
71 template <typename ResponseHandlerCallable, typename ErrorHandlerCallable>
72 auto invoke(ResponseHandlerCallable&& rhc, ErrorHandlerCallable&& ehc) {
73 *request_.mutable_name() = client_->name();
74 ClientContext ctx;
75
76 if (debug_key_ != "") {
77 ctx.set_debug_key(debug_key_);
78 }
79 const auto result = (stub_->*pfn_)(ctx, request_, &response_);
80 if (result.ok()) {
81 return std::forward<ResponseHandlerCallable>(rhc)(
82 const_cast<const ResponseType&>(response_));
83 }
84
85 std::forward<ErrorHandlerCallable>(ehc)(result);
86 client_helper_details::errorHandlerReturnedUnexpectedly(result);
87 }
88
89 // A version of invoke for gRPC calls returning `(stream ResponseType)`.
90 // ResponseHandlerCallable will be called for every response in the reader, and should return
91 // false to indicate it is no longer interested in the stream.
92 template <typename ResponseHandlerCallable,
93 typename ErrorHandlerCallable = decltype(default_ehc_)>
94 auto invoke_stream(ResponseHandlerCallable rhc, ErrorHandlerCallable&& ehc = default_ehc_) {
95 *request_.mutable_name() = client_->name();
96 ClientContext ctx;
97
98 auto reader = (stub_->*pfn_)(ctx, request_);
99
100 bool cancelled_by_handler = false;
101
102 while (reader->Read(&response_)) {
103 if (!rhc(response_)) {
104 cancelled_by_handler = true;
105 static_cast<::grpc::ClientContext*>(ctx)->TryCancel();
106 break;
107 }
108 }
109
110 const auto result = reader->Finish();
111
112 if (result.ok() ||
113 (cancelled_by_handler && result.error_code() == ::grpc::StatusCode::CANCELLED)) {
114 return;
115 }
116
117 std::forward<ErrorHandlerCallable>(ehc)(result);
118 client_helper_details::errorHandlerReturnedUnexpectedly(result);
119 }
120
121 private:
122 ClientType* client_;
123 StubType* stub_;
124 std::string debug_key_;
125 MethodType pfn_;
126 RequestType request_;
127 ResponseType response_;
128};
129
130template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
131auto make_client_helper(ClientType* client,
132 StubType& stub,
133 SyncMethodType<StubType, RequestType, ResponseType> method) {
134 return ClientHelper<ClientType,
135 StubType,
136 RequestType,
137 ResponseType,
138 SyncMethodType<StubType, RequestType, ResponseType>>(client, &stub, method);
139}
140
141template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
142auto make_client_helper(ClientType* client,
143 StubType& stub,
144 StreamingMethodType<StubType, RequestType, ResponseType> method) {
145 return ClientHelper<ClientType,
146 StubType,
147 RequestType,
148 ResponseType,
149 StreamingMethodType<StubType, RequestType, ResponseType>>(
150 client, &stub, method);
151}
152
153} // namespace sdk
154} // namespace viam
Definition utils.hpp:51
Definition client_helper.hpp:34
Defines an exception from a gRPC interaction.
Definition exception.hpp:50
Type-erased value for storing google::protobuf::Value types. A ProtoValue can be nullptr,...
Definition proto_value.hpp:53
T * get()
Return a T pointer if this is_a<T>(), else return nullptr.
Definition proto_value.hpp:416
Defines custom exceptions for the SDK.