From 4a29d46bb9ecaac6783eb757bac80e7c451a440f Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 20:56:14 +0000 Subject: [PATCH 01/20] Implement Channel Type Builder --- grpc/src/client/channel.rs | 241 +++++++++++------------- grpc/src/client/interceptor.rs | 20 +- grpc/src/client/mod.rs | 1 - grpc/src/client/name_resolution/mod.rs | 3 + grpc/src/client/transport/tonic/test.rs | 33 ++-- 5 files changed, 142 insertions(+), 156 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 2239bf97d..e75265a38 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -29,9 +29,7 @@ use std::error::Error; use std::str::FromStr; use std::sync::Arc; use std::sync::Mutex; -use std::time::Duration; use std::time::Instant; -use std::vec; use serde_json::json; use tokio::sync::mpsc; @@ -40,7 +38,6 @@ use url::Url; // NOTE: http::Uri requires non-empty authority portion of URI use crate::StatusCodeError; use crate::StatusError; -use crate::attributes::Attributes; use crate::client::CallOptions; use crate::client::ConnectivityState; use crate::client::DynInvoke; @@ -80,78 +77,13 @@ use crate::client::transport::TransportRegistry; #[cfg(feature = "_runtime-tokio")] use crate::client::transport::tonic as tonic_transport; use crate::core::RequestHeaders; -use crate::credentials::ChannelCredentials; use crate::credentials::client::ClientHandshakeInfo; use crate::credentials::common::Authority; use crate::credentials::dyn_wrapper::DynChannelCredentials; use crate::rt; -use crate::rt::GrpcEndpoint; use crate::rt::GrpcRuntime; use crate::rt::default_runtime; -/// Configuration options for [`Channel`]s. -#[non_exhaustive] -pub struct ChannelOptions { - pub(crate) transport_options: Attributes, // ? - pub(crate) channel_authority: Option, - pub(crate) connection_backoff: Option, - pub(crate) default_service_config: Option, - pub(crate) disable_proxy: bool, - pub(crate) disable_service_config_lookup: bool, - pub(crate) disable_health_checks: bool, - pub(crate) max_retry_memory: u32, // ? - pub(crate) idle_timeout: Duration, - // TODO: pub transport_registry: Option, - // TODO: pub name_resolver_registry: Option, - // TODO: pub lb_policy_registry: Option, - - // Typically we allow settings at the channel level that impact all RPCs, - // but can also be set per-RPC. E.g.s: - // - // - interceptors - // - user-agent string override - // - max message sizes - // - max retry/hedged attempts - // - disable retry - // - // In gRPC-Go, we can express CallOptions as DialOptions, which is a nice - // pattern: https://pkg.go.dev/google.golang.org/grpc#WithDefaultCallOptions - // - // To do this in rust, all optional behavior for a request would need to be - // expressed through a trait that applies a mutation to a request. We'd - // apply all those mutations before the user's options so the user's options - // would override the defaults, or so the defaults would occur first. - pub(crate) default_request_extensions: Vec, // ?? -} - -impl Default for ChannelOptions { - fn default() -> Self { - Self { - transport_options: Attributes::default(), - channel_authority: None, - connection_backoff: None, - default_service_config: None, - disable_proxy: false, - disable_service_config_lookup: false, - disable_health_checks: false, - max_retry_memory: 8 * 1024 * 1024, // 8MB -- ??? - idle_timeout: Duration::from_secs(30 * 60), - default_request_extensions: vec![], - } - } -} - -impl ChannelOptions { - /// Overrides the channel authority, which is used for credentials - /// handshaking and HTTP virtual hosting. - pub fn override_authority(self, authority: impl Into) -> Self { - Self { - channel_authority: Some(authority.into()), - ..self - } - } -} - /// A virtual, persistent connection to a gRPC service. /// /// A `Channel` begins in an "idle" state and connects when the first RPC is @@ -164,33 +96,14 @@ pub struct Channel { } impl Channel { - /// Constructs a new gRPC channel. Channel creation cannot fail, but if the - /// target string is invalid, the returned channel will never connect, and - /// will fail all RPCs. - pub fn new(target: impl Into, credentials: Arc, options: ChannelOptions) -> Self - where - C: ChannelCredentials, - C::Output>: GrpcEndpoint + 'static, - { - pick_first::reg(); - round_robin::reg(); - dns::reg(); - #[cfg(unix)] - name_resolution::unix::reg(); - #[cfg(target_os = "linux")] - name_resolution::unix_abstract::reg(); - #[cfg(feature = "_runtime-tokio")] - tonic_transport::reg(); - Self { - inner: Arc::new(PersistentChannel::new( - target, - default_runtime(), - options, - credentials as Arc, - )), + pub(crate) fn builder(target: impl Into) -> ChannelBuilder { + ChannelBuilder { + target: target.into(), + credentials: MissingOpt, + runtime: MissingOpt, + channel_authority: None, } } - // TODO: enter_idle(&self) and graceful_stop()? /// Returns the current state of the channel. If `connect` is true and the @@ -225,54 +138,113 @@ impl Invoke for Channel { } } -// A PersistentChannel represents the static configuration of a channel and an -// optional Arc of an ActiveChannel. An ActiveChannel exists whenever the -// PersistentChannel is not IDLE. Every channel is IDLE at creation, or after -// some configurable timeout elapses without any any RPC activity. -struct PersistentChannel { - target: Target, - resolver_builder: Arc, - options: ChannelOptions, - active_channel: Mutex>>, - runtime: GrpcRuntime, - security_opts: SecurityOpts, - authority: String, +pub struct MissingOpt; +pub struct PresentOpt(pub T); + +type PresentCredentials = PresentOpt>; +type PresentRuntime = PresentOpt; + +pub struct ChannelBuilder { + // Required values. + target: String, + credentials: C, + runtime: R, // Can be defaulted w/Tokio runtime feature. + + // Optional values. + channel_authority: Option, } -impl PersistentChannel { - // Channels begin idle so `new()` does not automatically connect. - // ChannelOption contain only optional parameters. - fn new( - target: impl Into, - runtime: GrpcRuntime, - options: ChannelOptions, +/// Impl for adding the required credentials to the builder. +// This is provided as a separate builder function to allow for the possibility +// of satisfying the credential/security configuration through different means +// in the future (via adding methods to this impl taking different args). +impl ChannelBuilder { + pub fn credentials( + self, credentials: Arc, - ) -> Self { - // TODO(arjan-bal): Return errors here instead of panicking. - let target = Url::from_str(&target.into()).unwrap(); + ) -> ChannelBuilder { + ChannelBuilder { + target: self.target, + credentials: PresentOpt(credentials.into()), + runtime: self.runtime, + channel_authority: self.channel_authority, + } + } +} + +/// Impl for adding the required runtime to the builder. If the Tokio runtime +/// feature is enabled, skipping this will cause the default Tokio runtime to be +/// used. +impl ChannelBuilder { + pub fn runtime(self, runtime: GrpcRuntime) -> ChannelBuilder { + ChannelBuilder { + target: self.target, + credentials: self.credentials, + runtime: PresentOpt(runtime), + channel_authority: self.channel_authority, + } + } +} + +/// If the Tokio runtime feature is enabled, the channel builder can be built +/// without explicitly providing a runtime, defaulting to the Tokio runtime. +/// This does not prevent a user from providing their own runtime if they wish, +/// and the builder will work as normal. +#[cfg(feature = "_runtime-tokio")] +impl ChannelBuilder { + pub fn build(self) -> Channel { + self.runtime(default_runtime()).build() + } +} + +impl ChannelBuilder { + pub fn build(self) -> Channel { + // TODO(nford) This construction is currently a rough-cut placeholder. + // The design of PersistentChannel and how and where it is initialized + // will be finalized with the 'Internal Channel Design' with + // consideration for: + // - error handling (inc. always-failing resolvers due to invalid targets)) + // - testing (inc. credential and transport configuration) + + // TODO(nford) Find a better place to set up default registries. + setup_registers(); + + let target = Url::from_str(self.target.as_str()).unwrap(); let resolver_builder = global_registry().get(target.scheme()).unwrap(); let target = name_resolution::Target::from(target); - let authority = options + let authority = self .channel_authority - .clone() .unwrap_or_else(|| resolver_builder.default_authority(&target).to_owned()); let security_opts = SecurityOpts { - credentials, + credentials: self.credentials.0, authority: parse_authority(&authority), handshake_info: ClientHandshakeInfo::default(), }; - - Self { - target, - resolver_builder, - active_channel: Mutex::default(), - options, - runtime, - security_opts, - authority, + Channel { + inner: Arc::new(PersistentChannel { + active_channel: Mutex::default(), + target: target, + security_opts: security_opts, + runtime: self.runtime.0, + resolver_builder, + }), } } +} + +struct PersistentChannel { + active_channel: Mutex>>, + // Configuration + target: Target, + security_opts: SecurityOpts, + runtime: GrpcRuntime, + + // Inferred Configuration + resolver_builder: Arc, +} + +impl PersistentChannel { /// Returns the current state of the channel. If there is no underlying active channel, /// returns Idle. If `connect` is true, will create a new active channel iff none exists. fn get_state(&self, connect: bool) -> ConnectivityState { @@ -329,7 +301,8 @@ impl ActiveChannel { let work_scheduler = Arc::new(ResolverWorkScheduler { wqtx }); let resolver_opts = name_resolution::ResolverOptions { - authority: persistent_channel.authority.clone(), + // authority: persistent_channel.security_opts.authority.clone(), + authority: "ignored".to_string(), // TODO(nford) currently, this option is always ignored. work_scheduler, runtime: runtime.clone(), }; @@ -621,6 +594,18 @@ fn parse_authority(host_and_port: &str) -> Authority { Authority::new(host_and_port.to_string(), None) } +fn setup_registers() { + pick_first::reg(); + round_robin::reg(); + dns::reg(); + #[cfg(unix)] + name_resolution::unix::reg(); + #[cfg(target_os = "linux")] + name_resolution::unix_abstract::reg(); + #[cfg(feature = "_runtime-tokio")] + tonic_transport::reg(); +} + #[cfg(test)] mod tests { use super::*; diff --git a/grpc/src/client/interceptor.rs b/grpc/src/client/interceptor.rs index 8dbf4fbd2..d058c2853 100644 --- a/grpc/src/client/interceptor.rs +++ b/grpc/src/client/interceptor.rs @@ -201,17 +201,15 @@ where /// /// ``` /// use std::sync::Arc; -/// use grpc::client::{Channel, ChannelOptions}; +/// use grpc::client::Channel; /// use grpc::credentials::LocalChannelCredentials; /// use grpc::client::stream_util::ResponseValidator; /// use grpc::client::interceptor::InvokeExt; /// /// // Create a channel: -/// let channel = Channel::new( -/// "dns:///localhost:123", -/// Arc::new(LocalChannelCredentials::new()), -/// ChannelOptions::default(), -/// ); +/// let channel = Channel::builder("dns:///localhost:123") +/// .credentials(Arc::new(LocalChannelCredentials::new())) +/// .build(); /// // Create an interceptor: /// let interceptor = ResponseValidator::new(true); /// @@ -247,17 +245,15 @@ pub trait InvokeExt: Invoke + Sized { /// /// ``` /// use std::sync::Arc; -/// use grpc::client::{Channel, ChannelOptions}; +/// use grpc::client::Channel; /// use grpc::credentials::LocalChannelCredentials; /// use grpc::client::stream_util::ResponseValidator; /// use grpc::client::interceptor::InvokeOnceExt; /// /// // Create a channel: -/// let channel = Channel::new( -/// "dns:///localhost:123", -/// Arc::new(LocalChannelCredentials::new()), -/// ChannelOptions::default(), -/// ); +/// let channel = Channel::builder("dns:///localhost:123") +/// .credentials(Arc::new(LocalChannelCredentials::new())) +/// .build(); /// // Create an interceptor: /// let interceptor = ResponseValidator::new(true); /// diff --git a/grpc/src/client/mod.rs b/grpc/src/client/mod.rs index 94fc8705c..a1daef560 100644 --- a/grpc/src/client/mod.rs +++ b/grpc/src/client/mod.rs @@ -62,7 +62,6 @@ pub(crate) mod service_config; pub mod stream_util; pub use channel::Channel; -pub use channel::ChannelOptions; pub(crate) mod load_balancing; pub(crate) mod name_resolution; diff --git a/grpc/src/client/name_resolution/mod.rs b/grpc/src/client/name_resolution/mod.rs index 9cecab56c..ad27f61b9 100644 --- a/grpc/src/client/name_resolution/mod.rs +++ b/grpc/src/client/name_resolution/mod.rs @@ -183,6 +183,9 @@ pub(crate) struct ResolverOptions { /// This value is either the result of the `default_authority` method of /// this `ResolverBuilder`, or another string if the channel was explicitly /// configured to override the default. + // TODO(nford): This field is currently unused. When/if it is needed ensure the type is appropriate. + // - Channels reference SecurityOpts, which hold the value in an Authority object. + // - All other references currently use "ignored" as the authority. pub authority: String, /// The runtime which provides utilities to do async work. diff --git a/grpc/src/client/transport/tonic/test.rs b/grpc/src/client/transport/tonic/test.rs index 6dc3fe478..6b710ae93 100644 --- a/grpc/src/client/transport/tonic/test.rs +++ b/grpc/src/client/transport/tonic/test.rs @@ -249,11 +249,9 @@ async fn grpc_invoke_tonic_unary() { // Create the channel. let target = format!("dns:///{}", addr); - let channel = Channel::new( - &target, - LocalChannelCredentials::new_arc(), - Default::default(), - ); + let channel = Channel::builder(&target) + .credentials(LocalChannelCredentials::new_arc()) + .build(); let (_, resp, trailers) = perform_unary_echo(&channel, "hello interop").await; assert_eq!(resp.message, "hello interop"); @@ -281,12 +279,9 @@ mod unix_tests { async fn run_unix_test(bind_path: &PathBuf, target: &str) { let listener = UnixListener::bind(bind_path).unwrap(); - - let channel = Channel::new( - target, - LocalChannelCredentials::new_arc(), - Default::default(), - ); + let channel = Channel::builder(target) + .credentials(LocalChannelCredentials::new_arc()) + .build(); let shutdown_notify = Arc::new(Notify::new()); let shutdown_notify_copy = shutdown_notify.clone(); @@ -457,7 +452,9 @@ async fn grpc_invoke_tonic_unary_tls() { let composite_creds = CompositeChannelCredentials::new(creds, call_creds); let target = format!("dns:///{}", addr); - let channel = Channel::new(&target, Arc::new(composite_creds), Default::default()); + let channel = Channel::builder(&target) + .credentials(Arc::new(composite_creds)) + .build(); let (headers, resp, trilers) = perform_unary_echo(&channel, "hello interop tls").await; assert_eq!( @@ -509,7 +506,9 @@ async fn grpc_invoke_failure_cases() { should_fail: None, }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::new(&target, Arc::new(composite_creds), Default::default()); + let channel = Channel::builder(&target) + .credentials(Arc::new(composite_creds)) + .build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( @@ -530,7 +529,9 @@ async fn grpc_invoke_failure_cases() { )), }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::new(&target, Arc::new(composite_creds), Default::default()); + let channel = Channel::builder(&target) + .credentials(Arc::new(composite_creds)) + .build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( @@ -559,7 +560,9 @@ async fn grpc_invoke_failure_cases() { )), }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::new(&target, Arc::new(composite_creds), Default::default()); + let channel = Channel::builder(&target) + .credentials(Arc::new(composite_creds)) + .build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( From 6739db63aada059677c5c07e14e159ae1139559e Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 21:18:06 +0000 Subject: [PATCH 02/20] Update ChannelBuilder to use IntoDynChannelCredentials trait. Make Channel::builder public and update ChannelBuilder::credentials to accept impl IntoDynChannelCredentials instead of Arc. --- grpc/src/client/channel.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index e75265a38..6e919f463 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -82,6 +82,7 @@ use crate::credentials::common::Authority; use crate::credentials::dyn_wrapper::DynChannelCredentials; use crate::rt; use crate::rt::GrpcRuntime; +#[cfg(feature = "_runtime-tokio")] use crate::rt::default_runtime; /// A virtual, persistent connection to a gRPC service. @@ -96,7 +97,7 @@ pub struct Channel { } impl Channel { - pub(crate) fn builder(target: impl Into) -> ChannelBuilder { + pub fn builder(target: impl Into) -> ChannelBuilder { ChannelBuilder { target: target.into(), credentials: MissingOpt, @@ -159,13 +160,13 @@ pub struct ChannelBuilder { // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { - pub fn credentials( - self, - credentials: Arc, - ) -> ChannelBuilder { + pub fn credentials(self, credentials: C) -> ChannelBuilder + where + C: crate::credentials::dyn_wrapper::IntoDynChannelCredentials, + { ChannelBuilder { target: self.target, - credentials: PresentOpt(credentials.into()), + credentials: PresentOpt(credentials.into_dyn_creds()), runtime: self.runtime, channel_authority: self.channel_authority, } From ef64d7c76109dbb312cce500e1743118f9882a62 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 22:27:36 +0000 Subject: [PATCH 03/20] Add optional method for channel authority override. --- grpc/src/client/channel.rs | 11 ++++++++++- interop/src/bin/client.rs | 20 +++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 6e919f463..0a284abed 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -152,7 +152,7 @@ pub struct ChannelBuilder { runtime: R, // Can be defaulted w/Tokio runtime feature. // Optional values. - channel_authority: Option, + channel_authority: Option, // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. } /// Impl for adding the required credentials to the builder. @@ -187,6 +187,15 @@ impl ChannelBuilder { } } +impl ChannelBuilder { + // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. + // May need to change how this is being set on the builder. + pub fn channel_authority(mut self, authority: impl Into) -> Self { + self.channel_authority = Some(authority.into()); + self + } +} + /// If the Tokio runtime feature is enabled, the channel builder can be built /// without explicitly providing a runtime, defaulting to the Tokio runtime. /// This does not prevent a user from providing their own runtime if they wish, diff --git a/interop/src/bin/client.rs b/interop/src/bin/client.rs index 7c2124123..fd6621547 100644 --- a/interop/src/bin/client.rs +++ b/interop/src/bin/client.rs @@ -99,21 +99,15 @@ async fn main() -> Result<(), Box> { GrpcClientTlsConfig::new() .with_root_certificates_provider(StaticProvider::new(root_certs)), )?; - let channel_options = - ChannelOptions::default().override_authority("test.test.google.fr"); - grpc::client::Channel::new( - "dns:///localhost:10000", - Arc::new(creds), - channel_options, - ) + grpc::client::Channel::builder("dns:///localhost:10000") + .credentials(creds) + .channel_authority("test.test.google.fr") + .build() } else { - grpc::client::Channel::new( - "dns:///localhost:10000", - Arc::new(LocalChannelCredentials::new()), - ChannelOptions::default(), - ) + grpc::client::Channel::builder("dns:///localhost:10000") + .credentials(LocalChannelCredentials::new()) + .build() }; - ( Box::new(client_protobuf::TestClient::new(channel.clone())), Box::new(client_protobuf::UnimplementedClient::new(channel)), From b9bce2af4827ddb3508f1c3a4bef68ce990ed950 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 22:34:29 +0000 Subject: [PATCH 04/20] Fix imports in interop client. --- grpc/src/client/channel.rs | 4 ++-- interop/src/bin/client.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 0a284abed..4436cfd1b 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -233,8 +233,8 @@ impl ChannelBuilder { Channel { inner: Arc::new(PersistentChannel { active_channel: Mutex::default(), - target: target, - security_opts: security_opts, + target, + security_opts, runtime: self.runtime.0, resolver_builder, }), diff --git a/interop/src/bin/client.rs b/interop/src/bin/client.rs index fd6621547..3a899ea48 100644 --- a/interop/src/bin/client.rs +++ b/interop/src/bin/client.rs @@ -1,8 +1,6 @@ use std::str::FromStr; -use std::sync::Arc; use std::time::Duration; -use grpc::client::ChannelOptions; use grpc::credentials::LocalChannelCredentials; use grpc::credentials::rustls::RootCertificates; use grpc::credentials::rustls::StaticProvider; From 7f240f9f25b9f32a48d2f015f1fd6bfcb0f94c92 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 22:42:50 +0000 Subject: [PATCH 05/20] Update examples to use the new Channel builder. --- examples/src/grpc-helloworld/client.rs | 9 +++------ examples/src/grpc-routeguide/client.rs | 10 ++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/examples/src/grpc-helloworld/client.rs b/examples/src/grpc-helloworld/client.rs index 87fba7e6c..865d75436 100644 --- a/examples/src/grpc-helloworld/client.rs +++ b/examples/src/grpc-helloworld/client.rs @@ -11,7 +11,6 @@ use std::sync::Arc; use generated::helloworld::HelloRequest; use generated::helloworld::greeter_client::GreeterClient; use grpc::client::Channel; -use grpc::client::ChannelOptions; use grpc::credentials::LocalChannelCredentials; use protobuf::proto; @@ -25,11 +24,9 @@ async fn main() { }; // Create a new gRPC channel: - let channel = Channel::new( - "dns:///[::1]:50051", - Arc::new(LocalChannelCredentials::new()), - ChannelOptions::default(), - ); + let channel = Channel::builder("dns:///[::1]:50051") + .credentials(Arc::new(LocalChannelCredentials::new())) + .build(); let client = GreeterClient::new(channel); // Send the request and print the response: diff --git a/examples/src/grpc-routeguide/client.rs b/examples/src/grpc-routeguide/client.rs index a94ff2ef2..66f1d763c 100644 --- a/examples/src/grpc-routeguide/client.rs +++ b/examples/src/grpc-routeguide/client.rs @@ -11,7 +11,6 @@ use std::env; use std::sync::Arc; use grpc::client::Channel; -use grpc::client::ChannelOptions; use grpc::client::Invoke; use grpc::credentials::LocalChannelCredentials; use tokio::task; @@ -180,11 +179,10 @@ async fn main() { println!("Connecting to {address}..."); // Create a new gRPC channel: - let channel = Channel::new( - format!("dns:///{address}"), - Arc::new(LocalChannelCredentials::new()), - ChannelOptions::default(), - ); + let channel = Channel::builder(format!("dns:///{address}")) + .credentials(Arc::new(LocalChannelCredentials::new())) + .build(); + let client = RouteGuideClient::new(channel); println!("*** SIMPLE RPC ***"); From 7365a7a991e9df06c58b6fed4b0b3a6471103847 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 23:13:21 +0000 Subject: [PATCH 06/20] Cleanup --- grpc/src/client/channel.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 4436cfd1b..cf6294158 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -155,7 +155,7 @@ pub struct ChannelBuilder { channel_authority: Option, // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. } -/// Impl for adding the required credentials to the builder. +/// Impl for adding the (required) credentials to the builder. // This is provided as a separate builder function to allow for the possibility // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). @@ -173,7 +173,7 @@ impl ChannelBuilder { } } -/// Impl for adding the required runtime to the builder. If the Tokio runtime +/// Impl for adding the (required) runtime to the builder. If the Tokio runtime /// feature is enabled, skipping this will cause the default Tokio runtime to be /// used. impl ChannelBuilder { @@ -217,7 +217,7 @@ impl ChannelBuilder { // - testing (inc. credential and transport configuration) // TODO(nford) Find a better place to set up default registries. - setup_registers(); + setup_registeries(); let target = Url::from_str(self.target.as_str()).unwrap(); let resolver_builder = global_registry().get(target.scheme()).unwrap(); @@ -604,7 +604,9 @@ fn parse_authority(host_and_port: &str) -> Authority { Authority::new(host_and_port.to_string(), None) } -fn setup_registers() { +// Sets up the default registries for transports, name resolvers, and load +// balancers. +fn setup_registeries() { pick_first::reg(); round_robin::reg(); dns::reg(); From d2649c6f94fdbe6f086a5bfffe8a172da404172c Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 4 Jun 2026 23:47:32 +0000 Subject: [PATCH 07/20] Cleanup and version bump. --- grpc-protobuf-build/Cargo.toml | 4 ++-- grpc-protobuf/Cargo.toml | 4 ++-- grpc/Cargo.toml | 2 +- grpc/src/client/channel.rs | 7 +++++++ protoc-gen-rust-grpc/Cargo.toml | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/grpc-protobuf-build/Cargo.toml b/grpc-protobuf-build/Cargo.toml index 9f41dcb98..04d52d6ac 100644 --- a/grpc-protobuf-build/Cargo.toml +++ b/grpc-protobuf-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grpc-protobuf-build" -version = "0.9.0" +version = "0.10.0" authors = ["gRPC Authors"] license = "MIT" homepage = "https://grpc.io" @@ -17,7 +17,7 @@ prettyplease = "0.2.35" protobuf-codegen = { version = "4.34.0-release" } syn = "2.0.104" which = "8.0" -protoc-gen-rust-grpc = { version = "0.9.0", path = "../protoc-gen-rust-grpc", optional = true } +protoc-gen-rust-grpc = { version = "0.10.0", path = "../protoc-gen-rust-grpc", optional = true } [features] default = ["build-plugin"] diff --git a/grpc-protobuf/Cargo.toml b/grpc-protobuf/Cargo.toml index 818e2e68f..d356539ff 100644 --- a/grpc-protobuf/Cargo.toml +++ b/grpc-protobuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grpc-protobuf" -version = "0.9.0" +version = "0.10.0" authors = ["gRPC Authors"] license = "MIT" homepage = "https://grpc.io" @@ -22,7 +22,7 @@ allowed_external_types = [ [dependencies] bytes = "1.11.1" -grpc = { version = "0.9.0", path = "../grpc" } +grpc = { version = "0.10.0", path = "../grpc" } protobuf = "4.34.0-release" [dev-dependencies] diff --git a/grpc/Cargo.toml b/grpc/Cargo.toml index c0c2434b0..769202fa4 100644 --- a/grpc/Cargo.toml +++ b/grpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grpc" -version = "0.9.0" +version = "0.10.0" authors = ["gRPC Authors"] license = "MIT" homepage = "https://grpc.io" diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index cf6294158..b1f549f33 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -152,6 +152,13 @@ pub struct ChannelBuilder { runtime: R, // Can be defaulted w/Tokio runtime feature. // Optional values. + // TODO(nford) In follow-up implement the following optional values: + // - default_service_config + // - http_proxy_cfg + // - disable_health_checks + // - idle_timeout + // - enable_channelz + // - keepalive_cfg channel_authority: Option, // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. } diff --git a/protoc-gen-rust-grpc/Cargo.toml b/protoc-gen-rust-grpc/Cargo.toml index 5fe3ea2cb..cf87cecd6 100644 --- a/protoc-gen-rust-grpc/Cargo.toml +++ b/protoc-gen-rust-grpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "protoc-gen-rust-grpc" -version = "0.9.0" +version = "0.10.0" authors = ["gRPC Authors"] license = "MIT" homepage = "https://grpc.io" From 44f7e275e35f55bcb16124d3442e63bfed32e2d2 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 11 Jun 2026 18:02:29 +0000 Subject: [PATCH 08/20] Fix typing on credentials builder impl. --- grpc/src/client/channel.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index b1f549f33..626d92562 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -167,13 +167,14 @@ pub struct ChannelBuilder { // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { - pub fn credentials(self, credentials: C) -> ChannelBuilder + pub fn credentials(self, credentials: Arc) -> ChannelBuilder where - C: crate::credentials::dyn_wrapper::IntoDynChannelCredentials, + C: crate::credentials::ChannelCredentials + 'static, + C::Output>: crate::rt::GrpcEndpoint, { ChannelBuilder { target: self.target, - credentials: PresentOpt(credentials.into_dyn_creds()), + credentials: PresentOpt(credentials), runtime: self.runtime, channel_authority: self.channel_authority, } From c0e1055eb946eb033b71fddb9f6a12bfe634247e Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Thu, 11 Jun 2026 19:47:56 +0000 Subject: [PATCH 09/20] Cleanup credential typing. --- grpc/src/client/channel.rs | 12 ++++++++---- interop/src/bin/client.rs | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 626d92562..36804a235 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -79,7 +79,6 @@ use crate::client::transport::tonic as tonic_transport; use crate::core::RequestHeaders; use crate::credentials::client::ClientHandshakeInfo; use crate::credentials::common::Authority; -use crate::credentials::dyn_wrapper::DynChannelCredentials; use crate::rt; use crate::rt::GrpcRuntime; #[cfg(feature = "_runtime-tokio")] @@ -142,7 +141,12 @@ impl Invoke for Channel { pub struct MissingOpt; pub struct PresentOpt(pub T); -type PresentCredentials = PresentOpt>; +// An opaque struct for holding credentials provided to the builder while +// complying with compiler public/private interface rules. +pub struct CredentialConfig( + pub(crate) Arc, +); +type PresentCredentials = PresentOpt; type PresentRuntime = PresentOpt; pub struct ChannelBuilder { @@ -174,7 +178,7 @@ impl ChannelBuilder { { ChannelBuilder { target: self.target, - credentials: PresentOpt(credentials), + credentials: PresentOpt(CredentialConfig(credentials)), runtime: self.runtime, channel_authority: self.channel_authority, } @@ -234,7 +238,7 @@ impl ChannelBuilder { .channel_authority .unwrap_or_else(|| resolver_builder.default_authority(&target).to_owned()); let security_opts = SecurityOpts { - credentials: self.credentials.0, + credentials: self.credentials.0.0, authority: parse_authority(&authority), handshake_info: ClientHandshakeInfo::default(), }; diff --git a/interop/src/bin/client.rs b/interop/src/bin/client.rs index 3a899ea48..d010a819a 100644 --- a/interop/src/bin/client.rs +++ b/interop/src/bin/client.rs @@ -1,4 +1,5 @@ use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use grpc::credentials::LocalChannelCredentials; @@ -98,12 +99,12 @@ async fn main() -> Result<(), Box> { .with_root_certificates_provider(StaticProvider::new(root_certs)), )?; grpc::client::Channel::builder("dns:///localhost:10000") - .credentials(creds) + .credentials(Arc::new(creds)) .channel_authority("test.test.google.fr") .build() } else { grpc::client::Channel::builder("dns:///localhost:10000") - .credentials(LocalChannelCredentials::new()) + .credentials(Arc::new(LocalChannelCredentials::new())) .build() }; ( From 65b77385e0b7a0e8c91e975d5749cd696d368a9d Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 16 Jun 2026 20:27:48 +0000 Subject: [PATCH 10/20] Add into implementation for CredentialConfig, which along with the DynChannelCredential impl adjustments should handle the type issue when passing DynChannelCredentials internally --- grpc/src/client/channel.rs | 30 +++++++++++++++++---- grpc/src/client/mod.rs | 2 ++ grpc/src/credentials/dyn_wrapper.rs | 41 +++++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 36804a235..db548f36b 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -146,6 +146,29 @@ pub struct PresentOpt(pub T); pub struct CredentialConfig( pub(crate) Arc, ); + +/// A trait for types that can be converted into a `CredentialConfig`. +pub trait IntoCredentialConfig { + #[doc(hidden)] + fn into_config(self) -> CredentialConfig; +} + +impl IntoCredentialConfig for Arc +where + C: crate::credentials::ChannelCredentials + Sized + 'static, + C::Output>: crate::rt::GrpcEndpoint, +{ + fn into_config(self) -> CredentialConfig { + CredentialConfig(self) + } +} + +impl IntoCredentialConfig for Arc { + fn into_config(self) -> CredentialConfig { + CredentialConfig(self) + } +} + type PresentCredentials = PresentOpt; type PresentRuntime = PresentOpt; @@ -171,14 +194,11 @@ pub struct ChannelBuilder { // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { - pub fn credentials(self, credentials: Arc) -> ChannelBuilder - where - C: crate::credentials::ChannelCredentials + 'static, - C::Output>: crate::rt::GrpcEndpoint, + pub fn credentials(self, credentials: impl IntoCredentialConfig) -> ChannelBuilder { ChannelBuilder { target: self.target, - credentials: PresentOpt(CredentialConfig(credentials)), + credentials: PresentOpt(credentials.into_config()), runtime: self.runtime, channel_authority: self.channel_authority, } diff --git a/grpc/src/client/mod.rs b/grpc/src/client/mod.rs index a1daef560..d551cd8b8 100644 --- a/grpc/src/client/mod.rs +++ b/grpc/src/client/mod.rs @@ -62,6 +62,8 @@ pub(crate) mod service_config; pub mod stream_util; pub use channel::Channel; +pub use channel::CredentialConfig; +pub use channel::IntoCredentialConfig; pub(crate) mod load_balancing; pub(crate) mod name_resolution; diff --git a/grpc/src/credentials/dyn_wrapper.rs b/grpc/src/credentials/dyn_wrapper.rs index 09543d1c5..37f8ad4f1 100644 --- a/grpc/src/credentials/dyn_wrapper.rs +++ b/grpc/src/credentials/dyn_wrapper.rs @@ -95,7 +95,7 @@ where } } -impl ChannelCredentials for Arc { +impl ChannelCredentials for dyn DynChannelCredentials { type ContextType = Box; type Output = BoxEndpoint; @@ -107,17 +107,42 @@ impl ChannelCredentials for Arc { runtime: &GrpcRuntime, _token: private::Internal, ) -> Result, Self::ContextType>, String> { - (**self) - .dyn_connect(authority, Box::new(source), info, runtime) + self.dyn_connect(authority, Box::new(source), info, runtime) .await } fn get_call_credentials(&self, _: private::Internal) -> Option<&Arc> { - (**self).get_call_credentials() + self.get_call_credentials() } fn info(&self) -> &ProtocolInfo { - (**self).info() + self.info() + } +} + +impl ChannelCredentials for Arc { + type ContextType = Box; + type Output = BoxEndpoint; + + async fn connect( + &self, + authority: &Authority, + source: Input, + info: &ClientHandshakeInfo, + runtime: &GrpcRuntime, + token: private::Internal, + ) -> Result, Self::ContextType>, String> { + (**self) + .connect(authority, source, info, runtime, token) + .await + } + + fn get_call_credentials(&self, token: private::Internal) -> Option<&Arc> { + ChannelCredentials::get_call_credentials(&**self, token) + } + + fn info(&self) -> &ProtocolInfo { + ChannelCredentials::info(&**self) } } @@ -273,4 +298,10 @@ mod tests { client_handle.abort(); } + + #[test] + fn test_channel_builder_with_dyn_creds() { + let dyn_creds = LocalChannelCredentials::new_arc() as Arc; + let _builder = crate::client::Channel::builder("localhost").credentials(dyn_creds); + } } From 45f16c0122b64107a417c2185066163bcecedd2f Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Wed, 17 Jun 2026 16:03:00 +0000 Subject: [PATCH 11/20] Fix formatting --- grpc/src/client/channel.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index db548f36b..58856bbd4 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -194,8 +194,10 @@ pub struct ChannelBuilder { // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { - pub fn credentials(self, credentials: impl IntoCredentialConfig) -> ChannelBuilder - { + pub fn credentials( + self, + credentials: impl IntoCredentialConfig, + ) -> ChannelBuilder { ChannelBuilder { target: self.target, credentials: PresentOpt(credentials.into_config()), From c82154185b93e6350b3e7f895da29d0ea8cc430f Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Wed, 17 Jun 2026 16:28:09 +0000 Subject: [PATCH 12/20] Fix new example to use builder. --- examples/src/grpc-gcp/client.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/src/grpc-gcp/client.rs b/examples/src/grpc-gcp/client.rs index c242f8084..614141e30 100644 --- a/examples/src/grpc-gcp/client.rs +++ b/examples/src/grpc-gcp/client.rs @@ -53,7 +53,9 @@ async fn main() -> Result<(), Box> { let tls = RustlsChannelCredendials::new(ClientTlsConfig::new())?; let channel_creds = CompositeChannelCredentials::new(tls, Arc::new(call_creds)); - let channel = Channel::new(ENDPOINT, Arc::new(channel_creds), Default::default()); + let channel = Channel::builder(ENDPOINT) + .credentials(Arc::new(channel_creds)) + .build(); let client = PublisherClient::new(channel); From e197877d5aaee155496f05106cadb1c6a2efad89 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Mon, 6 Jul 2026 18:35:10 +0000 Subject: [PATCH 13/20] Fix merge issues, use direct Arc --- grpc/src/client/channel.rs | 51 +++++++++++++------------ grpc/src/client/mod.rs | 1 - grpc/src/client/transport/tonic/test.rs | 16 +++----- grpc/src/credentials/dyn_wrapper.rs | 6 --- 4 files changed, 32 insertions(+), 42 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index ff0f98914..cdb3151cd 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -76,6 +76,7 @@ use crate::client::transport::TransportRegistry; #[cfg(feature = "_runtime-tokio")] use crate::client::transport::tonic as tonic_transport; use crate::core::RequestHeaders; +use crate::credentials::ChannelCredentials; use crate::credentials::client::ClientHandshakeInfo; use crate::credentials::common::Authority; use crate::rt; @@ -140,36 +141,36 @@ impl Invoke for Channel { pub struct MissingOpt; pub struct PresentOpt(pub T); -// An opaque struct for holding credentials provided to the builder while -// complying with compiler public/private interface rules. -pub struct CredentialConfig( - pub(crate) Arc, -); +type PresentCredentials = PresentOpt>; +type PresentRuntime = PresentOpt; -/// A trait for types that can be converted into a `CredentialConfig`. pub trait IntoCredentialConfig { - #[doc(hidden)] - fn into_config(self) -> CredentialConfig; + fn into_config(self) -> Arc; } impl IntoCredentialConfig for Arc where - C: crate::credentials::ChannelCredentials + Sized + 'static, - C::Output>: crate::rt::GrpcEndpoint, + C: ChannelCredentials + Sized + 'static, { - fn into_config(self) -> CredentialConfig { - CredentialConfig(self) + fn into_config(self) -> Arc { + self } } -impl IntoCredentialConfig for Arc { - fn into_config(self) -> CredentialConfig { - CredentialConfig(self) +impl IntoCredentialConfig for Arc { + fn into_config(self) -> Arc { + self } } -type PresentCredentials = PresentOpt; -type PresentRuntime = PresentOpt; +impl IntoCredentialConfig for C +where + C: ChannelCredentials + Sized + 'static, +{ + fn into_config(self) -> Arc { + Arc::new(self) + } +} pub struct ChannelBuilder { // Required values. @@ -178,14 +179,14 @@ pub struct ChannelBuilder { runtime: R, // Can be defaulted w/Tokio runtime feature. // Optional values. - // TODO(nford) In follow-up implement the following optional values: + // TODO(nathanielford) In follow-up implement the following optional values: // - default_service_config // - http_proxy_cfg // - disable_health_checks // - idle_timeout // - enable_channelz // - keepalive_cfg - channel_authority: Option, // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. + channel_authority: Option, // TODO(nathanielford) Revist if this is subsumed by the SecurityOpts authority. } /// Impl for adding the (required) credentials to the builder. @@ -221,7 +222,7 @@ impl ChannelBuilder { } impl ChannelBuilder { - // TODO(nford) Revist if this is subsumed by the SecurityOpts authority. + // TODO(nathanielford) Revist if this is subsumed by the SecurityOpts authority. // May need to change how this is being set on the builder. pub fn channel_authority(mut self, authority: impl Into) -> Self { self.channel_authority = Some(authority.into()); @@ -242,24 +243,24 @@ impl ChannelBuilder { impl ChannelBuilder { pub fn build(self) -> Channel { - // TODO(nford) This construction is currently a rough-cut placeholder. + // TODO(nathanielford) This construction is currently a rough-cut placeholder. // The design of PersistentChannel and how and where it is initialized // will be finalized with the 'Internal Channel Design' with // consideration for: // - error handling (inc. always-failing resolvers due to invalid targets)) // - testing (inc. credential and transport configuration) - // TODO(nford) Find a better place to set up default registries. + // TODO(nathanielford) Find a better place to set up default registries. setup_registeries(); - let target = Url::from_str(self.target.as_str()).unwrap(); + let target = Target::from_str(self.target.as_str()).unwrap(); let resolver_builder = global_registry().get(target.scheme()).unwrap(); let target = name_resolution::Target::from(target); let authority = self .channel_authority .unwrap_or_else(|| resolver_builder.default_authority(&target).to_owned()); let security_opts = SecurityOpts { - credentials: self.credentials.0.0, + credentials: self.credentials.0, authority: Authority::from_host_port_str(&authority), handshake_info: ClientHandshakeInfo::default(), }; @@ -345,7 +346,7 @@ impl ActiveChannel { let work_scheduler = Arc::new(ResolverWorkScheduler { wqtx }); let resolver_opts = name_resolution::ResolverOptions { // authority: persistent_channel.security_opts.authority.clone(), - authority: "ignored".to_string(), // TODO(nford) currently, this option is always ignored. + authority: "ignored".to_string(), // TODO(nathanielford) currently, this option is always ignored. work_scheduler, runtime: runtime.clone(), }; diff --git a/grpc/src/client/mod.rs b/grpc/src/client/mod.rs index d551cd8b8..60ae5716f 100644 --- a/grpc/src/client/mod.rs +++ b/grpc/src/client/mod.rs @@ -62,7 +62,6 @@ pub(crate) mod service_config; pub mod stream_util; pub use channel::Channel; -pub use channel::CredentialConfig; pub use channel::IntoCredentialConfig; pub(crate) mod load_balancing; diff --git a/grpc/src/client/transport/tonic/test.rs b/grpc/src/client/transport/tonic/test.rs index 16facd1c6..ea863dd89 100644 --- a/grpc/src/client/transport/tonic/test.rs +++ b/grpc/src/client/transport/tonic/test.rs @@ -893,11 +893,9 @@ async fn connect_timeout_exceeded() { // Create the channel with SlowChannelCredentials (21s). // The default timeout is 20s. let target = format!("dns:///{}", addr); - let channel = Channel::new( - &target, - SlowChannelCredentials::new_arc(Duration::from_secs(21)), - Default::default(), - ); + let channel = Channel::builder(&target) + .credentials(SlowChannelCredentials::new_arc(Duration::from_secs(21))) + .build(); // Spawn the RPC call because it will block waiting for connection. let rpc_handle = tokio::spawn(async move { perform_unary_echo_failure(&channel).await }); @@ -949,11 +947,9 @@ async fn trailers_only_metadata() { }); let target = format!("dns:///{}", addr); - let channel = Channel::new( - &target, - LocalChannelCredentials::new_arc(), - Default::default(), - ); + let channel = Channel::builder(&target) + .credentials(LocalChannelCredentials::new_arc()) + .build(); let trailers = perform_unary_echo_failure(&channel).await; diff --git a/grpc/src/credentials/dyn_wrapper.rs b/grpc/src/credentials/dyn_wrapper.rs index 7ca152de8..f6067c32e 100644 --- a/grpc/src/credentials/dyn_wrapper.rs +++ b/grpc/src/credentials/dyn_wrapper.rs @@ -129,10 +129,4 @@ mod tests { client_handle.abort(); } - - #[test] - fn test_channel_builder_with_dyn_creds() { - let dyn_creds = LocalChannelCredentials::new_arc() as Arc; - let _builder = crate::client::Channel::builder("localhost").credentials(dyn_creds); - } } From 0758d58b605fd8912103fe75b4b3033edec46090 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Mon, 6 Jul 2026 18:53:17 +0000 Subject: [PATCH 14/20] Fix comment --- grpc/src/client/name_resolution/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grpc/src/client/name_resolution/mod.rs b/grpc/src/client/name_resolution/mod.rs index 391634ee3..630372589 100644 --- a/grpc/src/client/name_resolution/mod.rs +++ b/grpc/src/client/name_resolution/mod.rs @@ -211,8 +211,10 @@ pub(crate) struct ResolverOptions { /// This value is either the result of the `default_authority` method of /// this `ResolverBuilder`, or another string if the channel was explicitly /// configured to override the default. - // TODO(nford): This field is currently unused. When/if it is needed ensure the type is appropriate. - // - Channels reference SecurityOpts, which hold the value in an Authority object. + // TODO(nathanielford): This field is currently unused. Review type if/when + // it is used. + // - Channels reference SecurityOpts, which hold the value in an Authority + // object. // - All other references currently use "ignored" as the authority. pub authority: String, From 73c3ddf98f57359887e99bda05ecddbe44345bac Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 7 Jul 2026 14:52:16 +0000 Subject: [PATCH 15/20] Remove tests that should have been removed in the merge --- grpc/src/client/channel.rs | 160 ------------------------------------- 1 file changed, 160 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index cdb3151cd..ad5a7368f 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -651,163 +651,3 @@ fn setup_registeries() { #[cfg(feature = "_runtime-tokio")] tonic_transport::reg(); } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_authority() { - struct TestCase { - input: &'static str, - expected: Authority, - } - - let cases = [ - TestCase { - input: "localhost:http", - expected: Authority::new("localhost:http", None), - }, - TestCase { - input: "localhost:80", - expected: Authority::new("localhost", Some(80)), - }, - // host name with zone identifier. - TestCase { - input: "localhost%lo0:80", - expected: Authority::new("localhost%lo0", Some(80)), - }, - TestCase { - input: "localhost%lo0:http", - expected: Authority::new("localhost%lo0:http", None), - }, - TestCase { - input: "[localhost%lo0]:http", - expected: Authority::new("[localhost%lo0]:http", None), - }, - TestCase { - input: "[localhost%lo0]:80", - expected: Authority::new("localhost%lo0", Some(80)), - }, - // IP literal - TestCase { - input: "127.0.0.1:http", - expected: Authority::new("127.0.0.1:http", None), - }, - TestCase { - input: "127.0.0.1:80", - expected: Authority::new("127.0.0.1", Some(80)), - }, - TestCase { - input: "[::1]:http", - expected: Authority::new("[::1]:http", None), - }, - TestCase { - input: "[::1]:80", - expected: Authority::new("::1", Some(80)), - }, - // IP literal with zone identifier. - TestCase { - input: "[::1%lo0]:http", - expected: Authority::new("[::1%lo0]:http", None), - }, - TestCase { - input: "[::1%lo0]:80", - expected: Authority::new("::1%lo0", Some(80)), - }, - TestCase { - input: ":http", - expected: Authority::new(":http", None), - }, - TestCase { - input: ":80", - expected: Authority::new("", Some(80)), - }, - TestCase { - input: "grpc.io:", - expected: Authority::new("grpc.io:", None), - }, - TestCase { - input: "127.0.0.1:", - expected: Authority::new("127.0.0.1:", None), - }, - TestCase { - input: "[::1]:", - expected: Authority::new("[::1]:", None), - }, - TestCase { - input: "grpc.io:https%foo", - expected: Authority::new("grpc.io:https%foo", None), - }, - TestCase { - input: "grpc.io", - expected: Authority::new("grpc.io", None), - }, - TestCase { - input: "127.0.0.1", - expected: Authority::new("127.0.0.1", None), - }, - TestCase { - input: "[::1]", - expected: Authority::new("[::1]", None), - }, - TestCase { - input: "[fe80::1%lo0]", - expected: Authority::new("[fe80::1%lo0]", None), - }, - TestCase { - input: "[localhost%lo0]", - expected: Authority::new("[localhost%lo0]", None), - }, - TestCase { - input: "localhost%lo0", - expected: Authority::new("localhost%lo0", None), - }, - TestCase { - input: "::1", - expected: Authority::new("::1", None), - }, - TestCase { - input: "fe80::1%lo0", - expected: Authority::new("fe80::1%lo0", None), - }, - TestCase { - input: "fe80::1%lo0:80", - expected: Authority::new("fe80::1%lo0:80", None), - }, - TestCase { - input: "[foo:bar]", - expected: Authority::new("[foo:bar]", None), - }, - TestCase { - input: "[foo:bar]baz", - expected: Authority::new("[foo:bar]baz", None), - }, - TestCase { - input: "[foo]bar:baz", - expected: Authority::new("[foo]bar:baz", None), - }, - TestCase { - input: "[foo]:[bar]:baz", - expected: Authority::new("[foo]:[bar]:baz", None), - }, - TestCase { - input: "[foo]:[bar]baz", - expected: Authority::new("[foo]:[bar]baz", None), - }, - TestCase { - input: "foo[bar]:baz", - expected: Authority::new("foo[bar]:baz", None), - }, - TestCase { - input: "foo]bar:baz", - expected: Authority::new("foo]bar:baz", None), - }, - ]; - - for TestCase { input, expected } in cases { - let auth = parse_authority(input); - assert_eq!(auth, expected, "authority mismatch for {}", input); - } - } -} From 8c1e34b1432789795bf8777cedd035f36707584f Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 7 Jul 2026 14:58:31 +0000 Subject: [PATCH 16/20] Adding ZSF to MissingOpt to prevent external usage, removing pub marker from PresentOpt since it is unneeded. --- grpc/src/client/channel.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index ad5a7368f..69b9b0c0b 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -99,8 +99,8 @@ impl Channel { pub fn builder(target: impl Into) -> ChannelBuilder { ChannelBuilder { target: target.into(), - credentials: MissingOpt, - runtime: MissingOpt, + credentials: MissingOpt(()), + runtime: MissingOpt(()), channel_authority: None, } } @@ -138,8 +138,8 @@ impl Invoke for Channel { } } -pub struct MissingOpt; -pub struct PresentOpt(pub T); +pub struct MissingOpt(()); +pub struct PresentOpt(T); type PresentCredentials = PresentOpt>; type PresentRuntime = PresentOpt; From e98a9c94177ec1ba2fc28b7da872f4dbd52e774e Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 7 Jul 2026 15:37:41 +0000 Subject: [PATCH 17/20] Comment removal --- grpc/src/client/name_resolution/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/grpc/src/client/name_resolution/mod.rs b/grpc/src/client/name_resolution/mod.rs index 630372589..f8e1266a6 100644 --- a/grpc/src/client/name_resolution/mod.rs +++ b/grpc/src/client/name_resolution/mod.rs @@ -211,11 +211,6 @@ pub(crate) struct ResolverOptions { /// This value is either the result of the `default_authority` method of /// this `ResolverBuilder`, or another string if the channel was explicitly /// configured to override the default. - // TODO(nathanielford): This field is currently unused. Review type if/when - // it is used. - // - Channels reference SecurityOpts, which hold the value in an Authority - // object. - // - All other references currently use "ignored" as the authority. pub authority: String, /// The runtime which provides utilities to do async work. From 2232440eead5a05534ea438fb3d71dc888f03714 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 7 Jul 2026 20:17:57 +0000 Subject: [PATCH 18/20] Comment fix. --- grpc/src/client/channel.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index 69b9b0c0b..b9d8cb85e 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -194,6 +194,7 @@ pub struct ChannelBuilder { // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { + /// Adds (required) channel credentials to the builder. pub fn credentials( self, credentials: impl IntoCredentialConfig, @@ -222,8 +223,8 @@ impl ChannelBuilder { } impl ChannelBuilder { - // TODO(nathanielford) Revist if this is subsumed by the SecurityOpts authority. - // May need to change how this is being set on the builder. + // TODO(nathanielford) Revisit if this is subsumed by the SecurityOpts + // authority. May need to change how this is being set on the builder. pub fn channel_authority(mut self, authority: impl Into) -> Self { self.channel_authority = Some(authority.into()); self @@ -255,6 +256,7 @@ impl ChannelBuilder { let target = Target::from_str(self.target.as_str()).unwrap(); let resolver_builder = global_registry().get(target.scheme()).unwrap(); + // TODO(nathanielford): Return errors here instead of panicking. let target = name_resolution::Target::from(target); let authority = self .channel_authority From fbcbbb101501b878f4c4bd7fa76d95327ade2012 Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Tue, 7 Jul 2026 22:21:04 +0000 Subject: [PATCH 19/20] Polish updates --- grpc/src/client/channel.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index b9d8cb85e..ce51d9809 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -96,6 +96,7 @@ pub struct Channel { } impl Channel { + /// Creates a new channel builder for the given target. pub fn builder(target: impl Into) -> ChannelBuilder { ChannelBuilder { target: target.into(), @@ -186,15 +187,14 @@ pub struct ChannelBuilder { // - idle_timeout // - enable_channelz // - keepalive_cfg - channel_authority: Option, // TODO(nathanielford) Revist if this is subsumed by the SecurityOpts authority. + channel_authority: Option, // TODO(nathanielford) Revisit if this is subsumed by the SecurityOpts authority. } -/// Impl for adding the (required) credentials to the builder. // This is provided as a separate builder function to allow for the possibility // of satisfying the credential/security configuration through different means // in the future (via adding methods to this impl taking different args). impl ChannelBuilder { - /// Adds (required) channel credentials to the builder. + /// (Required) Adds channel credentials to the builder. pub fn credentials( self, credentials: impl IntoCredentialConfig, @@ -208,10 +208,10 @@ impl ChannelBuilder { } } -/// Impl for adding the (required) runtime to the builder. If the Tokio runtime -/// feature is enabled, skipping this will cause the default Tokio runtime to be -/// used. impl ChannelBuilder { + /// (Required) Adds the runtime to the builder. If the Tokio runtime + /// feature is enabled, skipping this will cause the default Tokio runtime + /// to be used. pub fn runtime(self, runtime: GrpcRuntime) -> ChannelBuilder { ChannelBuilder { target: self.target, @@ -223,8 +223,8 @@ impl ChannelBuilder { } impl ChannelBuilder { - // TODO(nathanielford) Revisit if this is subsumed by the SecurityOpts - // authority. May need to change how this is being set on the builder. + /// Overrides the authority used for the channel. This will override both + /// any authority specified in the target or by the name resolver. pub fn channel_authority(mut self, authority: impl Into) -> Self { self.channel_authority = Some(authority.into()); self @@ -237,12 +237,24 @@ impl ChannelBuilder { /// and the builder will work as normal. #[cfg(feature = "_runtime-tokio")] impl ChannelBuilder { + /// Builds the channel with the provided configuration, using the default + /// Tokio runtime if no runtime was explicitly provided. pub fn build(self) -> Channel { self.runtime(default_runtime()).build() } } impl ChannelBuilder { + /// Builds the channel with the provided configuration. + /// # Example + /// + /// ``` + /// use grpc::credentials::LocalChannelCredentials; + /// + /// let channel = Channel::builder("dns:///localhost:123") + /// .credentials(Arc::new(LocalChannelCredentials::new())) + /// .build(); + /// ``` pub fn build(self) -> Channel { // TODO(nathanielford) This construction is currently a rough-cut placeholder. // The design of PersistentChannel and how and where it is initialized From 308b1c7d519b0483b2bbe553409895231d11235a Mon Sep 17 00:00:00 2001 From: Nathaniel Ford Date: Wed, 8 Jul 2026 21:46:32 +0000 Subject: [PATCH 20/20] Reversing course to a non-type builder --- examples/src/grpc-gcp/client.rs | 4 +- examples/src/grpc-helloworld/client.rs | 8 +- examples/src/grpc-routeguide/client.rs | 8 +- grpc/src/client/channel.rs | 132 ++++++------------------ grpc/src/client/interceptor.rs | 7 +- grpc/src/client/mod.rs | 1 - grpc/src/client/transport/tonic/test.rs | 36 +++---- interop/src/bin/client.rs | 11 +- 8 files changed, 64 insertions(+), 143 deletions(-) diff --git a/examples/src/grpc-gcp/client.rs b/examples/src/grpc-gcp/client.rs index 614141e30..e9e1989ef 100644 --- a/examples/src/grpc-gcp/client.rs +++ b/examples/src/grpc-gcp/client.rs @@ -53,9 +53,7 @@ async fn main() -> Result<(), Box> { let tls = RustlsChannelCredendials::new(ClientTlsConfig::new())?; let channel_creds = CompositeChannelCredentials::new(tls, Arc::new(call_creds)); - let channel = Channel::builder(ENDPOINT) - .credentials(Arc::new(channel_creds)) - .build(); + let channel = Channel::builder(ENDPOINT, Arc::new(channel_creds)).build(); let client = PublisherClient::new(channel); diff --git a/examples/src/grpc-helloworld/client.rs b/examples/src/grpc-helloworld/client.rs index 865d75436..76642eaef 100644 --- a/examples/src/grpc-helloworld/client.rs +++ b/examples/src/grpc-helloworld/client.rs @@ -24,9 +24,11 @@ async fn main() { }; // Create a new gRPC channel: - let channel = Channel::builder("dns:///[::1]:50051") - .credentials(Arc::new(LocalChannelCredentials::new())) - .build(); + let channel = Channel::builder( + "dns:///[::1]:50051", + Arc::new(LocalChannelCredentials::new()), + ) + .build(); let client = GreeterClient::new(channel); // Send the request and print the response: diff --git a/examples/src/grpc-routeguide/client.rs b/examples/src/grpc-routeguide/client.rs index 66f1d763c..cdf24cf39 100644 --- a/examples/src/grpc-routeguide/client.rs +++ b/examples/src/grpc-routeguide/client.rs @@ -179,9 +179,11 @@ async fn main() { println!("Connecting to {address}..."); // Create a new gRPC channel: - let channel = Channel::builder(format!("dns:///{address}")) - .credentials(Arc::new(LocalChannelCredentials::new())) - .build(); + let channel = Channel::builder( + format!("dns:///{address}"), + Arc::new(LocalChannelCredentials::new()), + ) + .build(); let client = RouteGuideClient::new(channel); diff --git a/grpc/src/client/channel.rs b/grpc/src/client/channel.rs index ce51d9809..5acb07668 100644 --- a/grpc/src/client/channel.rs +++ b/grpc/src/client/channel.rs @@ -97,12 +97,26 @@ pub struct Channel { impl Channel { /// Creates a new channel builder for the given target. - pub fn builder(target: impl Into) -> ChannelBuilder { + ///# Example + /// + /// ``` + /// use std::sync::Arc; + /// use grpc::client::Channel; + /// use grpc::credentials::LocalChannelCredentials; + /// + /// let channel = Channel::builder("dns:///localhost:123", Arc::new(LocalChannelCredentials::new())) + /// .build(); + /// ``` + #[cfg(feature = "_runtime-tokio")] + pub fn builder( + target: impl Into, + credentials: Arc, + ) -> ChannelBuilder { ChannelBuilder { target: target.into(), - credentials: MissingOpt(()), - runtime: MissingOpt(()), + credentials: credentials, channel_authority: None, + runtime: default_runtime(), } } // TODO: enter_idle(&self) and graceful_stop()? @@ -139,47 +153,14 @@ impl Invoke for Channel { } } -pub struct MissingOpt(()); -pub struct PresentOpt(T); - -type PresentCredentials = PresentOpt>; -type PresentRuntime = PresentOpt; - -pub trait IntoCredentialConfig { - fn into_config(self) -> Arc; -} - -impl IntoCredentialConfig for Arc -where - C: ChannelCredentials + Sized + 'static, -{ - fn into_config(self) -> Arc { - self - } -} - -impl IntoCredentialConfig for Arc { - fn into_config(self) -> Arc { - self - } -} - -impl IntoCredentialConfig for C -where - C: ChannelCredentials + Sized + 'static, -{ - fn into_config(self) -> Arc { - Arc::new(self) - } -} - -pub struct ChannelBuilder { +pub struct ChannelBuilder { // Required values. target: String, - credentials: C, - runtime: R, // Can be defaulted w/Tokio runtime feature. + credentials: Arc, + runtime: GrpcRuntime, // Optional values. + channel_authority: Option, // TODO(nathanielford) In follow-up implement the following optional values: // - default_service_config // - http_proxy_cfg @@ -187,72 +168,18 @@ pub struct ChannelBuilder { // - idle_timeout // - enable_channelz // - keepalive_cfg - channel_authority: Option, // TODO(nathanielford) Revisit if this is subsumed by the SecurityOpts authority. } -// This is provided as a separate builder function to allow for the possibility -// of satisfying the credential/security configuration through different means -// in the future (via adding methods to this impl taking different args). -impl ChannelBuilder { - /// (Required) Adds channel credentials to the builder. - pub fn credentials( - self, - credentials: impl IntoCredentialConfig, - ) -> ChannelBuilder { - ChannelBuilder { - target: self.target, - credentials: PresentOpt(credentials.into_config()), - runtime: self.runtime, - channel_authority: self.channel_authority, - } - } -} - -impl ChannelBuilder { - /// (Required) Adds the runtime to the builder. If the Tokio runtime - /// feature is enabled, skipping this will cause the default Tokio runtime - /// to be used. - pub fn runtime(self, runtime: GrpcRuntime) -> ChannelBuilder { - ChannelBuilder { - target: self.target, - credentials: self.credentials, - runtime: PresentOpt(runtime), - channel_authority: self.channel_authority, - } - } -} - -impl ChannelBuilder { - /// Overrides the authority used for the channel. This will override both - /// any authority specified in the target or by the name resolver. - pub fn channel_authority(mut self, authority: impl Into) -> Self { - self.channel_authority = Some(authority.into()); - self - } -} - -/// If the Tokio runtime feature is enabled, the channel builder can be built -/// without explicitly providing a runtime, defaulting to the Tokio runtime. -/// This does not prevent a user from providing their own runtime if they wish, -/// and the builder will work as normal. -#[cfg(feature = "_runtime-tokio")] -impl ChannelBuilder { - /// Builds the channel with the provided configuration, using the default - /// Tokio runtime if no runtime was explicitly provided. - pub fn build(self) -> Channel { - self.runtime(default_runtime()).build() - } -} - -impl ChannelBuilder { +impl ChannelBuilder { /// Builds the channel with the provided configuration. /// # Example /// /// ``` + /// use std::sync::Arc; + /// use grpc::client::Channel; /// use grpc::credentials::LocalChannelCredentials; /// - /// let channel = Channel::builder("dns:///localhost:123") - /// .credentials(Arc::new(LocalChannelCredentials::new())) + /// let channel = Channel::builder("dns:///localhost:123", Arc::new(LocalChannelCredentials::new())) /// .build(); /// ``` pub fn build(self) -> Channel { @@ -274,7 +201,7 @@ impl ChannelBuilder { .channel_authority .unwrap_or_else(|| resolver_builder.default_authority(&target).to_owned()); let security_opts = SecurityOpts { - credentials: self.credentials.0, + credentials: self.credentials, authority: Authority::from_host_port_str(&authority), handshake_info: ClientHandshakeInfo::default(), }; @@ -283,11 +210,16 @@ impl ChannelBuilder { active_channel: Mutex::default(), target, security_opts, - runtime: self.runtime.0, + runtime: self.runtime, resolver_builder, }), } } + + pub fn channel_authority(mut self, authority: impl Into) -> Self { + self.channel_authority = Some(authority.into()); + self + } } struct PersistentChannel { diff --git a/grpc/src/client/interceptor.rs b/grpc/src/client/interceptor.rs index d058c2853..5224ccdd1 100644 --- a/grpc/src/client/interceptor.rs +++ b/grpc/src/client/interceptor.rs @@ -207,9 +207,9 @@ where /// use grpc::client::interceptor::InvokeExt; /// /// // Create a channel: -/// let channel = Channel::builder("dns:///localhost:123") -/// .credentials(Arc::new(LocalChannelCredentials::new())) +/// let channel = Channel::builder("dns:///localhost:123", Arc::new(LocalChannelCredentials::new())) /// .build(); +/// /// // Create an interceptor: /// let interceptor = ResponseValidator::new(true); /// @@ -251,8 +251,7 @@ pub trait InvokeExt: Invoke + Sized { /// use grpc::client::interceptor::InvokeOnceExt; /// /// // Create a channel: -/// let channel = Channel::builder("dns:///localhost:123") -/// .credentials(Arc::new(LocalChannelCredentials::new())) +/// let channel = Channel::builder("dns:///localhost:123", Arc::new(LocalChannelCredentials::new())) /// .build(); /// // Create an interceptor: /// let interceptor = ResponseValidator::new(true); diff --git a/grpc/src/client/mod.rs b/grpc/src/client/mod.rs index 60ae5716f..a1daef560 100644 --- a/grpc/src/client/mod.rs +++ b/grpc/src/client/mod.rs @@ -62,7 +62,6 @@ pub(crate) mod service_config; pub mod stream_util; pub use channel::Channel; -pub use channel::IntoCredentialConfig; pub(crate) mod load_balancing; pub(crate) mod name_resolution; diff --git a/grpc/src/client/transport/tonic/test.rs b/grpc/src/client/transport/tonic/test.rs index ea863dd89..bd17eeb27 100644 --- a/grpc/src/client/transport/tonic/test.rs +++ b/grpc/src/client/transport/tonic/test.rs @@ -262,9 +262,7 @@ async fn grpc_invoke_tonic_unary() { // Create the channel. let target = format!("dns:///{}", addr); - let channel = Channel::builder(&target) - .credentials(LocalChannelCredentials::new_arc()) - .build(); + let channel = Channel::builder(&target, LocalChannelCredentials::new_arc()).build(); let (_, resp, trailers) = perform_unary_echo(&channel, "hello interop").await; assert_eq!(resp.message, "hello interop"); @@ -292,9 +290,7 @@ mod unix_tests { async fn run_unix_test(bind_path: &PathBuf, target: &str) { let listener = UnixListener::bind(bind_path).unwrap(); - let channel = Channel::builder(target) - .credentials(LocalChannelCredentials::new_arc()) - .build(); + let channel = Channel::builder(target, LocalChannelCredentials::new_arc()).build(); let shutdown_notify = Arc::new(Notify::new()); let shutdown_notify_copy = shutdown_notify.clone(); @@ -467,9 +463,7 @@ async fn grpc_invoke_tonic_unary_tls() { let composite_creds = CompositeChannelCredentials::new(creds, call_creds); let target = format!("dns:///{}", addr); - let channel = Channel::builder(&target) - .credentials(Arc::new(composite_creds)) - .build(); + let channel = Channel::builder(&target, Arc::new(composite_creds)).build(); let (headers, resp, trilers) = perform_unary_echo(&channel, "hello interop tls").await; @@ -523,9 +517,7 @@ async fn grpc_invoke_failure_cases() { should_fail: None, }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::builder(&target) - .credentials(Arc::new(composite_creds)) - .build(); + let channel = Channel::builder(&target, Arc::new(composite_creds)).build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( @@ -546,9 +538,7 @@ async fn grpc_invoke_failure_cases() { )), }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::builder(&target) - .credentials(Arc::new(composite_creds)) - .build(); + let channel = Channel::builder(&target, Arc::new(composite_creds)).build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( @@ -577,9 +567,7 @@ async fn grpc_invoke_failure_cases() { )), }); let composite_creds = CompositeChannelCredentials::new(creds, call_creds); - let channel = Channel::builder(&target) - .credentials(Arc::new(composite_creds)) - .build(); + let channel = Channel::builder(&target, Arc::new(composite_creds)).build(); let trailers = perform_unary_echo_failure(&channel).await; assert_eq!( @@ -893,9 +881,11 @@ async fn connect_timeout_exceeded() { // Create the channel with SlowChannelCredentials (21s). // The default timeout is 20s. let target = format!("dns:///{}", addr); - let channel = Channel::builder(&target) - .credentials(SlowChannelCredentials::new_arc(Duration::from_secs(21))) - .build(); + let channel = Channel::builder( + &target, + SlowChannelCredentials::new_arc(Duration::from_secs(21)), + ) + .build(); // Spawn the RPC call because it will block waiting for connection. let rpc_handle = tokio::spawn(async move { perform_unary_echo_failure(&channel).await }); @@ -947,9 +937,7 @@ async fn trailers_only_metadata() { }); let target = format!("dns:///{}", addr); - let channel = Channel::builder(&target) - .credentials(LocalChannelCredentials::new_arc()) - .build(); + let channel = Channel::builder(&target, LocalChannelCredentials::new_arc()).build(); let trailers = perform_unary_echo_failure(&channel).await; diff --git a/interop/src/bin/client.rs b/interop/src/bin/client.rs index d010a819a..687308a9b 100644 --- a/interop/src/bin/client.rs +++ b/interop/src/bin/client.rs @@ -98,14 +98,15 @@ async fn main() -> Result<(), Box> { GrpcClientTlsConfig::new() .with_root_certificates_provider(StaticProvider::new(root_certs)), )?; - grpc::client::Channel::builder("dns:///localhost:10000") - .credentials(Arc::new(creds)) + grpc::client::Channel::builder("dns:///localhost:10000", Arc::new(creds)) .channel_authority("test.test.google.fr") .build() } else { - grpc::client::Channel::builder("dns:///localhost:10000") - .credentials(Arc::new(LocalChannelCredentials::new())) - .build() + grpc::client::Channel::builder( + "dns:///localhost:10000", + Arc::new(LocalChannelCredentials::new()), + ) + .build() }; ( Box::new(client_protobuf::TestClient::new(channel.clone())),