-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RSDK-794 ServiceHelper to simplify service method implementations (#178)
- Loading branch information
Showing
7 changed files
with
303 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#include <viam/sdk/common/service_helper.hpp> | ||
|
||
#include <sstream> | ||
|
||
namespace viam { | ||
namespace sdk { | ||
|
||
::grpc::Status ServiceHelperBase::fail(::grpc::StatusCode code, const char* message) const noexcept | ||
try { | ||
std::ostringstream stream; | ||
stream << '[' << method_ << "]: " << message; | ||
return {code, stream.str()}; | ||
} catch (...) { | ||
return {code, message}; | ||
} | ||
|
||
::grpc::Status ServiceHelperBase::failNoRequest() const noexcept { | ||
return fail(::grpc::INVALID_ARGUMENT, "Called without a `request` object"); | ||
} | ||
|
||
::grpc::Status ServiceHelperBase::failNoResource(const std::string& name) const noexcept try { | ||
std::ostringstream stream; | ||
stream << "Failed to find resource `" << name << "`"; | ||
return fail(::grpc::NOT_FOUND, stream.str().c_str()); | ||
} catch (...) { | ||
return fail(::grpc::NOT_FOUND, "Failed to find resource"); | ||
} | ||
|
||
::grpc::Status ServiceHelperBase::failStdException(const std::exception& xcp) const noexcept try { | ||
std::ostringstream stream; | ||
stream << "Failed with a std::exception: " << xcp.what(); | ||
return fail(::grpc::INTERNAL, stream.str().c_str()); | ||
} catch (...) { | ||
return fail(::grpc::INTERNAL, "Failed with a std::exception: <unknown>"); | ||
} | ||
|
||
::grpc::Status ServiceHelperBase::failUnknownException() const noexcept { | ||
return fail(::grpc::INTERNAL, "Failed with an unknown exception"); | ||
} | ||
|
||
} // namespace sdk | ||
} // namespace viam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#pragma once | ||
|
||
#include <type_traits> | ||
|
||
#include <viam/sdk/resource/resource_server_base.hpp> | ||
|
||
namespace viam { | ||
namespace sdk { | ||
|
||
class ServiceHelperBase { | ||
public: | ||
::grpc::Status fail(::grpc::StatusCode code, const char* message) const noexcept; | ||
|
||
::grpc::Status failNoRequest() const noexcept; | ||
|
||
::grpc::Status failNoResource(const std::string& name) const noexcept; | ||
|
||
::grpc::Status failStdException(const std::exception& xcp) const noexcept; | ||
|
||
::grpc::Status failUnknownException() const noexcept; | ||
|
||
protected: | ||
explicit ServiceHelperBase(const char* method) noexcept : method_{method} {} | ||
|
||
private: | ||
const char* method_; | ||
}; | ||
|
||
template <typename ServiceType, typename RequestType> | ||
class ServiceHelper : public ServiceHelperBase { | ||
public: | ||
ServiceHelper(const char* method, ResourceServer* rs, RequestType* request) noexcept | ||
: ServiceHelperBase{method}, rs_{rs}, request_{request} {}; | ||
|
||
template <typename Callable> | ||
::grpc::Status operator()(Callable&& callable) const noexcept try { | ||
if (!request_) { | ||
return failNoRequest(); | ||
} | ||
const auto resource = rs_->resource_manager()->resource<ServiceType>(request_->name()); | ||
if (!resource) { | ||
return failNoResource(request_->name()); | ||
} | ||
return invoke_(std::forward<Callable>(callable), std::move(resource)); | ||
} catch (const std::exception& xcp) { | ||
return failStdException(xcp); | ||
} catch (...) { | ||
return failUnknownException(); | ||
} | ||
|
||
auto getExtra() const { | ||
return request_->has_extra() ? struct_to_map(request_->extra()) : AttributeMap{}; | ||
} | ||
|
||
private: | ||
template <typename Callable, typename... Args> | ||
using is_void_result = std::is_void<std::result_of_t<Callable(Args...)>>; | ||
|
||
// Implementation of `invoke_` for a Callable returning non-void, | ||
// presumably an error return, which we return as a | ||
// ::grpc::Status. | ||
template <typename Callable, | ||
typename ResourcePtrType, | ||
std::enable_if_t<!is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value, | ||
bool> = true> | ||
::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const { | ||
return std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource)); | ||
} | ||
|
||
// Implementation of `invoke_` for a Callable returning void, | ||
// which is therefore either non-failing or communicates errors by | ||
// throwing exceptions. We return an OK status automatically. | ||
template <typename Callable, | ||
typename ResourcePtrType, | ||
std::enable_if_t<is_void_result<Callable, ServiceHelper&, ResourcePtrType&&>::value, | ||
bool> = true> | ||
::grpc::Status invoke_(Callable&& callable, ResourcePtrType&& resource) const { | ||
std::forward<Callable>(callable)(*this, std::forward<ResourcePtrType>(resource)); | ||
return {}; | ||
} | ||
|
||
ResourceServer* rs_; | ||
RequestType* request_; | ||
}; | ||
|
||
template <typename ServiceType, typename RequestType> | ||
auto make_service_helper(const char* method, ResourceServer* rs, RequestType* request) { | ||
return ServiceHelper<ServiceType, RequestType>{method, rs, request}; | ||
} | ||
|
||
} // namespace sdk | ||
} // namespace viam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.