1use crate::caller::{ClientCaller, ClientCallerBuilder};
4use crate::error::Result;
5use crate::intercept::InterceptedChannel;
6use crate::rpc::pb::etcdserverpb::lease_client::LeaseClient as PbLeaseClient;
7use crate::rpc::pb::etcdserverpb::{
8 LeaseGrantRequest as PbLeaseGrantRequest, LeaseGrantResponse as PbLeaseGrantResponse,
9 LeaseKeepAliveRequest as PbLeaseKeepAliveRequest,
10 LeaseKeepAliveResponse as PbLeaseKeepAliveResponse, LeaseLeasesRequest as PbLeaseLeasesRequest,
11 LeaseLeasesResponse as PbLeaseLeasesResponse, LeaseRevokeRequest as PbLeaseRevokeRequest,
12 LeaseRevokeResponse as PbLeaseRevokeResponse, LeaseStatus as PbLeaseStatus,
13 LeaseTimeToLiveRequest as PbLeaseTimeToLiveRequest,
14 LeaseTimeToLiveResponse as PbLeaseTimeToLiveResponse,
15};
16use crate::rpc::ResponseHeader;
17use crate::vec::VecExt;
18use crate::Error;
19use std::pin::Pin;
20use std::task::{Context, Poll};
21use tokio::sync::mpsc::{channel, Sender};
22use tokio_stream::wrappers::ReceiverStream;
23use tokio_stream::Stream;
24use tonic::{IntoRequest, Request, Streaming};
25
26type Client = PbLeaseClient<InterceptedChannel>;
27
28#[repr(transparent)]
30#[derive(Clone)]
31pub struct LeaseClient {
32 inner: ClientCaller<Client>,
33}
34
35impl LeaseClient {
36 #[inline]
38 pub(crate) fn new(builder: ClientCallerBuilder) -> Self {
39 Self {
40 inner: builder.build(Client::new),
41 }
42 }
43
44 #[inline]
48 pub async fn grant(
49 &mut self,
50 ttl: i64,
51 options: Option<LeaseGrantOptions>,
52 ) -> Result<LeaseGrantResponse> {
53 async fn grant_impl(
54 client: &mut Client,
55 options: LeaseGrantOptions,
56 ) -> Result<LeaseGrantResponse> {
57 Ok(LeaseGrantResponse::new(
58 client.lease_grant(options).await?.into_inner(),
59 ))
60 }
61 self.inner
62 .do_call(options.unwrap_or_default().with_ttl(ttl), grant_impl)
63 .await
64 }
65
66 #[inline]
68 pub async fn revoke(&mut self, id: i64) -> Result<LeaseRevokeResponse> {
69 async fn revoke_impl(
70 client: &mut Client,
71 options: LeaseRevokeOptions,
72 ) -> Result<LeaseRevokeResponse> {
73 let resp = client.lease_revoke(options).await?.into_inner();
74 Ok(LeaseRevokeResponse::new(resp))
75 }
76
77 self.inner
78 .do_call(LeaseRevokeOptions::new().with_id(id), revoke_impl)
79 .await
80 }
81
82 #[inline]
85 pub async fn keep_alive(&mut self, id: i64) -> Result<(LeaseKeeper, LeaseKeepAliveStream)> {
86 async fn keep_alive_impl(
87 client: &mut Client,
88 options: PbLeaseKeepAliveRequest,
89 ) -> Result<(
90 Sender<PbLeaseKeepAliveRequest>,
91 Streaming<PbLeaseKeepAliveResponse>,
92 )> {
93 let (sender, receiver) = channel::<PbLeaseKeepAliveRequest>(100);
94 sender
95 .send(options)
96 .await
97 .map_err(|e| Error::LeaseKeepAliveError(e.to_string()))?;
98
99 let receiver = ReceiverStream::new(receiver);
100 let resp = client.lease_keep_alive(receiver).await?.into_inner();
101 Ok((sender, resp))
102 }
103
104 let (sender, mut stream) = self
105 .inner
106 .do_call(
107 LeaseKeepAliveOptions::new().with_id(id).into(),
108 keep_alive_impl,
109 )
110 .await?;
111
112 let id = match stream.message().await? {
113 Some(resp) => {
114 if resp.ttl <= 0 {
115 return Err(Error::LeaseKeepAliveError("lease not found".to_string()));
116 }
117 resp.id
118 }
119 None => {
120 return Err(Error::WatchError(
121 "failed to create lease keeper".to_string(),
122 ));
123 }
124 };
125
126 Ok((
127 LeaseKeeper::new(id, sender),
128 LeaseKeepAliveStream::new(stream),
129 ))
130 }
131
132 #[inline]
134 pub async fn time_to_live(
135 &mut self,
136 id: i64,
137 options: Option<LeaseTimeToLiveOptions>,
138 ) -> Result<LeaseTimeToLiveResponse> {
139 async fn time_to_live_impl(
140 client: &mut Client,
141 options: LeaseTimeToLiveOptions,
142 ) -> Result<LeaseTimeToLiveResponse> {
143 let resp = client.lease_time_to_live(options).await?.into_inner();
144 Ok(LeaseTimeToLiveResponse::new(resp))
145 }
146
147 self.inner
148 .do_call(options.unwrap_or_default().with_id(id), time_to_live_impl)
149 .await
150 }
151
152 #[inline]
154 pub async fn leases(&mut self) -> Result<LeaseLeasesResponse> {
155 async fn leases_impl(
156 client: &mut Client,
157 req: PbLeaseLeasesRequest,
158 ) -> Result<LeaseLeasesResponse> {
159 let resp = client.lease_leases(req).await?.into_inner();
160 Ok(LeaseLeasesResponse::new(resp))
161 }
162
163 self.inner
164 .do_call(PbLeaseLeasesRequest {}, leases_impl)
165 .await
166 }
167}
168
169#[derive(Debug, Default, Clone)]
171#[repr(transparent)]
172pub struct LeaseGrantOptions(PbLeaseGrantRequest);
173
174impl LeaseGrantOptions {
175 #[inline]
177 const fn with_ttl(mut self, ttl: i64) -> Self {
178 self.0.ttl = ttl;
179 self
180 }
181
182 #[inline]
184 pub const fn with_id(mut self, id: i64) -> Self {
185 self.0.id = id;
186 self
187 }
188
189 #[inline]
191 pub const fn new() -> Self {
192 Self(PbLeaseGrantRequest { ttl: 0, id: 0 })
193 }
194}
195
196impl From<LeaseGrantOptions> for PbLeaseGrantRequest {
197 #[inline]
198 fn from(options: LeaseGrantOptions) -> Self {
199 options.0
200 }
201}
202
203impl IntoRequest<PbLeaseGrantRequest> for LeaseGrantOptions {
204 #[inline]
205 fn into_request(self) -> Request<PbLeaseGrantRequest> {
206 Request::new(self.into())
207 }
208}
209
210#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
212#[derive(Debug, Clone)]
213#[repr(transparent)]
214pub struct LeaseGrantResponse(PbLeaseGrantResponse);
215
216impl LeaseGrantResponse {
217 #[inline]
219 const fn new(resp: PbLeaseGrantResponse) -> Self {
220 Self(resp)
221 }
222
223 #[inline]
225 pub fn header(&self) -> Option<&ResponseHeader> {
226 self.0.header.as_ref().map(From::from)
227 }
228
229 #[inline]
231 pub fn take_header(&mut self) -> Option<ResponseHeader> {
232 self.0.header.take().map(ResponseHeader::new)
233 }
234
235 #[inline]
237 pub const fn ttl(&self) -> i64 {
238 self.0.ttl
239 }
240
241 #[inline]
243 pub const fn id(&self) -> i64 {
244 self.0.id
245 }
246
247 #[inline]
249 pub fn error(&self) -> &str {
250 &self.0.error
251 }
252}
253
254#[derive(Debug, Default, Clone)]
256#[repr(transparent)]
257struct LeaseRevokeOptions(PbLeaseRevokeRequest);
258
259impl LeaseRevokeOptions {
260 #[inline]
262 fn with_id(mut self, id: i64) -> Self {
263 self.0.id = id;
264 self
265 }
266
267 #[inline]
269 pub const fn new() -> Self {
270 Self(PbLeaseRevokeRequest { id: 0 })
271 }
272}
273
274impl From<LeaseRevokeOptions> for PbLeaseRevokeRequest {
275 #[inline]
276 fn from(options: LeaseRevokeOptions) -> Self {
277 options.0
278 }
279}
280
281impl IntoRequest<PbLeaseRevokeRequest> for LeaseRevokeOptions {
282 #[inline]
283 fn into_request(self) -> Request<PbLeaseRevokeRequest> {
284 Request::new(self.into())
285 }
286}
287
288#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
290#[derive(Debug, Clone)]
291#[repr(transparent)]
292pub struct LeaseRevokeResponse(PbLeaseRevokeResponse);
293
294impl LeaseRevokeResponse {
295 #[inline]
297 const fn new(resp: PbLeaseRevokeResponse) -> Self {
298 Self(resp)
299 }
300
301 #[inline]
303 pub fn header(&self) -> Option<&ResponseHeader> {
304 self.0.header.as_ref().map(From::from)
305 }
306
307 #[inline]
309 pub fn take_header(&mut self) -> Option<ResponseHeader> {
310 self.0.header.take().map(ResponseHeader::new)
311 }
312}
313
314#[derive(Debug, Default, Clone)]
316#[repr(transparent)]
317struct LeaseKeepAliveOptions(PbLeaseKeepAliveRequest);
318
319impl LeaseKeepAliveOptions {
320 #[inline]
322 fn with_id(mut self, id: i64) -> Self {
323 self.0.id = id;
324 self
325 }
326
327 #[inline]
329 pub const fn new() -> Self {
330 Self(PbLeaseKeepAliveRequest { id: 0 })
331 }
332}
333
334impl From<LeaseKeepAliveOptions> for PbLeaseKeepAliveRequest {
335 #[inline]
336 fn from(options: LeaseKeepAliveOptions) -> Self {
337 options.0
338 }
339}
340
341impl IntoRequest<PbLeaseKeepAliveRequest> for LeaseKeepAliveOptions {
342 #[inline]
343 fn into_request(self) -> Request<PbLeaseKeepAliveRequest> {
344 Request::new(self.into())
345 }
346}
347
348#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
350#[derive(Debug, Clone)]
351#[repr(transparent)]
352pub struct LeaseKeepAliveResponse(PbLeaseKeepAliveResponse);
353
354impl LeaseKeepAliveResponse {
355 #[inline]
357 const fn new(resp: PbLeaseKeepAliveResponse) -> Self {
358 Self(resp)
359 }
360
361 #[inline]
363 pub fn header(&self) -> Option<&ResponseHeader> {
364 self.0.header.as_ref().map(From::from)
365 }
366
367 #[inline]
369 pub fn take_header(&mut self) -> Option<ResponseHeader> {
370 self.0.header.take().map(ResponseHeader::new)
371 }
372
373 #[inline]
375 pub const fn ttl(&self) -> i64 {
376 self.0.ttl
377 }
378
379 #[inline]
381 pub const fn id(&self) -> i64 {
382 self.0.id
383 }
384}
385
386#[derive(Debug, Default, Clone)]
388#[repr(transparent)]
389pub struct LeaseTimeToLiveOptions(PbLeaseTimeToLiveRequest);
390
391impl LeaseTimeToLiveOptions {
392 #[inline]
394 const fn with_id(mut self, id: i64) -> Self {
395 self.0.id = id;
396 self
397 }
398
399 #[inline]
401 pub const fn with_keys(mut self) -> Self {
402 self.0.keys = true;
403 self
404 }
405
406 #[inline]
408 pub const fn new() -> Self {
409 Self(PbLeaseTimeToLiveRequest { id: 0, keys: false })
410 }
411}
412
413impl From<LeaseTimeToLiveOptions> for PbLeaseTimeToLiveRequest {
414 #[inline]
415 fn from(options: LeaseTimeToLiveOptions) -> Self {
416 options.0
417 }
418}
419
420impl IntoRequest<PbLeaseTimeToLiveRequest> for LeaseTimeToLiveOptions {
421 #[inline]
422 fn into_request(self) -> Request<PbLeaseTimeToLiveRequest> {
423 Request::new(self.into())
424 }
425}
426
427#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
429#[derive(Debug, Clone)]
430#[repr(transparent)]
431pub struct LeaseTimeToLiveResponse(PbLeaseTimeToLiveResponse);
432
433impl LeaseTimeToLiveResponse {
434 #[inline]
436 const fn new(resp: PbLeaseTimeToLiveResponse) -> Self {
437 Self(resp)
438 }
439
440 #[inline]
442 pub fn header(&self) -> Option<&ResponseHeader> {
443 self.0.header.as_ref().map(From::from)
444 }
445
446 #[inline]
448 pub fn take_header(&mut self) -> Option<ResponseHeader> {
449 self.0.header.take().map(ResponseHeader::new)
450 }
451
452 #[inline]
454 pub const fn ttl(&self) -> i64 {
455 self.0.ttl
456 }
457
458 #[inline]
460 pub const fn id(&self) -> i64 {
461 self.0.id
462 }
463
464 #[inline]
466 pub const fn granted_ttl(&self) -> i64 {
467 self.0.granted_ttl
468 }
469
470 #[inline]
472 pub fn keys(&self) -> &[Vec<u8>] {
473 &self.0.keys
474 }
475
476 #[inline]
477 pub(crate) fn strip_keys_prefix(&mut self, prefix: &[u8]) {
478 self.0.keys.iter_mut().for_each(|key| {
479 key.strip_key_prefix(prefix);
480 });
481 }
482}
483
484#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
486#[derive(Debug, Clone)]
487#[repr(transparent)]
488pub struct LeaseLeasesResponse(PbLeaseLeasesResponse);
489
490impl LeaseLeasesResponse {
491 #[inline]
493 const fn new(resp: PbLeaseLeasesResponse) -> Self {
494 Self(resp)
495 }
496
497 #[inline]
499 pub fn header(&self) -> Option<&ResponseHeader> {
500 self.0.header.as_ref().map(From::from)
501 }
502
503 #[inline]
505 pub fn take_header(&mut self) -> Option<ResponseHeader> {
506 self.0.header.take().map(ResponseHeader::new)
507 }
508
509 #[inline]
511 pub fn leases(&self) -> &[LeaseStatus] {
512 unsafe { &*(self.0.leases.as_slice() as *const _ as *const [LeaseStatus]) }
513 }
514}
515
516#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
518#[derive(Debug, Clone, PartialEq)]
519#[repr(transparent)]
520pub struct LeaseStatus(PbLeaseStatus);
521
522impl LeaseStatus {
523 #[inline]
525 pub const fn id(&self) -> i64 {
526 self.0.id
527 }
528}
529
530impl From<&PbLeaseStatus> for &LeaseStatus {
531 #[inline]
532 fn from(src: &PbLeaseStatus) -> Self {
533 unsafe { &*(src as *const _ as *const LeaseStatus) }
534 }
535}
536
537#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
539#[derive(Debug)]
540pub struct LeaseKeeper {
541 id: i64,
542 sender: Sender<PbLeaseKeepAliveRequest>,
543}
544
545impl LeaseKeeper {
546 #[inline]
548 const fn new(id: i64, sender: Sender<PbLeaseKeepAliveRequest>) -> Self {
549 Self { id, sender }
550 }
551
552 #[inline]
554 pub const fn id(&self) -> i64 {
555 self.id
556 }
557
558 #[inline]
560 pub async fn keep_alive(&mut self) -> Result<()> {
561 self.sender
562 .send(LeaseKeepAliveOptions::new().with_id(self.id).into())
563 .await
564 .map_err(|e| Error::LeaseKeepAliveError(e.to_string()))
565 }
566}
567
568#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
570#[derive(Debug)]
571pub struct LeaseKeepAliveStream {
572 stream: Streaming<PbLeaseKeepAliveResponse>,
573}
574
575impl LeaseKeepAliveStream {
576 #[inline]
578 const fn new(stream: Streaming<PbLeaseKeepAliveResponse>) -> Self {
579 Self { stream }
580 }
581
582 #[inline]
584 pub async fn message(&mut self) -> Result<Option<LeaseKeepAliveResponse>> {
585 match self.stream.message().await? {
586 Some(resp) => Ok(Some(LeaseKeepAliveResponse::new(resp))),
587 None => Ok(None),
588 }
589 }
590}
591
592impl Stream for LeaseKeepAliveStream {
593 type Item = Result<LeaseKeepAliveResponse>;
594
595 #[inline]
596 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
597 Pin::new(&mut self.get_mut().stream)
598 .poll_next(cx)
599 .map(|t| match t {
600 Some(Ok(resp)) => Some(Ok(LeaseKeepAliveResponse::new(resp))),
601 Some(Err(e)) => Some(Err(From::from(e))),
602 None => None,
603 })
604 }
605}