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
13namespace viam {
14namespace sdk {
15
17 public:
18 ::grpc::Status fail(::grpc::StatusCode code, const char* message) const noexcept;
19
20 ::grpc::Status failNoContext() const noexcept;
21
22 ::grpc::Status failNoRequest() const noexcept;
23
24 ::grpc::Status failNoResource(const std::string& name) const noexcept;
25
26 ::grpc::Status failStdException(const std::exception& xcp) const noexcept;
27
28 ::grpc::Status failUnknownException() const noexcept;
29
30 protected:
31 explicit ServiceHelperBase(const char* method) noexcept : method_{method} {}
32
33 private:
34 const char* method_;
35};
36
37template <typename ServiceType, typename RequestType>
39 public:
40 ServiceHelper(const char* method,
42 const GrpcServerContext* context,
43 RequestType* request) noexcept
44 : ServiceHelperBase{method}, rs_{rs}, context_{context}, request_{request} {};
45
46 template <typename Callable>
47 BOOST_ATTRIBUTE_NODISCARD ::grpc::Status operator()(Callable&& callable) const noexcept try {
48 if (!context_) {
49 return failNoContext();
50 }
51 if (!request_) {
52 return failNoRequest();
53 }
54 const auto resource = rs_->resource_manager()->resource<ServiceType>(request_->name());
55 if (!resource) {
56 return failNoResource(request_->name());
57 }
58 const GrpcContextObserver::Enable enable{*context_};
59 return invoke_(std::forward<Callable>(callable), std::move(resource));
60 } catch (const std::exception& xcp) {
61 return failStdException(xcp);
62 } catch (...) {
63 return failUnknownException();
64 }
65
66 auto getExtra() const {
67 return request_->has_extra() ? from_proto(request_->extra()) : ProtoStruct{};
68 }
69
70 private:
71#if __cplusplus >= 201703L
72 template <typename Callable, typename... Args>
73 using is_void_result = std::is_void<std::invoke_result_t<Callable, Args...>>;
74#else
75 template <typename Callable, typename... Args>
76 using is_void_result = std::is_void<std::result_of_t<Callable(Args...)>>;
77#endif
78
79 // Implementation of `invoke_` for a Callable returning non-void,
80 // presumably an error return, which we return as a
81 // ::grpc::Status.
82 template <typename Callable,
83 typename ResourcePtrType,
84 std::enable_if_t<!is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value,
85 bool> = true>
86 ::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const {
87 return std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource));
88 }
89
90 // Implementation of `invoke_` for a Callable returning void,
91 // which is therefore either non-failing or communicates errors by
92 // throwing exceptions. We return an OK status automatically.
93 template <typename Callable,
94 typename ResourcePtrType,
95 std::enable_if_t<is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value,
96 bool> = true>
97 ::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const {
98 std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource));
99 return {};
100 }
101
102 ResourceServer* rs_;
103 const GrpcServerContext* context_;
104 RequestType* request_;
105};
106
107template <typename ServiceType, typename RequestType>
108BOOST_ATTRIBUTE_NODISCARD auto make_service_helper(const char* method,
109 ResourceServer* rs,
110 GrpcServerContext* context,
111 RequestType* request) {
112 return ServiceHelper<ServiceType, RequestType>{method, rs, context, request};
113}
114
115} // namespace sdk
116} // 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:16
Definition service_helper.hpp:38