Skip to content

Commit

Permalink
RSDK-794 Client side helper to replace stub_wrapper (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
acmorrow authored Nov 17, 2023
1 parent c92eb1e commit e1b1e48
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 305 deletions.
3 changes: 3 additions & 0 deletions src/viam/sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ target_sources(viamsdk
# consider making all necessary runtime values a single `context` that has to
# be initialized within main before anything else happens?
registry/registry.cpp
common/client_helper.cpp
common/linear_algebra.cpp
common/pose.cpp
common/proto_type.cpp
Expand Down Expand Up @@ -106,9 +107,11 @@ target_sources(viamsdk
BASE_DIRS
../..
FILES
../../viam/sdk/common/client_helper.hpp
../../viam/sdk/common/linear_algebra.hpp
../../viam/sdk/common/pose.hpp
../../viam/sdk/common/proto_type.hpp
../../viam/sdk/common/service_helper.hpp
../../viam/sdk/common/utils.hpp
../../viam/sdk/common/world_state.hpp
../../viam/sdk/components/base/base.hpp
Expand Down
20 changes: 20 additions & 0 deletions src/viam/sdk/common/client_helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <viam/sdk/common/client_helper.hpp>

#include <cstdlib>

#include <boost/log/trivial.hpp>

namespace viam {
namespace sdk {

namespace client_helper_details {

[[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status& status) noexcept {
BOOST_LOG_TRIVIAL(fatal) << "ClientHelper error handler callback returned instead of throwing: "
<< status.error_message() << '(' << status.error_details() << ')';
std::abort();
}

} // namespace client_helper_details
} // namespace sdk
} // namespace viam
84 changes: 84 additions & 0 deletions src/viam/sdk/common/client_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

#include <grpcpp/client_context.h>
#include <viam/sdk/common/proto_type.hpp>
#include <viam/sdk/common/utils.hpp>

namespace viam {
namespace sdk {

namespace client_helper_details {
[[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status&) noexcept;
} // namespace client_helper_details

template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
class ClientHelper {
static void default_rsc_(RequestType&) {}
static void default_rhc_(const ResponseType&) {}
static void default_ehc_(const ::grpc::Status& status) {
throw std::runtime_error(status.error_message());
}

public:
using PFn = ::grpc::Status (StubType::*)(::grpc::ClientContext*,
const RequestType&,
ResponseType*);
explicit ClientHelper(ClientType* client, StubType* stub, PFn pfn)
: client_(client), stub_(stub), pfn_(pfn) {}

ClientHelper& with(const AttributeMap& extra) {
return with(extra, default_rsc_);
}

template <typename RequestSetupCallable>
ClientHelper& with(RequestSetupCallable&& rsc) {
std::forward<RequestSetupCallable>(rsc)(request_);
return *this;
}

template <typename RequestSetupCallable>
ClientHelper& with(const AttributeMap& extra, RequestSetupCallable&& rsc) {
*request_.mutable_extra() = map_to_struct(extra);
return with(std::forward<RequestSetupCallable>(rsc));
}

template <typename ResponseHandlerCallable = decltype(default_rhc_)>
auto invoke(ResponseHandlerCallable&& rhc = default_rhc_) {
return invoke(std::forward<ResponseHandlerCallable>(rhc), default_ehc_);
}

template <typename ResponseHandlerCallable, typename ErrorHandlerCallable>
auto invoke(ResponseHandlerCallable&& rhc, ErrorHandlerCallable&& ehc) {
*request_.mutable_name() = client_->name();
::grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

const auto result = (stub_->*pfn_)(&ctx, request_, &response_);
if (result.ok()) {
return std::forward<ResponseHandlerCallable>(rhc)(
const_cast<const ResponseType&>(response_));
}

std::forward<ErrorHandlerCallable>(ehc)(result);
client_helper_details::errorHandlerReturnedUnexpectedly(result);
}

private:
ClientType* client_;
StubType* stub_;
PFn pfn_;
RequestType request_;
ResponseType response_;
};

template <typename ClientType, typename StubType, typename RequestType, typename ResponseType>
auto make_client_helper(ClientType* client,
StubType& stub,
::grpc::Status (StubType::*method)(::grpc::ClientContext*,
const RequestType&,
ResponseType*)) {
return ClientHelper<ClientType, StubType, RequestType, ResponseType>(client, &stub, method);
}

} // namespace sdk
} // namespace viam
179 changes: 40 additions & 139 deletions src/viam/sdk/components/motor/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <viam/api/common/v1/common.pb.h>
#include <viam/api/component/motor/v1/motor.grpc.pb.h>

#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/common/client_helper.hpp>
#include <viam/sdk/components/motor/motor.hpp>
#include <viam/sdk/config/resource.hpp>
#include <viam/sdk/robot/client.hpp>
Expand All @@ -23,107 +23,47 @@ MotorClient::MotorClient(std::string name, std::shared_ptr<grpc::Channel> channe
channel_(std::move(channel)){};

void MotorClient::set_power(double power_pct, const AttributeMap& extra) {
viam::component::motor::v1::SetPowerRequest request;
viam::component::motor::v1::SetPowerResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);
request.set_power_pct(power_pct);

const grpc::Status status = stub_->SetPower(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return make_client_helper(this, *stub_, &StubType::SetPower)
.with(extra, [&](auto& request) { request.set_power_pct(power_pct); })
.invoke();
}

void MotorClient::go_for(double rpm, double revolutions, const AttributeMap& extra) {
viam::component::motor::v1::GoForRequest request;
viam::component::motor::v1::GoForResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);
request.set_rpm(rpm);
request.set_revolutions(revolutions);

const grpc::Status status = stub_->GoFor(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return make_client_helper(this, *stub_, &StubType::GoFor)
.with(extra,
[&](auto& request) {
request.set_rpm(rpm);
request.set_revolutions(revolutions);
})
.invoke();
}

void MotorClient::go_to(double rpm, double position_revolutions, const AttributeMap& extra) {
viam::component::motor::v1::GoToRequest request;
viam::component::motor::v1::GoToResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);
request.set_rpm(rpm);
request.set_position_revolutions(position_revolutions);

const grpc::Status status = stub_->GoTo(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return make_client_helper(this, *stub_, &StubType::GoTo)
.with(extra,
[&](auto& request) {
request.set_rpm(rpm);
request.set_position_revolutions(position_revolutions);
})
.invoke();
}

void MotorClient::reset_zero_position(double offset, const AttributeMap& extra) {
viam::component::motor::v1::ResetZeroPositionRequest request;
viam::component::motor::v1::ResetZeroPositionResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);
request.set_offset(offset);

const grpc::Status status = stub_->ResetZeroPosition(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return make_client_helper(this, *stub_, &StubType::ResetZeroPosition)
.with(extra, [&](auto& request) { request.set_offset(offset); })
.invoke();
}

Motor::position MotorClient::get_position(const AttributeMap& extra) {
viam::component::motor::v1::GetPositionRequest request;
viam::component::motor::v1::GetPositionResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);

const grpc::Status status = stub_->GetPosition(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return from_proto(response);
return make_client_helper(this, *stub_, &StubType::GetPosition)
.with(extra)
.invoke([](auto& response) { return from_proto(response); });
}

Motor::properties MotorClient::get_properties(const AttributeMap& extra) {
viam::component::motor::v1::GetPropertiesRequest request;
viam::component::motor::v1::GetPropertiesResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);

const grpc::Status status = stub_->GetProperties(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return from_proto(response);
return make_client_helper(this, *stub_, &StubType::GetProperties)
.with(extra)
.invoke([](auto& response) { return from_proto(response); });
}

grpc::StatusCode MotorClient::stop(const AttributeMap& extra) {
Expand All @@ -141,66 +81,27 @@ grpc::StatusCode MotorClient::stop(const AttributeMap& extra) {
}

Motor::power_status MotorClient::get_power_status(const AttributeMap& extra) {
viam::component::motor::v1::IsPoweredRequest request;
viam::component::motor::v1::IsPoweredResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();
*request.mutable_extra() = map_to_struct(extra);

const grpc::Status status = stub_->IsPowered(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return from_proto(response);
return make_client_helper(this, *stub_, &StubType::IsPowered)
.with(extra)
.invoke([](auto& response) { return from_proto(response); });
}

std::vector<GeometryConfig> MotorClient::get_geometries(const AttributeMap& extra) {
viam::common::v1::GetGeometriesRequest req;
viam::common::v1::GetGeometriesResponse resp;
grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*req.mutable_name() = this->name();
*req.mutable_extra() = map_to_struct(extra);

stub_->GetGeometries(&ctx, req, &resp);
return GeometryConfig::from_proto(resp);
};
return make_client_helper(this, *stub_, &StubType::GetGeometries)
.with(extra)
.invoke([](auto& response) { return GeometryConfig::from_proto(response); });
}

bool MotorClient::is_moving() {
viam::component::motor::v1::IsMovingRequest request;
viam::component::motor::v1::IsMovingResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_name() = this->name();

const grpc::Status status = stub_->IsMoving(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return response.is_moving();
return make_client_helper(this, *stub_, &StubType::IsMoving).invoke([](auto& response) {
return response.is_moving();
});
}

AttributeMap MotorClient::do_command(const AttributeMap& command) {
viam::common::v1::DoCommandRequest request;
viam::common::v1::DoCommandResponse response;

grpc::ClientContext ctx;
set_client_ctx_authority(ctx);

*request.mutable_command() = map_to_struct(command);
*request.mutable_name() = this->name();

const grpc::Status status = stub_->DoCommand(&ctx, request, &response);
if (!status.ok()) {
throw std::runtime_error(status.error_message());
}
return struct_to_map(response.result());
return make_client_helper(this, *stub_, &StubType::DoCommand)
.with([&](auto& request) { *request.mutable_command() = map_to_struct(command); })
.invoke([](auto& response) { return struct_to_map(response.result()); });
}

} // namespace sdk
Expand Down
3 changes: 2 additions & 1 deletion src/viam/sdk/components/motor/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class MotorClient : public Motor {
using Motor::stop;

private:
std::unique_ptr<viam::component::motor::v1::MotorService::StubInterface> stub_;
using StubType = viam::component::motor::v1::MotorService::StubInterface;
std::unique_ptr<StubType> stub_;
std::shared_ptr<grpc::Channel> channel_;
};

Expand Down
Loading

0 comments on commit e1b1e48

Please sign in to comment.