Skip to content

Commit 758bacf

Browse files
authored
Merge branch 'main' into RSDK-10366-rust-utils-for-windows
2 parents c7490e2 + faa73b6 commit 758bacf

File tree

8 files changed

+99
-69
lines changed

8 files changed

+99
-69
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ else()
4444
cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
4545
endif()
4646

47-
set(CMAKE_PROJECT_VERSION 0.9.0)
47+
set(CMAKE_PROJECT_VERSION 0.10.0)
4848

4949
# Identify the project.
5050
project(viam-cpp-sdk

src/viam/api/api_proto_tag.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.1.431
1+
v0.1.432

src/viam/api/buf.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ deps:
88
- remote: buf.build
99
owner: viamrobotics
1010
repository: api
11-
commit: 7602eb52384c4ee9bba76965852d8381
11+
commit: 1f5b8a47f15e49af89174672bb898b77
1212
- remote: buf.build
1313
owner: viamrobotics
1414
repository: goutils

src/viam/sdk/robot/client.cpp

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,15 @@ RobotClient::~RobotClient() {
129129

130130
void RobotClient::close() {
131131
should_refresh_.store(false);
132-
for (const std::shared_ptr<std::thread>& t : threads_) {
133-
t->~thread();
132+
133+
for (auto& thread : threads_) {
134+
thread.join();
134135
}
136+
threads_.clear();
137+
135138
stop_all();
136-
viam_channel_->close();
139+
140+
viam_channel_.close();
137141
}
138142

139143
bool is_error_response(const grpc::Status& response) {
@@ -211,7 +215,7 @@ void RobotClient::refresh() {
211215
if (rs) {
212216
try {
213217
const std::shared_ptr<Resource> rpc_client =
214-
rs->create_rpc_client(name.name(), channel_);
218+
rs->create_rpc_client(name.name(), viam_channel_.channel());
215219
const Name name_({name.namespace_(), name.type(), name.subtype()}, "", name.name());
216220
new_resources.emplace(name_, rpc_client);
217221
} catch (const std::exception& exc) {
@@ -250,11 +254,10 @@ void RobotClient::refresh_every() {
250254
}
251255
};
252256

253-
RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel)
254-
: channel_(channel->channel()),
255-
viam_channel_(std::move(channel)),
257+
RobotClient::RobotClient(ViamChannel channel)
258+
: viam_channel_(std::move(channel)),
256259
should_close_channel_(false),
257-
impl_(std::make_unique<impl>(RobotService::NewStub(channel_))) {}
260+
impl_(std::make_unique<impl>(RobotService::NewStub(viam_channel_.channel()))) {}
258261

259262
std::vector<Name> RobotClient::resource_names() const {
260263
const std::lock_guard<std::mutex> lock(lock_);
@@ -286,20 +289,14 @@ void RobotClient::log(const std::string& name,
286289
}
287290
}
288291

289-
std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel,
292+
std::shared_ptr<RobotClient> RobotClient::with_channel(ViamChannel channel,
290293
const Options& options) {
291-
std::shared_ptr<RobotClient> robot = std::make_shared<RobotClient>(std::move(channel));
294+
auto robot = std::make_shared<RobotClient>(std::move(channel));
292295
robot->refresh_interval_ = options.refresh_interval();
293296
robot->should_refresh_ = (robot->refresh_interval_ > 0);
294297
if (robot->should_refresh_) {
295-
const std::shared_ptr<std::thread> t =
296-
std::make_shared<std::thread>(&RobotClient::refresh_every, robot);
297-
// TODO(RSDK-1743): this was leaking, confirm that adding thread catching in
298-
// close/destructor lets us shutdown gracefully. See also address sanitizer,
299-
// UB sanitizer
300-
t->detach();
301-
robot->threads_.push_back(t);
302-
};
298+
robot->threads_.emplace_back(&RobotClient::refresh_every, robot);
299+
}
303300

304301
robot->refresh();
305302
return robot;
@@ -308,8 +305,8 @@ std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChann
308305
std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address,
309306
const Options& options) {
310307
const char* uri = address.c_str();
311-
auto channel = ViamChannel::dial_initial(uri, options.dial_options());
312-
std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options);
308+
auto robot =
309+
RobotClient::with_channel(ViamChannel::dial_initial(uri, options.dial_options()), options);
313310
robot->should_close_channel_ = true;
314311

315312
return robot;
@@ -318,11 +315,9 @@ std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address,
318315
std::shared_ptr<RobotClient> RobotClient::at_local_socket(const std::string& address,
319316
const Options& options) {
320317
const std::string addr = "unix:" + address;
321-
const char* uri = addr.c_str();
322-
const std::shared_ptr<grpc::Channel> channel =
323-
sdk::impl::create_viam_channel(uri, grpc::InsecureChannelCredentials());
324-
auto viam_channel = std::make_shared<ViamChannel>(channel, address.c_str(), nullptr);
325-
std::shared_ptr<RobotClient> robot = RobotClient::with_channel(viam_channel, options);
318+
auto robot = RobotClient::with_channel(
319+
ViamChannel(sdk::impl::create_viam_channel(addr, grpc::InsecureChannelCredentials())),
320+
options);
326321
robot->should_close_channel_ = true;
327322

328323
return robot;

src/viam/sdk/robot/client.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ class RobotClient {
6464
friend bool operator==(const operation& lhs, const operation& rhs);
6565
};
6666

67+
explicit RobotClient(ViamChannel channel);
68+
6769
~RobotClient();
70+
6871
void refresh();
6972
void close();
7073

@@ -87,10 +90,7 @@ class RobotClient {
8790
/// @param options Options for connecting and refreshing.
8891
/// Connects directly to a pre-existing channel. A robot created this way must be
8992
/// `close()`d manually.
90-
static std::shared_ptr<RobotClient> with_channel(std::shared_ptr<ViamChannel> channel,
91-
const Options& options);
92-
93-
RobotClient(std::shared_ptr<ViamChannel> channel);
93+
static std::shared_ptr<RobotClient> with_channel(ViamChannel channel, const Options& options);
9494

9595
std::vector<Name> resource_names() const;
9696

@@ -165,13 +165,12 @@ class RobotClient {
165165

166166
void refresh_every();
167167

168-
std::vector<std::shared_ptr<std::thread>> threads_;
168+
std::vector<std::thread> threads_;
169169

170170
std::atomic<bool> should_refresh_;
171171
unsigned int refresh_interval_;
172172

173-
std::shared_ptr<GrpcChannel> channel_;
174-
std::shared_ptr<ViamChannel> viam_channel_;
173+
ViamChannel viam_channel_;
175174
bool should_close_channel_;
176175

177176
struct impl;

src/viam/sdk/rpc/dial.cpp

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,46 @@
1919
namespace viam {
2020
namespace sdk {
2121

22-
const std::shared_ptr<grpc::Channel>& ViamChannel::channel() const {
23-
return channel_;
24-
}
22+
struct ViamChannel::impl {
23+
impl(const char* path, void* runtime) : path(path), rust_runtime(runtime) {}
2524

26-
void ViamChannel::close() {
27-
if (closed_) {
28-
return;
25+
impl(const impl&) = delete;
26+
27+
impl(impl&& other) noexcept
28+
: path(std::exchange(other.path, nullptr)),
29+
rust_runtime(std::exchange(other.rust_runtime, nullptr)) {}
30+
31+
impl& operator=(const impl&) = delete;
32+
33+
impl& operator=(impl&& other) noexcept {
34+
path = std::exchange(other.path, nullptr);
35+
rust_runtime = std::exchange(other.rust_runtime, nullptr);
36+
37+
return *this;
2938
}
30-
closed_ = true;
31-
free_string(path_);
32-
free_rust_runtime(rust_runtime_);
39+
40+
~impl() {
41+
free_string(path);
42+
free_rust_runtime(rust_runtime);
43+
}
44+
45+
const char* path;
46+
void* rust_runtime;
3347
};
3448

49+
ViamChannel::ViamChannel(std::shared_ptr<grpc::Channel> channel, const char* path, void* runtime)
50+
: channel_(std::move(channel)), pimpl_(std::make_unique<ViamChannel::impl>(path, runtime)) {}
51+
52+
ViamChannel::ViamChannel(std::shared_ptr<grpc::Channel> channel) : channel_(std::move(channel)) {}
53+
54+
ViamChannel::ViamChannel(ViamChannel&&) noexcept = default;
55+
56+
ViamChannel& ViamChannel::operator=(ViamChannel&&) noexcept = default;
57+
58+
ViamChannel::~ViamChannel() {
59+
close();
60+
}
61+
3562
const std::string& Credentials::type() const {
3663
return type_;
3764
}
@@ -40,9 +67,6 @@ const std::string& Credentials::payload() const {
4067
return payload_;
4168
}
4269

43-
ViamChannel::ViamChannel(std::shared_ptr<grpc::Channel> channel, const char* path, void* runtime)
44-
: channel_(std::move(channel)), path_(path), closed_(false), rust_runtime_(runtime) {}
45-
4670
DialOptions::DialOptions() = default;
4771

4872
DialOptions& DialOptions::set_credentials(boost::optional<Credentials> creds) {
@@ -106,8 +130,8 @@ bool DialOptions::allows_insecure_downgrade() const {
106130
return allow_insecure_downgrade_;
107131
}
108132

109-
std::shared_ptr<ViamChannel> ViamChannel::dial_initial(
110-
const char* uri, const boost::optional<DialOptions>& options) {
133+
ViamChannel ViamChannel::dial_initial(const char* uri,
134+
const boost::optional<DialOptions>& options) {
111135
DialOptions opts = options.get_value_or(DialOptions());
112136
auto timeout = opts.timeout();
113137
auto attempts_remaining = opts.initial_connection_attempts();
@@ -130,11 +154,10 @@ std::shared_ptr<ViamChannel> ViamChannel::dial_initial(
130154
}
131155
// the while loop will run until we either return or throw an error, so we can never reach this
132156
// point
133-
BOOST_UNREACHABLE_RETURN(nullptr)
157+
BOOST_UNREACHABLE_RETURN(ViamChannel(nullptr))
134158
}
135159

136-
std::shared_ptr<ViamChannel> ViamChannel::dial(const char* uri,
137-
const boost::optional<DialOptions>& options) {
160+
ViamChannel ViamChannel::dial(const char* uri, const boost::optional<DialOptions>& options) {
138161
void* ptr = init_rust_runtime();
139162
const DialOptions opts = options.get_value_or(DialOptions());
140163
const std::chrono::duration<float> float_timeout = opts.timeout();
@@ -164,12 +187,18 @@ std::shared_ptr<ViamChannel> ViamChannel::dial(const char* uri,
164187
}
165188
address += proxy_path;
166189

167-
const std::shared_ptr<grpc::Channel> channel =
168-
impl::create_viam_channel(address, grpc::InsecureChannelCredentials());
169-
const std::unique_ptr<viam::robot::v1::RobotService::Stub> st =
170-
viam::robot::v1::RobotService::NewStub(channel);
171-
return std::make_shared<ViamChannel>(channel, proxy_path, ptr);
172-
};
190+
return ViamChannel(sdk::impl::create_viam_channel(address, grpc::InsecureChannelCredentials()),
191+
proxy_path,
192+
ptr);
193+
}
194+
195+
const std::shared_ptr<grpc::Channel>& ViamChannel::channel() const {
196+
return channel_;
197+
}
198+
199+
void ViamChannel::close() {
200+
pimpl_.reset();
201+
}
173202

174203
unsigned int Options::refresh_interval() const {
175204
return refresh_interval_;

src/viam/sdk/rpc/dial.hpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,24 @@ namespace sdk {
1313

1414
class DialOptions;
1515
class ViamChannel {
16-
public:
17-
void close();
1816
ViamChannel(std::shared_ptr<GrpcChannel> channel, const char* path, void* runtime);
1917

18+
public:
19+
explicit ViamChannel(std::shared_ptr<GrpcChannel> channel);
20+
21+
ViamChannel(ViamChannel&&) noexcept;
22+
23+
ViamChannel& operator=(ViamChannel&&) noexcept;
24+
25+
~ViamChannel();
26+
2027
/// @brief Connects to a robot at the given URI address, using the provided dial options (or
2128
/// default options is none are provided). Ignores initial connection options specifying
2229
/// how many times to attempt to connect and with what timeout.
2330
/// In general, use of this method is discouraged. `RobotClient::at_address(...)` is the
2431
/// preferred method to connect to a robot, and creates the channel itself.
2532
/// @throws Exception if it is unable to establish a connection to the provided URI
26-
static std::shared_ptr<ViamChannel> dial(const char* uri,
27-
const boost::optional<DialOptions>& options);
33+
static ViamChannel dial(const char* uri, const boost::optional<DialOptions>& options);
2834

2935
// @brief Dials to a robot at the given URI address, using the provided dial options (or default
3036
// options is none are provided). Additionally specifies that this dial is an initial connection
@@ -33,16 +39,18 @@ class ViamChannel {
3339
/// preferred method to connect to a robot, and creates the channel itself.
3440
/// @throws Exception if it is unable to establish a connection to the provided URI within
3541
/// the given number of initial connection attempts
36-
static std::shared_ptr<ViamChannel> dial_initial(const char* uri,
37-
const boost::optional<DialOptions>& options);
42+
static ViamChannel dial_initial(const char* uri, const boost::optional<DialOptions>& options);
3843

3944
const std::shared_ptr<GrpcChannel>& channel() const;
4045

46+
void close();
47+
4148
private:
49+
struct impl;
50+
4251
std::shared_ptr<GrpcChannel> channel_;
43-
const char* path_;
44-
bool closed_;
45-
void* rust_runtime_;
52+
53+
std::unique_ptr<impl> pimpl_;
4654
};
4755

4856
class Credentials {

src/viam/sdk/tests/test_robot.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) {
5050
// in-process gRPC channel.
5151
auto test_server = TestServer(server);
5252
auto grpc_channel = test_server.grpc_in_process_channel();
53-
auto viam_channel = std::make_shared<ViamChannel>(grpc_channel, "", nullptr);
54-
auto client = RobotClient::with_channel(viam_channel, Options(0, boost::none));
53+
auto client = RobotClient::with_channel(ViamChannel(grpc_channel), Options(0, boost::none));
5554

5655
// Run the passed-in test case on the created stack and give access to the
5756
// created RobotClient and MockRobotService.

0 commit comments

Comments
 (0)