diff --git a/src/viam/examples/modules/complex/proto/buf.lock b/src/viam/examples/modules/complex/proto/buf.lock index f31ad2510..73ebfcf9b 100644 --- a/src/viam/examples/modules/complex/proto/buf.lock +++ b/src/viam/examples/modules/complex/proto/buf.lock @@ -4,5 +4,5 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: 546238c53f7340c6a2a6099fb863bc1b - digest: shake256:8d75c12f391e392b24c076d05117b47aeddb090add99c70247a8f4389b906a65f61a933c68e54ed8b73a050b967b6b712ba194348b67c3ab3ee26cc2cb25852c + commit: 751cbe31638d43a9bfb6162cd2352e67 + digest: shake256:87f55470d9d124e2d1dedfe0231221f4ed7efbc55bc5268917c678e2d9b9c41573a7f9a557f6d8539044524d9fc5ca8fbb7db05eb81379d168285d76b57eb8a4 diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index fff691fd2..a7f1f3b0f 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -256,7 +256,7 @@ std::shared_ptr RobotClient::with_channel(std::shared_ptr RobotClient::at_address(const std::string& address, const Options& options) { const char* uri = address.c_str(); - auto channel = ViamChannel::dial(uri, options.dial_options()); + auto channel = ViamChannel::dial_initial(uri, options.dial_options()); std::shared_ptr robot = RobotClient::with_channel(channel, options); robot->should_close_channel_ = true; diff --git a/src/viam/sdk/rpc/dial.cpp b/src/viam/sdk/rpc/dial.cpp index 2f4cbaa8d..d360acca2 100644 --- a/src/viam/sdk/rpc/dial.cpp +++ b/src/viam/sdk/rpc/dial.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -52,16 +53,35 @@ ViamChannel::ViamChannel(std::shared_ptr channel, const char* pat DialOptions::DialOptions() = default; -void DialOptions::set_credentials(boost::optional creds) { +DialOptions& DialOptions::set_credentials(boost::optional creds) { credentials_ = std::move(creds); + + return *this; } -void DialOptions::set_entity(boost::optional entity) { +DialOptions& DialOptions::set_entity(boost::optional entity) { auth_entity_ = std::move(entity); + + return *this; +} + +DialOptions& DialOptions::set_initial_connection_attempts(int attempts) { + initial_connection_attempts_ = attempts; + + return *this; } -void DialOptions::set_timeout(std::chrono::duration timeout) { - timeout_ = std::move(timeout); +DialOptions& DialOptions::set_timeout(std::chrono::duration timeout) { + timeout_ = timeout; + + return *this; +} + +DialOptions& DialOptions::set_initial_connection_attempt_timeout( + std::chrono::duration timeout) { + initial_connection_attempt_timeout_ = timeout; + + return *this; } const boost::optional& DialOptions::entity() const { @@ -72,18 +92,55 @@ const boost::optional& DialOptions::credentials() const { return credentials_; } +int DialOptions::initial_connection_attempts() const { + return initial_connection_attempts_; +} + const std::chrono::duration& DialOptions::timeout() const { return timeout_; } -void DialOptions::set_allow_insecure_downgrade(bool allow) { +std::chrono::duration DialOptions::initial_connection_attempt_timeout() const { + return initial_connection_attempt_timeout_; +} + +DialOptions& DialOptions::set_allow_insecure_downgrade(bool allow) { allow_insecure_downgrade_ = allow; + + return *this; } bool DialOptions::allows_insecure_downgrade() const { return allow_insecure_downgrade_; } +std::shared_ptr ViamChannel::dial_initial( + const char* uri, const boost::optional& options) { + DialOptions opts = options.get_value_or(DialOptions()); + auto timeout = opts.timeout(); + auto attempts_remaining = opts.initial_connection_attempts(); + if (attempts_remaining == 0) { + attempts_remaining = -1; + } + opts.set_timeout(opts.initial_connection_attempt_timeout()); + + while (attempts_remaining != 0) { + try { + auto connection = dial(uri, opts); + opts.set_timeout(timeout); + return connection; + } catch (const std::exception& e) { + attempts_remaining -= 1; + if (attempts_remaining == 0) { + throw e; + } + } + } + // the while loop will run until we either return or throw an error, so we can never reach this + // point + BOOST_UNREACHABLE_RETURN(nullptr) +} + std::shared_ptr ViamChannel::dial(const char* uri, const boost::optional& options) { void* ptr = init_rust_runtime(); diff --git a/src/viam/sdk/rpc/dial.hpp b/src/viam/sdk/rpc/dial.hpp index a8e2bf07a..64cf4e5df 100644 --- a/src/viam/sdk/rpc/dial.hpp +++ b/src/viam/sdk/rpc/dial.hpp @@ -16,9 +16,26 @@ class ViamChannel { public: void close(); ViamChannel(std::shared_ptr channel, const char* path, void* runtime); + + /// @brief Connects to a robot at the given URI address, using the provided dial options (or + /// default options is none are provided). Ignores initial connection options specifying + /// how many times to attempt to connect and with what timeout. + /// In general, use of this method is discouraged. `RobotClient::at_address(...)` is the + /// preferred method to connect to a robot, and creates the channel itself. + /// @throws Exception if it is unable to establish a connection to the provided URI static std::shared_ptr dial(const char* uri, const boost::optional& options); + // @brief Dials to a robot at the given URI address, using the provided dial options (or default + // options is none are provided). Additionally specifies that this dial is an initial connection + // attempt and so uses the initial connection options. + /// In general, use of this method is discouraged. `RobotClient::at_address(...)` is the + /// preferred method to connect to a robot, and creates the channel itself. + /// @throws Exception if it is unable to establish a connection to the provided URI within + /// the given number of initial connection attempts + static std::shared_ptr dial_initial(const char* uri, + const boost::optional& options); + const std::shared_ptr& channel() const; private: @@ -49,11 +66,15 @@ class DialOptions { const boost::optional& entity() const; bool allows_insecure_downgrade() const; const std::chrono::duration& timeout() const; + int initial_connection_attempts() const; + std::chrono::duration initial_connection_attempt_timeout() const; - void set_entity(boost::optional entity); - void set_credentials(boost::optional creds); - void set_allow_insecure_downgrade(bool allow); - void set_timeout(std::chrono::duration timeout); + DialOptions& set_entity(boost::optional entity); + DialOptions& set_credentials(boost::optional creds); + DialOptions& set_allow_insecure_downgrade(bool allow); + DialOptions& set_timeout(std::chrono::duration timeout); + DialOptions& set_initial_connection_attempts(int attempts); + DialOptions& set_initial_connection_attempt_timeout(std::chrono::duration timeout); private: // TODO (RSDK-917): We currently don't provide a flag for disabling webRTC, instead relying on a @@ -72,6 +93,14 @@ class DialOptions { /// @brief Duration before the dial connection times out /// Set to 20sec to match _defaultOfferDeadline in goutils/rpc/wrtc_call_queue.go std::chrono::duration timeout_{20}; + + /// @brief Number of attempts to make when initially connecting to a robot + /// If set to 0 or a negative integer, will attempt to reconnect forever. + int initial_connection_attempts_ = 3; + + /// @brief Timeout of connection attempts when initially dialing a robot + /// Defaults to 20sec to match the default timeout duration + std::chrono::duration initial_connection_attempt_timeout_{20}; }; class Options {