use std::fmt; use std::path::PathBuf; use std::time::Duration; use crate::auth::ApiKey; const DEFAULT_MAX_GRPC_MESSAGE_BYTES: usize = 16 * 1024 * 1024; #[derive(Clone)] pub struct ClientOptions { endpoint: String, api_key: Option, plaintext: bool, ca_file: Option, server_name_override: Option, connect_timeout: Duration, call_timeout: Duration, stream_timeout: Option, max_grpc_message_bytes: usize, } impl ClientOptions { pub fn new(endpoint: impl Into) -> Self { Self { endpoint: endpoint.into(), api_key: None, plaintext: true, ca_file: None, server_name_override: None, connect_timeout: Duration::from_secs(10), call_timeout: Duration::from_secs(30), stream_timeout: None, max_grpc_message_bytes: DEFAULT_MAX_GRPC_MESSAGE_BYTES, } } pub fn with_api_key(mut self, api_key: ApiKey) -> Self { self.api_key = Some(api_key); self } pub fn with_plaintext(mut self, plaintext: bool) -> Self { self.plaintext = plaintext; self } pub fn with_ca_file(mut self, ca_file: impl Into) -> Self { self.ca_file = Some(ca_file.into()); self } pub fn with_server_name_override(mut self, server_name_override: impl Into) -> Self { self.server_name_override = Some(server_name_override.into()); self } pub fn with_connect_timeout(mut self, connect_timeout: Duration) -> Self { self.connect_timeout = connect_timeout; self } pub fn with_call_timeout(mut self, call_timeout: Duration) -> Self { self.call_timeout = call_timeout; self } pub fn with_stream_timeout(mut self, stream_timeout: Duration) -> Self { self.stream_timeout = Some(stream_timeout); self } pub fn with_max_grpc_message_bytes(mut self, max_grpc_message_bytes: usize) -> Self { self.max_grpc_message_bytes = max_grpc_message_bytes; self } pub fn endpoint(&self) -> &str { &self.endpoint } pub fn api_key(&self) -> Option<&ApiKey> { self.api_key.as_ref() } pub fn plaintext(&self) -> bool { self.plaintext } pub fn ca_file(&self) -> Option<&PathBuf> { self.ca_file.as_ref() } pub fn server_name_override(&self) -> Option<&str> { self.server_name_override.as_deref() } pub fn connect_timeout(&self) -> Duration { self.connect_timeout } pub fn call_timeout(&self) -> Duration { self.call_timeout } pub fn stream_timeout(&self) -> Option { self.stream_timeout } pub fn max_grpc_message_bytes(&self) -> usize { self.max_grpc_message_bytes } } impl Default for ClientOptions { fn default() -> Self { Self::new("http://127.0.0.1:5000") } } impl fmt::Debug for ClientOptions { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter .debug_struct("ClientOptions") .field("endpoint", &self.endpoint) .field("api_key", &self.api_key.as_ref().map(|_| "")) .field("plaintext", &self.plaintext) .field("ca_file", &self.ca_file) .field("server_name_override", &self.server_name_override) .field("connect_timeout", &self.connect_timeout) .field("call_timeout", &self.call_timeout) .field("stream_timeout", &self.stream_timeout) .field("max_grpc_message_bytes", &self.max_grpc_message_bytes) .finish() } } #[cfg(test)] mod tests { use super::ClientOptions; use crate::auth::ApiKey; #[test] fn debug_redacts_api_key() { let options = ClientOptions::new("http://localhost:5000").with_api_key(ApiKey::new("mxgw_secret")); let debug = format!("{options:?}"); assert!(debug.contains("")); assert!(!debug.contains("mxgw_secret")); } }