Viam C++ SDK current
Loading...
Searching...
No Matches
service_helper.hpp
1#pragma once
2
3#include <type_traits>
4
5#include <boost/config.hpp>
6#include <grpcpp/support/status.h>
7
8#include <viam/sdk/common/grpc_fwd.hpp>
9
10#include <viam/sdk/resource/resource_server_base.hpp>
11#include <viam/sdk/rpc/private/grpc_context_observer.hpp>
12#include <viam/sdk/tracing/private/span_guard.hpp>
13
14namespace viam {
15namespace sdk {
16
18 public:
19 ::grpc::Status fail(::grpc::StatusCode code, const char* message) const noexcept;
20
21 ::grpc::Status failNoContext() const noexcept;
22
23 ::grpc::Status failNoRequest() const noexcept;
24
25 ::grpc::Status failNoResource(const std::string& name) const noexcept;
26
27 ::grpc::Status failStdException(const std::exception& xcp) const noexcept;
28
29 ::grpc::Status failUnknownException() const noexcept;
30
31 protected:
32 explicit ServiceHelperBase(const char* method) noexcept : method_{method} {}
33
34 const char* method_name() const noexcept {
35 return method_;
36 }
37
38 private:
39 const char* method_;
40};
41
42template <typename ServiceType, typename RequestType>
44 public:
45 ServiceHelper(const char* method,
47 const GrpcServerContext* context,
48 RequestType* request) noexcept
49 : ServiceHelperBase{method}, rs_{rs}, context_{context}, request_{request} {};
50
51 template <typename Callable>
52 BOOST_ATTRIBUTE_NODISCARD ::grpc::Status operator()(Callable&& callable) const noexcept try {
53 if (!context_) {
54 return failNoContext();
55 }
56 if (!request_) {
57 return failNoRequest();
58 }
59 const auto resource = rs_->resource_manager()->resource<ServiceType>(request_->name());
60 if (!resource) {
61 return failNoResource(request_->name());
62 }
63 const GrpcContextObserver::Enable enable{*context_};
64 impl::ServerSpanGuard span_guard{context_, method_name()};
65
66 // This is kind of hideous but automates the process of recording exception
67 // info in the active span in case of failure.
68 try {
69 return span_guard.commit(
70 invoke_(std::forward<Callable>(callable), std::move(resource)));
71 } catch (const std::exception& xcp) {
72 span_guard.record_exception(xcp);
73 throw;
74 } catch (...) {
75 span_guard.record_unknown_exception();
76 throw;
77 }
78 } catch (const std::exception& xcp) {
79 return failStdException(xcp);
80 } catch (...) {
81 return failUnknownException();
82 }
83
84 auto getExtra() const {
85 return request_->has_extra() ? from_proto(request_->extra()) : ProtoStruct{};
86 }
87
88 private:
89#if __cplusplus >= 201703L
90 template <typename Callable, typename... Args>
91 using is_void_result = std::is_void<std::invoke_result_t<Callable, Args...>>;
92#else
93 template <typename Callable, typename... Args>
94 using is_void_result = std::is_void<std::result_of_t<Callable(Args...)>>;
95#endif
96
97 // Implementation of `invoke_` for a Callable returning non-void,
98 // presumably an error return, which we return as a
99 // ::grpc::Status.
100 template <typename Callable,
101 typename ResourcePtrType,
102 std::enable_if_t<!is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value,
103 bool> = true>
104 ::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const {
105 return std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource));
106 }
107
108 // Implementation of `invoke_` for a Callable returning void,
109 // which is therefore either non-failing or communicates errors by
110 // throwing exceptions. We return an OK status automatically.
111 template <typename Callable,
112 typename ResourcePtrType,
113 std::enable_if_t<is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value,
114 bool> = true>
115 ::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const {
116 std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource));
117 return {};
118 }
119
120 ResourceServer* rs_;
121 const GrpcServerContext* context_;
122 RequestType* request_;
123};
124
125template <typename ServiceType, typename RequestType>
126BOOST_ATTRIBUTE_NODISCARD auto make_service_helper(const char* method,
127 ResourceServer* rs,
128 GrpcServerContext* context,
129 RequestType* request) {
130 return ServiceHelper<ServiceType, RequestType>{method, rs, context, request};
131}
132
133} // namespace sdk
134} // namespace viam
RAII helper for activating the gRPC context observer for the current thread.
Definition grpc_context_observer.hpp:10
Definition resource_server_base.hpp:8
Definition service_helper.hpp:17
Definition service_helper.hpp:43
RAII guard that creates a server-side OpenTelemetry span for the duration of a gRPC handler invocatio...
Definition span_guard.hpp:27