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