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