1use crate::caller::{CallOptions, ClientCaller, ClientCallerBuilder};
4#[cfg(feature = "raw-channel")]
5use crate::channel::Channel;
6use crate::error::{Error, Result};
7use crate::intercept::{InterceptedChannel, Interceptor};
8#[cfg(feature = "tls-openssl")]
9use crate::openssl_tls::{OpenSslClientConfig, OpenSslConnector};
10use crate::rpc::auth::Permission;
11use crate::rpc::auth::RawAuthClient;
12use crate::rpc::auth::{AuthClient, AuthDisableResponse, AuthEnableResponse};
13use crate::rpc::auth::{
14 RoleAddResponse, RoleDeleteResponse, RoleGetResponse, RoleGrantPermissionResponse,
15 RoleListResponse, RoleRevokePermissionOptions, RoleRevokePermissionResponse, UserAddOptions,
16 UserAddResponse, UserChangePasswordResponse, UserDeleteResponse, UserGetResponse,
17 UserGrantRoleResponse, UserListResponse, UserRevokeRoleResponse,
18};
19use crate::rpc::cluster::{
20 ClusterClient, MemberAddOptions, MemberAddResponse, MemberListResponse, MemberPromoteResponse,
21 MemberRemoveResponse, MemberUpdateResponse,
22};
23use crate::rpc::election::{
24 CampaignResponse, ElectionClient, LeaderResponse, ObserveStream, ProclaimOptions,
25 ProclaimResponse, ResignOptions, ResignResponse,
26};
27use crate::rpc::kv::{
28 CompactionOptions, CompactionResponse, DeleteOptions, DeleteResponse, GetOptions, GetResponse,
29 KvClient, PutOptions, PutResponse, Txn, TxnResponse,
30};
31use crate::rpc::lease::{
32 LeaseClient, LeaseGrantOptions, LeaseGrantResponse, LeaseKeepAliveStream, LeaseKeeper,
33 LeaseLeasesResponse, LeaseRevokeResponse, LeaseTimeToLiveOptions, LeaseTimeToLiveResponse,
34};
35use crate::rpc::lock::{LockClient, LockOptions, LockResponse, UnlockResponse};
36use crate::rpc::maintenance::{
37 AlarmAction, AlarmOptions, AlarmResponse, AlarmType, DefragmentResponse, HashKvResponse,
38 HashResponse, MaintenanceClient, MoveLeaderResponse, SnapshotStreaming, StatusResponse,
39};
40use crate::rpc::watch::{WatchClient, WatchOptions, WatchStream};
41#[cfg(feature = "tls-openssl")]
42use crate::OpenSslResult;
43#[cfg(feature = "_tls")]
44use crate::TlsOptions;
45use http::uri::Uri;
46use tonic::metadata::{Ascii, MetadataValue};
47
48use std::str::FromStr;
49use std::sync::{Arc, RwLock};
50use std::time::Duration;
51use tokio::sync::mpsc::Sender;
52
53use tonic::transport::{channel::Change, Endpoint};
54
55const HTTP_PREFIX: &str = "http://";
56const HTTPS_PREFIX: &str = "https://";
57
58pub(crate) type AuthToken = Arc<RwLock<Option<MetadataValue<Ascii>>>>;
59
60#[derive(Clone)]
62pub struct Client {
63 kv: KvClient,
64 watch: WatchClient,
65 lease: LeaseClient,
66 lock: LockClient,
67 auth: AuthClient,
68 maintenance: MaintenanceClient,
69 cluster: ClusterClient,
70 election: ElectionClient,
71 options: ConnectOptions,
74 tx: Option<Sender<Change<Uri, Endpoint>>>,
75 client_caller: ClientCaller<()>,
76}
77
78impl Client {
79 pub async fn connect<E: AsRef<str>, S: AsRef<[E]>>(
81 endpoints: S,
82 options: Option<ConnectOptions>,
83 ) -> Result<Self> {
84 #[cfg(not(feature = "tls-openssl"))]
85 let make_balanced_channel = crate::channel::Tonic;
86 #[cfg(feature = "tls-openssl")]
87 let make_balanced_channel = crate::channel::Openssl {
88 conn: options
89 .clone()
90 .and_then(|o| o.otls)
91 .unwrap_or_else(OpenSslConnector::create_default)?,
92 };
93 Self::connect_with_balanced_channel(endpoints, options, make_balanced_channel).await
94 }
95
96 pub async fn connect_with_balanced_channel<E: AsRef<str>, S: AsRef<[E]>, MBC>(
98 endpoints: S,
99 options: Option<ConnectOptions>,
100 make_balanced_channel: MBC,
101 ) -> Result<Self>
102 where
103 MBC: crate::channel::BalancedChannelBuilder,
104 crate::error::Error: From<MBC::Error>,
105 {
106 let options = options.unwrap_or_default();
107 let endpoints = {
108 let mut eps = Vec::new();
109 for e in endpoints.as_ref() {
110 let channel = Self::build_endpoint(e.as_ref(), &options)?;
111 eps.push(channel);
112 }
113 eps
114 };
115
116 if endpoints.is_empty() {
117 return Err(Error::InvalidArgs(String::from("empty endpoints")));
118 }
119
120 let auth_token = Arc::new(RwLock::new(None));
121
122 let (channel, tx) = make_balanced_channel.balanced_channel(64)?;
124 let channel = InterceptedChannel::new(
125 channel,
126 Interceptor {
127 require_leader: options.require_leader,
128 auth_token: auth_token.clone(),
129 },
130 );
131 for endpoint in endpoints {
132 tx.send(Change::Insert(endpoint.uri().clone(), endpoint))
135 .await
136 .map_err(|_| {
137 Error::Internal("failed to insert endpoint into the balanced channel".into())
138 })?;
139 }
140
141 let client = Self::build_client(channel, Some(tx), auth_token, options);
142 client.refresh_token().await?;
143 Ok(client)
144 }
145
146 #[cfg(feature = "raw-channel")]
147 pub async fn from_channel(channel: Channel, options: Option<ConnectOptions>) -> Result<Self> {
149 let options = options.unwrap_or_default();
150 let auth_token = Arc::new(RwLock::new(None));
151 let channel = InterceptedChannel::new(
152 channel,
153 Interceptor {
154 require_leader: options.require_leader,
155 auth_token: auth_token.clone(),
156 },
157 );
158
159 let client = Self::build_client(channel, None, auth_token, options);
160 client.refresh_token().await?;
161 Ok(client)
162 }
163
164 fn build_endpoint(url: &str, options: &ConnectOptions) -> Result<Endpoint> {
165 use tonic::transport::Channel as TonicChannel;
166 let mut endpoint = if url.starts_with(HTTP_PREFIX) {
167 #[cfg(feature = "_tls")]
168 if options.tls.is_some() {
169 return Err(Error::InvalidArgs(String::from(
170 "TLS options are only supported with HTTPS URLs",
171 )));
172 }
173
174 TonicChannel::builder(url.parse()?)
175 } else if url.starts_with(HTTPS_PREFIX) {
176 #[cfg(not(any(feature = "_tls", feature = "tls-openssl")))]
177 return Err(Error::InvalidArgs(String::from(
178 "HTTPS URLs are only supported with one of the features \"tls\", \"tls-ring\" or \"tls-aws-lc\"",
179 )));
180
181 #[cfg(all(feature = "tls-openssl", not(feature = "_tls")))]
182 {
183 TonicChannel::builder(url.parse()?)
184 }
185
186 #[cfg(feature = "_tls")]
187 {
188 let tls = options.tls.clone().unwrap_or_default();
189 TonicChannel::builder(url.parse()?).tls_config(tls)?
190 }
191 } else {
192 #[cfg(feature = "_tls")]
193 {
194 let tls = options.tls.clone();
195
196 match tls {
197 Some(tls) => {
198 let e = HTTPS_PREFIX.to_owned() + url;
199 TonicChannel::builder(e.parse()?).tls_config(tls)?
200 }
201 None => {
202 let e = HTTP_PREFIX.to_owned() + url;
203 TonicChannel::builder(e.parse()?)
204 }
205 }
206 }
207
208 #[cfg(all(feature = "tls-openssl", not(feature = "_tls")))]
209 {
210 let pfx = if options.otls.as_ref().is_some() {
211 HTTPS_PREFIX
212 } else {
213 HTTP_PREFIX
214 };
215 let e = pfx.to_owned() + url;
216 TonicChannel::builder(e.parse()?)
217 }
218
219 #[cfg(all(not(feature = "_tls"), not(feature = "tls-openssl")))]
220 {
221 let e = HTTP_PREFIX.to_owned() + url;
222 TonicChannel::builder(e.parse()?)
223 }
224 };
225
226 if let Some((interval, timeout)) = options.keep_alive {
227 endpoint = endpoint
228 .keep_alive_while_idle(options.keep_alive_while_idle)
229 .http2_keep_alive_interval(interval)
230 .keep_alive_timeout(timeout);
231 }
232
233 if let Some(timeout) = options.timeout {
234 endpoint = endpoint.timeout(timeout);
235 }
236
237 if let Some(timeout) = options.connect_timeout {
238 endpoint = endpoint.connect_timeout(timeout);
239 }
240
241 if let Some(tcp_keepalive) = options.tcp_keepalive {
242 endpoint = endpoint.tcp_keepalive(Some(tcp_keepalive));
243 }
244
245 Ok(endpoint)
246 }
247
248 fn build_client(
249 channel: InterceptedChannel,
250 tx: Option<Sender<Change<Uri, Endpoint>>>,
251 auth_token: Arc<RwLock<Option<MetadataValue<Ascii>>>>,
252 options: ConnectOptions,
253 ) -> Self {
254 let builder = ClientCallerBuilder::new(
255 (&options).into(),
256 auth_token,
257 RawAuthClient::new(channel.clone()),
258 channel,
259 );
260
261 let auth = AuthClient::new(builder.clone());
262 let kv = KvClient::new(builder.clone());
263 let watch = WatchClient::new(builder.clone());
264 let lease = LeaseClient::new(builder.clone());
265 let lock = LockClient::new(builder.clone());
266 let cluster = ClusterClient::new(builder.clone());
267 let maintenance = MaintenanceClient::new(builder.clone());
268 let election = ElectionClient::new(builder.clone());
269
270 Self {
271 kv,
272 watch,
273 lease,
274 lock,
275 auth,
276 maintenance,
277 cluster,
278 election,
279 options,
280 tx,
281 client_caller: builder.build(|_| ()),
282 }
283 }
284
285 #[inline]
296 pub async fn add_endpoint<E: AsRef<str>>(&self, endpoint: E) -> Result<()> {
297 let endpoint = Self::build_endpoint(endpoint.as_ref(), &self.options)?;
298 let Some(tx) = &self.tx else {
299 return Err(Error::EndpointsNotManaged);
300 };
301 tx.send(Change::Insert(endpoint.uri().clone(), endpoint))
302 .await
303 .map_err(|e| Error::EndpointError(format!("failed to add endpoint because of {e}")))
304 }
305
306 #[inline]
312 pub async fn remove_endpoint<E: AsRef<str>>(&self, endpoint: E) -> Result<()> {
313 let uri = http::Uri::from_str(endpoint.as_ref())?;
314 let Some(tx) = &self.tx else {
315 return Err(Error::EndpointsNotManaged);
316 };
317 tx.send(Change::Remove(uri))
318 .await
319 .map_err(|e| Error::EndpointError(format!("failed to remove endpoint because of {e}")))
320 }
321
322 #[inline]
324 pub fn kv_client(&self) -> KvClient {
325 self.kv.clone()
326 }
327
328 #[inline]
330 pub fn watch_client(&self) -> WatchClient {
331 self.watch.clone()
332 }
333
334 #[inline]
336 pub fn lease_client(&self) -> LeaseClient {
337 self.lease.clone()
338 }
339
340 #[inline]
342 pub fn auth_client(&self) -> AuthClient {
343 self.auth.clone()
344 }
345
346 #[inline]
348 pub fn maintenance_client(&self) -> MaintenanceClient {
349 self.maintenance.clone()
350 }
351
352 #[inline]
354 pub fn cluster_client(&self) -> ClusterClient {
355 self.cluster.clone()
356 }
357
358 #[inline]
360 pub fn lock_client(&self) -> LockClient {
361 self.lock.clone()
362 }
363
364 #[inline]
366 pub fn election_client(&self) -> ElectionClient {
367 self.election.clone()
368 }
369
370 #[inline]
374 pub async fn put(
375 &mut self,
376 key: impl Into<Vec<u8>>,
377 value: impl Into<Vec<u8>>,
378 options: Option<PutOptions>,
379 ) -> Result<PutResponse> {
380 self.kv.put(key, value, options).await
381 }
382
383 #[inline]
385 pub async fn get(
386 &mut self,
387 key: impl Into<Vec<u8>>,
388 options: Option<GetOptions>,
389 ) -> Result<GetResponse> {
390 self.kv.get(key, options).await
391 }
392
393 #[inline]
395 pub async fn delete(
396 &mut self,
397 key: impl Into<Vec<u8>>,
398 options: Option<DeleteOptions>,
399 ) -> Result<DeleteResponse> {
400 self.kv.delete(key, options).await
401 }
402
403 #[inline]
407 pub async fn compact(
408 &mut self,
409 revision: i64,
410 options: Option<CompactionOptions>,
411 ) -> Result<CompactionResponse> {
412 self.kv.compact(revision, options).await
413 }
414
415 #[inline]
420 pub async fn txn(&mut self, txn: Txn) -> Result<TxnResponse> {
421 self.kv.txn(txn).await
422 }
423
424 #[inline]
429 pub async fn watch(
430 &mut self,
431 key: impl Into<Vec<u8>>,
432 options: Option<WatchOptions>,
433 ) -> Result<WatchStream> {
434 self.watch.watch(key, options).await
435 }
436
437 #[inline]
441 pub async fn lease_grant(
442 &mut self,
443 ttl: i64,
444 options: Option<LeaseGrantOptions>,
445 ) -> Result<LeaseGrantResponse> {
446 self.lease.grant(ttl, options).await
447 }
448
449 #[inline]
451 pub async fn lease_revoke(&mut self, id: i64) -> Result<LeaseRevokeResponse> {
452 self.lease.revoke(id).await
453 }
454
455 #[inline]
458 pub async fn lease_keep_alive(
459 &mut self,
460 id: i64,
461 ) -> Result<(LeaseKeeper, LeaseKeepAliveStream)> {
462 self.lease.keep_alive(id).await
463 }
464
465 #[inline]
467 pub async fn lease_time_to_live(
468 &mut self,
469 id: i64,
470 options: Option<LeaseTimeToLiveOptions>,
471 ) -> Result<LeaseTimeToLiveResponse> {
472 self.lease.time_to_live(id, options).await
473 }
474
475 #[inline]
477 pub async fn leases(&mut self) -> Result<LeaseLeasesResponse> {
478 self.lease.leases().await
479 }
480
481 #[inline]
488 pub async fn lock(
489 &mut self,
490 name: impl Into<Vec<u8>>,
491 options: Option<LockOptions>,
492 ) -> Result<LockResponse> {
493 self.lock.lock(name, options).await
494 }
495
496 #[inline]
500 pub async fn unlock(&mut self, key: impl Into<Vec<u8>>) -> Result<UnlockResponse> {
501 self.lock.unlock(key).await
502 }
503
504 #[inline]
506 pub async fn auth_enable(&mut self) -> Result<AuthEnableResponse> {
507 self.auth.auth_enable().await
508 }
509
510 #[inline]
512 pub async fn auth_disable(&mut self) -> Result<AuthDisableResponse> {
513 self.auth.auth_disable().await
514 }
515
516 #[inline]
518 pub async fn role_add(&mut self, name: impl Into<String>) -> Result<RoleAddResponse> {
519 self.auth.role_add(name).await
520 }
521
522 #[inline]
524 pub async fn role_delete(&mut self, name: impl Into<String>) -> Result<RoleDeleteResponse> {
525 self.auth.role_delete(name).await
526 }
527
528 #[inline]
530 pub async fn role_get(&mut self, name: impl Into<String>) -> Result<RoleGetResponse> {
531 self.auth.role_get(name).await
532 }
533
534 #[inline]
536 pub async fn role_list(&mut self) -> Result<RoleListResponse> {
537 self.auth.role_list().await
538 }
539
540 #[inline]
542 pub async fn role_grant_permission(
543 &mut self,
544 name: impl Into<String>,
545 perm: Permission,
546 ) -> Result<RoleGrantPermissionResponse> {
547 self.auth.role_grant_permission(name, perm).await
548 }
549
550 #[inline]
552 pub async fn role_revoke_permission(
553 &mut self,
554 name: impl Into<String>,
555 key: impl Into<Vec<u8>>,
556 options: Option<RoleRevokePermissionOptions>,
557 ) -> Result<RoleRevokePermissionResponse> {
558 self.auth.role_revoke_permission(name, key, options).await
559 }
560
561 #[inline]
563 pub async fn user_add(
564 &mut self,
565 name: impl Into<String>,
566 password: impl Into<String>,
567 options: Option<UserAddOptions>,
568 ) -> Result<UserAddResponse> {
569 self.auth.user_add(name, password, options).await
570 }
571
572 #[inline]
574 pub async fn user_get(&mut self, name: impl Into<String>) -> Result<UserGetResponse> {
575 self.auth.user_get(name).await
576 }
577
578 #[inline]
580 pub async fn user_list(&mut self) -> Result<UserListResponse> {
581 self.auth.user_list().await
582 }
583
584 #[inline]
586 pub async fn user_delete(&mut self, name: impl Into<String>) -> Result<UserDeleteResponse> {
587 self.auth.user_delete(name).await
588 }
589
590 #[inline]
592 pub async fn user_change_password(
593 &mut self,
594 name: impl Into<String>,
595 password: impl Into<String>,
596 ) -> Result<UserChangePasswordResponse> {
597 self.auth.user_change_password(name, password).await
598 }
599
600 #[inline]
602 pub async fn user_grant_role(
603 &mut self,
604 user: impl Into<String>,
605 role: impl Into<String>,
606 ) -> Result<UserGrantRoleResponse> {
607 self.auth.user_grant_role(user, role).await
608 }
609
610 #[inline]
612 pub async fn user_revoke_role(
613 &mut self,
614 user: impl Into<String>,
615 role: impl Into<String>,
616 ) -> Result<UserRevokeRoleResponse> {
617 self.auth.user_revoke_role(user, role).await
618 }
619
620 #[inline]
622 pub async fn alarm(
623 &mut self,
624 alarm_action: AlarmAction,
625 alarm_type: AlarmType,
626 options: Option<AlarmOptions>,
627 ) -> Result<AlarmResponse> {
628 self.maintenance
629 .alarm(alarm_action, alarm_type, options)
630 .await
631 }
632
633 #[inline]
635 pub async fn status(&mut self) -> Result<StatusResponse> {
636 self.maintenance.status().await
637 }
638
639 #[inline]
641 pub async fn defragment(&mut self) -> Result<DefragmentResponse> {
642 self.maintenance.defragment().await
643 }
644
645 #[inline]
649 pub async fn hash(&mut self) -> Result<HashResponse> {
650 self.maintenance.hash().await
651 }
652
653 #[inline]
656 pub async fn hash_kv(&mut self, revision: i64) -> Result<HashKvResponse> {
657 self.maintenance.hash_kv(revision).await
658 }
659
660 #[inline]
662 pub async fn snapshot(&mut self) -> Result<SnapshotStreaming> {
663 self.maintenance.snapshot().await
664 }
665
666 #[inline]
668 pub async fn member_add<E: AsRef<str>, S: AsRef<[E]>>(
669 &mut self,
670 urls: S,
671 options: Option<MemberAddOptions>,
672 ) -> Result<MemberAddResponse> {
673 let mut eps = Vec::new();
674 for e in urls.as_ref() {
675 let e = e.as_ref();
676 let url = if e.starts_with(HTTP_PREFIX) || e.starts_with(HTTPS_PREFIX) {
677 e.to_string()
678 } else {
679 HTTP_PREFIX.to_owned() + e
680 };
681 eps.push(url);
682 }
683
684 self.cluster.member_add(eps, options).await
685 }
686
687 #[inline]
689 pub async fn member_remove(&mut self, id: u64) -> Result<MemberRemoveResponse> {
690 self.cluster.member_remove(id).await
691 }
692
693 #[inline]
695 pub async fn member_update(
696 &mut self,
697 id: u64,
698 url: impl Into<Vec<String>>,
699 ) -> Result<MemberUpdateResponse> {
700 self.cluster.member_update(id, url).await
701 }
702
703 #[inline]
705 pub async fn member_promote(&mut self, id: u64) -> Result<MemberPromoteResponse> {
706 self.cluster.member_promote(id).await
707 }
708
709 #[inline]
711 pub async fn member_list(&mut self) -> Result<MemberListResponse> {
712 self.cluster.member_list().await
713 }
714
715 #[inline]
717 pub async fn move_leader(&mut self, target_id: u64) -> Result<MoveLeaderResponse> {
718 self.maintenance.move_leader(target_id).await
719 }
720
721 #[inline]
725 pub async fn campaign(
726 &mut self,
727 name: impl Into<Vec<u8>>,
728 value: impl Into<Vec<u8>>,
729 lease: i64,
730 ) -> Result<CampaignResponse> {
731 self.election.campaign(name, value, lease).await
732 }
733
734 #[inline]
736 pub async fn proclaim(
737 &mut self,
738 value: impl Into<Vec<u8>>,
739 options: Option<ProclaimOptions>,
740 ) -> Result<ProclaimResponse> {
741 self.election.proclaim(value, options).await
742 }
743
744 #[inline]
746 pub async fn leader(&mut self, name: impl Into<Vec<u8>>) -> Result<LeaderResponse> {
747 self.election.leader(name).await
748 }
749
750 #[inline]
753 pub async fn observe(&mut self, name: impl Into<Vec<u8>>) -> Result<ObserveStream> {
754 self.election.observe(name).await
755 }
756
757 #[inline]
759 pub async fn resign(&mut self, option: Option<ResignOptions>) -> Result<ResignResponse> {
760 self.election.resign(option).await
761 }
762
763 pub async fn refresh_token(&self) -> Result<()> {
765 self.client_caller.refresh_token().await
766 }
767
768 pub async fn update_user(&mut self, user: Option<(String, String)>) -> Result<()> {
776 self.client_caller.update_user(user).await
777 }
778}
779
780#[derive(Debug, Default, Clone)]
782pub struct ConnectOptions {
783 user: Option<(String, String)>,
785 keep_alive: Option<(Duration, Duration)>,
787 keep_alive_while_idle: bool,
789 timeout: Option<Duration>,
791 connect_timeout: Option<Duration>,
793 tcp_keepalive: Option<Duration>,
795 #[cfg(feature = "_tls")]
796 tls: Option<TlsOptions>,
797 #[cfg(feature = "tls-openssl")]
798 otls: Option<OpenSslResult<OpenSslConnector>>,
799 require_leader: bool,
801 refresh_expired_token: bool,
803}
804
805impl ConnectOptions {
806 #[inline]
808 pub fn with_user(mut self, name: impl Into<String>, password: impl Into<String>) -> Self {
809 self.user = Some((name.into(), password.into()));
810 self
811 }
812
813 #[cfg_attr(docsrs, doc(cfg(any(feature = "tls-ring", feature = "tls-aws-lc"))))]
817 #[cfg(feature = "_tls")]
818 #[inline]
819 pub fn with_tls(mut self, tls: TlsOptions) -> Self {
820 self.tls = Some(tls);
821 self
822 }
823
824 #[cfg_attr(docsrs, doc(cfg(feature = "tls-openssl")))]
826 #[cfg(feature = "tls-openssl")]
827 #[inline]
828 pub fn with_openssl_tls(mut self, otls: OpenSslClientConfig) -> Self {
829 self.otls = Some(otls.build());
834 self
835 }
836
837 #[inline]
839 pub fn with_keep_alive(mut self, interval: Duration, timeout: Duration) -> Self {
840 self.keep_alive = Some((interval, timeout));
841 self
842 }
843
844 #[inline]
846 pub fn with_timeout(mut self, timeout: Duration) -> Self {
847 self.timeout = Some(timeout);
848 self
849 }
850
851 #[inline]
853 pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
854 self.connect_timeout = Some(timeout);
855 self
856 }
857
858 #[inline]
860 pub fn with_tcp_keepalive(mut self, tcp_keepalive: Duration) -> Self {
861 self.tcp_keepalive = Some(tcp_keepalive);
862 self
863 }
864
865 #[inline]
871 pub fn with_keep_alive_while_idle(mut self, enabled: bool) -> Self {
872 self.keep_alive_while_idle = enabled;
873 self
874 }
875
876 #[inline]
878 pub fn with_require_leader(mut self, require_leader: bool) -> Self {
879 self.require_leader = require_leader;
880 self
881 }
882
883 pub fn with_auto_token_refresh(mut self, refresh_expired_token: bool) -> Self {
892 self.refresh_expired_token = refresh_expired_token;
893 self
894 }
895
896 #[inline]
898 pub const fn new() -> Self {
899 ConnectOptions {
900 user: None,
901 keep_alive: None,
902 keep_alive_while_idle: true,
903 timeout: None,
904 connect_timeout: None,
905 tcp_keepalive: None,
906 #[cfg(feature = "_tls")]
907 tls: None,
908 #[cfg(feature = "tls-openssl")]
909 otls: None,
910 require_leader: false,
911 refresh_expired_token: false,
912 }
913 }
914}
915
916impl From<&ConnectOptions> for CallOptions {
917 fn from(options: &ConnectOptions) -> Self {
918 Self {
919 creds: Arc::new(RwLock::new(options.user.clone())),
920 refresh_expired_token: options.refresh_expired_token,
921 refresh_lock: Default::default(),
922 }
923 }
924}