1use crate::caller::{ClientCaller, ClientCallerBuilder};
4pub use crate::rpc::pb::etcdserverpb::alarm_request::AlarmAction;
5pub use crate::rpc::pb::etcdserverpb::downgrade_request::DowngradeAction;
6pub use crate::rpc::pb::etcdserverpb::AlarmType;
7
8use super::pb::etcdserverpb;
9use crate::error::Result;
10use crate::intercept::InterceptedChannel;
11use crate::rpc::pb::etcdserverpb::{
12 AlarmRequest as PbAlarmRequest, AlarmResponse as PbAlarmResponse,
13 DefragmentRequest as PbDefragmentRequest, DefragmentResponse as PbDefragmentResponse,
14 DowngradeInfo as PbDowngradeInfo, DowngradeRequest as PbDowngradeRequest,
15 DowngradeResponse as PbDowngradeResponse, HashKvRequest as PbHashKvRequest,
16 HashKvResponse as PbHashKvResponse, HashRequest as PbHashRequest,
17 HashResponse as PbHashResponse, MoveLeaderRequest as PbMoveLeaderRequest,
18 MoveLeaderResponse as PbMoveLeaderResponse, SnapshotRequest as PbSnapshotRequest,
19 SnapshotResponse as PbSnapshotResponse, StatusRequest as PbStatusRequest,
20 StatusResponse as PbStatusResponse,
21};
22use crate::rpc::ResponseHeader;
23use etcdserverpb::maintenance_client::MaintenanceClient as PbMaintenanceClient;
24use etcdserverpb::AlarmMember as PbAlarmMember;
25use tonic::codec::Streaming as PbStreaming;
26use tonic::{IntoRequest, Request};
27
28type Client = PbMaintenanceClient<InterceptedChannel>;
29
30#[repr(transparent)]
32#[derive(Clone)]
33pub struct MaintenanceClient {
34 inner: ClientCaller<Client>,
35}
36
37#[derive(Debug, Default, Clone)]
39#[repr(transparent)]
40pub struct AlarmOptions(PbAlarmRequest);
41
42impl AlarmOptions {
43 #[inline]
45 pub const fn new() -> Self {
46 AlarmOptions(PbAlarmRequest {
47 action: AlarmAction::Get as i32,
48 member_id: 0,
49 alarm: AlarmType::None as i32,
50 })
51 }
52
53 #[inline]
55 const fn with_action_and_type(
56 mut self,
57 alarm_action: AlarmAction,
58 alarm_type: AlarmType,
59 ) -> Self {
60 self.0.action = alarm_action as i32;
61 self.0.alarm = alarm_type as i32;
62 self
63 }
64
65 #[inline]
67 pub fn with_member(&mut self, member: u64) {
68 self.0.member_id = member;
69 }
70}
71
72impl From<AlarmOptions> for PbAlarmRequest {
73 #[inline]
74 fn from(alarm: AlarmOptions) -> Self {
75 alarm.0
76 }
77}
78
79impl IntoRequest<PbAlarmRequest> for AlarmOptions {
80 #[inline]
81 fn into_request(self) -> Request<PbAlarmRequest> {
82 Request::new(self.into())
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub enum DowngradeOptions {
89 Validate(String),
91
92 Enable(String),
94
95 Cancel,
97}
98
99impl From<DowngradeOptions> for PbDowngradeRequest {
100 #[inline]
101 fn from(options: DowngradeOptions) -> Self {
102 match options {
103 DowngradeOptions::Validate(version) => PbDowngradeRequest {
104 action: DowngradeAction::Validate as i32,
105 version,
106 },
107 DowngradeOptions::Enable(version) => PbDowngradeRequest {
108 action: DowngradeAction::Enable as i32,
109 version,
110 },
111 DowngradeOptions::Cancel => PbDowngradeRequest {
112 action: DowngradeAction::Cancel as i32,
113 version: String::new(),
114 },
115 }
116 }
117}
118
119impl IntoRequest<PbDowngradeRequest> for DowngradeOptions {
120 #[inline]
121 fn into_request(self) -> Request<PbDowngradeRequest> {
122 Request::new(self.into())
123 }
124}
125
126#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
128#[derive(Debug, Clone)]
129#[repr(transparent)]
130pub struct DowngradeInfo(PbDowngradeInfo);
131
132impl DowngradeInfo {
133 #[inline]
135 pub fn enabled(&self) -> bool {
136 self.0.enabled
137 }
138
139 #[inline]
141 pub fn target_version(&self) -> &str {
142 &self.0.target_version
143 }
144}
145
146impl From<&PbDowngradeInfo> for &DowngradeInfo {
147 #[inline]
148 fn from(info: &PbDowngradeInfo) -> Self {
149 unsafe { &*(info as *const _ as *const DowngradeInfo) }
150 }
151}
152
153#[derive(Debug, Default, Clone)]
155struct StatusOptions(PbStatusRequest);
156
157impl StatusOptions {
158 #[inline]
159 const fn new() -> Self {
160 Self(PbStatusRequest {})
161 }
162}
163
164impl From<StatusOptions> for PbStatusRequest {
165 #[inline]
166 fn from(status: StatusOptions) -> Self {
167 status.0
168 }
169}
170
171impl IntoRequest<PbStatusRequest> for StatusOptions {
172 #[inline]
173 fn into_request(self) -> Request<PbStatusRequest> {
174 Request::new(self.into())
175 }
176}
177
178#[derive(Debug, Default, Clone)]
180struct DefragmentOptions(PbDefragmentRequest);
181
182impl DefragmentOptions {
183 #[inline]
184 const fn new() -> Self {
185 Self(PbDefragmentRequest {})
186 }
187}
188
189impl From<DefragmentOptions> for PbDefragmentRequest {
190 #[inline]
191 fn from(defragment: DefragmentOptions) -> Self {
192 defragment.0
193 }
194}
195
196impl IntoRequest<PbDefragmentRequest> for DefragmentOptions {
197 #[inline]
198 fn into_request(self) -> Request<PbDefragmentRequest> {
199 Request::new(self.into())
200 }
201}
202
203#[derive(Debug, Default, Clone)]
205struct HashOptions(PbHashRequest);
206
207impl HashOptions {
208 #[inline]
209 const fn new() -> Self {
210 Self(PbHashRequest {})
211 }
212}
213
214impl From<HashOptions> for PbHashRequest {
215 #[inline]
216 fn from(hash: HashOptions) -> Self {
217 hash.0
218 }
219}
220
221impl IntoRequest<PbHashRequest> for HashOptions {
222 #[inline]
223 fn into_request(self) -> Request<PbHashRequest> {
224 Request::new(self.into())
225 }
226}
227
228#[derive(Debug, Default, Clone)]
230#[repr(transparent)]
231struct HashKvOptions(PbHashKvRequest);
232
233impl HashKvOptions {
234 #[inline]
235 const fn new(revision: i64) -> Self {
236 Self(PbHashKvRequest { revision })
237 }
238}
239
240impl From<HashKvOptions> for PbHashKvRequest {
241 #[inline]
242 fn from(hash_kv: HashKvOptions) -> Self {
243 hash_kv.0
244 }
245}
246
247impl IntoRequest<PbHashKvRequest> for HashKvOptions {
248 #[inline]
249 fn into_request(self) -> Request<PbHashKvRequest> {
250 Request::new(self.into())
251 }
252}
253
254#[derive(Debug, Default, Clone)]
256struct SnapshotOptions(PbSnapshotRequest);
257
258impl SnapshotOptions {
259 #[inline]
260 const fn new() -> Self {
261 Self(PbSnapshotRequest {})
262 }
263}
264
265impl From<SnapshotOptions> for PbSnapshotRequest {
266 #[inline]
267 fn from(snapshot: SnapshotOptions) -> Self {
268 snapshot.0
269 }
270}
271
272impl IntoRequest<PbSnapshotRequest> for SnapshotOptions {
273 #[inline]
274 fn into_request(self) -> Request<PbSnapshotRequest> {
275 Request::new(self.into())
276 }
277}
278
279#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
281#[derive(Debug, Clone)]
282#[repr(transparent)]
283pub struct AlarmResponse(PbAlarmResponse);
284
285#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
287#[derive(Clone, PartialEq, Eq)]
288pub struct AlarmMember {
289 member_id: u64,
291 alarm: AlarmType,
293}
294
295impl AlarmMember {
296 #[inline]
298 pub fn member_id(&self) -> u64 {
299 self.member_id
300 }
301
302 #[inline]
304 pub fn alarm(&self) -> AlarmType {
305 self.alarm
306 }
307}
308
309impl AlarmResponse {
310 #[inline]
312 const fn new(resp: PbAlarmResponse) -> Self {
313 Self(resp)
314 }
315
316 #[inline]
318 pub fn header(&self) -> Option<&ResponseHeader> {
319 self.0.header.as_ref().map(From::from)
320 }
321
322 #[inline]
324 pub fn take_header(&mut self) -> Option<ResponseHeader> {
325 self.0.header.take().map(ResponseHeader::new)
326 }
327
328 #[inline]
330 pub fn alarms(&self) -> &[AlarmMember] {
331 unsafe { &*(&self.0.alarms as *const Vec<PbAlarmMember> as *const Vec<AlarmMember>) }
332 }
333}
334
335#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
337#[derive(Debug, Clone)]
338#[repr(transparent)]
339pub struct StatusResponse(PbStatusResponse);
340
341impl StatusResponse {
342 #[inline]
344 const fn new(resp: PbStatusResponse) -> Self {
345 Self(resp)
346 }
347
348 #[inline]
350 pub fn header(&self) -> Option<&ResponseHeader> {
351 self.0.header.as_ref().map(From::from)
352 }
353
354 #[inline]
356 pub fn take_header(&mut self) -> Option<ResponseHeader> {
357 self.0.header.take().map(ResponseHeader::new)
358 }
359
360 #[inline]
362 pub fn version(&self) -> &str {
363 &self.0.version
364 }
365
366 #[inline]
368 pub fn db_size(&self) -> i64 {
369 self.0.db_size
370 }
371
372 #[inline]
374 pub fn leader(&self) -> u64 {
375 self.0.leader
376 }
377
378 #[inline]
380 pub fn raft_index(&self) -> u64 {
381 self.0.raft_index
382 }
383
384 #[inline]
386 pub fn raft_term(&self) -> u64 {
387 self.0.raft_term
388 }
389
390 #[inline]
392 pub fn raft_applied_index(&self) -> u64 {
393 self.0.raft_applied_index
394 }
395
396 #[inline]
398 pub fn errors(&self) -> &[String] {
399 &self.0.errors
400 }
401
402 #[inline]
404 pub fn raft_used_db_size(&self) -> i64 {
405 self.0.db_size_in_use
406 }
407
408 #[inline]
410 pub fn is_learner(&self) -> bool {
411 self.0.is_learner
412 }
413
414 #[inline]
419 pub fn storage_version(&self) -> &str {
420 &self.0.storage_version
421 }
422
423 #[inline]
428 pub fn db_size_quota(&self) -> i64 {
429 self.0.db_size_quota
430 }
431
432 #[inline]
436 pub fn downgrade_info(&self) -> Option<&DowngradeInfo> {
437 self.0.downgrade_info.as_ref().map(From::from)
438 }
439}
440
441#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
443#[derive(Debug, Clone)]
444#[repr(transparent)]
445pub struct DefragmentResponse(PbDefragmentResponse);
446
447impl DefragmentResponse {
448 #[inline]
450 const fn new(resp: PbDefragmentResponse) -> Self {
451 Self(resp)
452 }
453
454 #[inline]
456 pub fn header(&self) -> Option<&ResponseHeader> {
457 self.0.header.as_ref().map(From::from)
458 }
459
460 #[inline]
462 pub fn take_header(&mut self) -> Option<ResponseHeader> {
463 self.0.header.take().map(ResponseHeader::new)
464 }
465}
466
467#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
469#[derive(Debug, Clone)]
470#[repr(transparent)]
471pub struct HashResponse(PbHashResponse);
472
473impl HashResponse {
474 #[inline]
476 const fn new(resp: PbHashResponse) -> Self {
477 Self(resp)
478 }
479
480 #[inline]
482 pub fn header(&self) -> Option<&ResponseHeader> {
483 self.0.header.as_ref().map(From::from)
484 }
485
486 #[inline]
488 pub fn take_header(&mut self) -> Option<ResponseHeader> {
489 self.0.header.take().map(ResponseHeader::new)
490 }
491
492 #[inline]
494 pub fn hash(&self) -> u32 {
495 self.0.hash
496 }
497}
498
499#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
501#[derive(Debug, Clone)]
502#[repr(transparent)]
503pub struct HashKvResponse(PbHashKvResponse);
504
505impl HashKvResponse {
506 #[inline]
508 const fn new(resp: PbHashKvResponse) -> Self {
509 Self(resp)
510 }
511
512 #[inline]
514 pub fn header(&self) -> Option<&ResponseHeader> {
515 self.0.header.as_ref().map(From::from)
516 }
517
518 #[inline]
520 pub fn take_header(&mut self) -> Option<ResponseHeader> {
521 self.0.header.take().map(ResponseHeader::new)
522 }
523
524 #[inline]
526 pub fn hash(&self) -> u32 {
527 self.0.hash
528 }
529
530 #[inline]
532 pub fn compact_version(&self) -> i64 {
533 self.0.compact_revision
534 }
535
536 #[inline]
540 pub fn hash_revision(&self) -> i64 {
541 self.0.hash_revision
542 }
543}
544
545#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
547#[derive(Debug, Clone)]
548#[repr(transparent)]
549pub struct SnapshotResponse(PbSnapshotResponse);
550
551impl SnapshotResponse {
552 #[inline]
554 const fn new(resp: PbSnapshotResponse) -> Self {
555 Self(resp)
556 }
557
558 #[inline]
560 pub fn header(&self) -> Option<&ResponseHeader> {
561 self.0.header.as_ref().map(From::from)
562 }
563
564 #[inline]
566 pub fn take_header(&mut self) -> Option<ResponseHeader> {
567 self.0.header.take().map(ResponseHeader::new)
568 }
569
570 #[inline]
572 pub fn remaining_bytes(&self) -> u64 {
573 self.0.remaining_bytes
574 }
575
576 #[inline]
578 pub fn blob(&self) -> &[u8] {
579 &self.0.blob
580 }
581
582 #[inline]
588 pub fn version(&self) -> &str {
589 &self.0.version
590 }
591}
592
593#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
595#[derive(Debug)]
596#[repr(transparent)]
597pub struct SnapshotStreaming(PbStreaming<PbSnapshotResponse>);
598
599impl SnapshotStreaming {
600 #[inline]
602 pub async fn message(&mut self) -> Result<Option<SnapshotResponse>> {
603 let ret = self.0.message().await?;
604 match ret {
605 Some(rsp) => Ok(Some(SnapshotResponse::new(rsp))),
606 None => Ok(None),
607 }
608 }
609}
610
611#[derive(Debug, Default, Clone)]
613#[repr(transparent)]
614pub struct MoveLeaderOptions(PbMoveLeaderRequest);
615
616impl MoveLeaderOptions {
617 #[inline]
619 const fn with_target_id(mut self, target_id: u64) -> Self {
620 self.0.target_id = target_id;
621 self
622 }
623
624 #[inline]
626 pub const fn new() -> Self {
627 Self(PbMoveLeaderRequest { target_id: 0 })
628 }
629}
630
631impl From<MoveLeaderOptions> for PbMoveLeaderRequest {
632 #[inline]
633 fn from(options: MoveLeaderOptions) -> Self {
634 options.0
635 }
636}
637
638impl IntoRequest<PbMoveLeaderRequest> for MoveLeaderOptions {
639 #[inline]
640 fn into_request(self) -> Request<PbMoveLeaderRequest> {
641 Request::new(self.into())
642 }
643}
644
645#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
647#[derive(Debug, Clone)]
648#[repr(transparent)]
649pub struct MoveLeaderResponse(PbMoveLeaderResponse);
650
651impl MoveLeaderResponse {
652 #[inline]
653 const fn new(resp: PbMoveLeaderResponse) -> Self {
654 Self(resp)
655 }
656
657 #[inline]
659 pub fn header(&self) -> Option<&ResponseHeader> {
660 self.0.header.as_ref().map(From::from)
661 }
662
663 #[inline]
665 pub fn take_header(&mut self) -> Option<ResponseHeader> {
666 self.0.header.take().map(ResponseHeader::new)
667 }
668}
669
670#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
672#[derive(Debug, Clone)]
673#[repr(transparent)]
674pub struct DowngradeResponse(PbDowngradeResponse);
675
676impl DowngradeResponse {
677 #[inline]
678 const fn new(resp: PbDowngradeResponse) -> Self {
679 Self(resp)
680 }
681
682 #[inline]
684 pub fn header(&self) -> Option<&ResponseHeader> {
685 self.0.header.as_ref().map(From::from)
686 }
687
688 #[inline]
690 pub fn take_header(&mut self) -> Option<ResponseHeader> {
691 self.0.header.take().map(ResponseHeader::new)
692 }
693
694 #[inline]
696 pub fn version(&self) -> &str {
697 &self.0.version
698 }
699}
700
701impl MaintenanceClient {
702 #[inline]
704 pub(crate) fn new(builder: ClientCallerBuilder) -> Self {
705 Self {
706 inner: builder.build(Client::new),
707 }
708 }
709
710 #[inline]
712 pub async fn alarm(
713 &mut self,
714 alarm_action: AlarmAction,
715 alarm_type: AlarmType,
716 options: Option<AlarmOptions>,
717 ) -> Result<AlarmResponse> {
718 async fn alarm_impl(client: &mut Client, options: AlarmOptions) -> Result<AlarmResponse> {
719 let resp = client.alarm(options).await?.into_inner();
720 Ok(AlarmResponse::new(resp))
721 }
722 self.inner
723 .do_call(
724 options
725 .unwrap_or_default()
726 .with_action_and_type(alarm_action, alarm_type),
727 alarm_impl,
728 )
729 .await
730 }
731
732 #[inline]
734 pub async fn status(&mut self) -> Result<StatusResponse> {
735 async fn status_impl(
736 client: &mut Client,
737 options: StatusOptions,
738 ) -> Result<StatusResponse> {
739 let resp = client.status(options).await?.into_inner();
740 Ok(StatusResponse::new(resp))
741 }
742 self.inner.do_call(StatusOptions::new(), status_impl).await
743 }
744
745 #[inline]
747 pub async fn defragment(&mut self) -> Result<DefragmentResponse> {
748 async fn defragment_impl(
749 client: &mut Client,
750 options: DefragmentOptions,
751 ) -> Result<DefragmentResponse> {
752 let resp = client.defragment(options).await?.into_inner();
753 Ok(DefragmentResponse::new(resp))
754 }
755 self.inner
756 .do_call(DefragmentOptions::new(), defragment_impl)
757 .await
758 }
759
760 #[inline]
764 pub async fn hash(&mut self) -> Result<HashResponse> {
765 async fn hash_impl(client: &mut Client, options: HashOptions) -> Result<HashResponse> {
766 let resp = client.hash(options).await?.into_inner();
767 Ok(HashResponse::new(resp))
768 }
769 self.inner.do_call(HashOptions::new(), hash_impl).await
770 }
771
772 #[inline]
775 pub async fn hash_kv(&mut self, revision: i64) -> Result<HashKvResponse> {
776 async fn hash_kv_impl(
777 client: &mut Client,
778 options: HashKvOptions,
779 ) -> Result<HashKvResponse> {
780 let resp = client.hash_kv(options).await?.into_inner();
781 Ok(HashKvResponse::new(resp))
782 }
783 self.inner
784 .do_call(HashKvOptions::new(revision), hash_kv_impl)
785 .await
786 }
787
788 #[inline]
790 pub async fn snapshot(&mut self) -> Result<SnapshotStreaming> {
791 async fn snapshot_impl(
792 client: &mut Client,
793 options: SnapshotOptions,
794 ) -> Result<SnapshotStreaming> {
795 let resp = client.snapshot(options).await?.into_inner();
796 Ok(SnapshotStreaming(resp))
797 }
798 self.inner
799 .do_call(SnapshotOptions::new(), snapshot_impl)
800 .await
801 }
802
803 #[inline]
805 pub async fn move_leader(&mut self, target_id: u64) -> Result<MoveLeaderResponse> {
806 async fn move_leader_impl(
807 client: &mut Client,
808 options: MoveLeaderOptions,
809 ) -> Result<MoveLeaderResponse> {
810 let resp = client.move_leader(options).await?.into_inner();
811 Ok(MoveLeaderResponse::new(resp))
812 }
813 self.inner
814 .do_call(
815 MoveLeaderOptions::new().with_target_id(target_id),
816 move_leader_impl,
817 )
818 .await
819 }
820
821 #[inline]
826 pub async fn downgrade(&mut self, options: DowngradeOptions) -> Result<DowngradeResponse> {
827 async fn downgrade_impl(
828 client: &mut Client,
829 options: DowngradeOptions,
830 ) -> Result<DowngradeResponse> {
831 let resp = client.downgrade(options).await?.into_inner();
832 Ok(DowngradeResponse::new(resp))
833 }
834 self.inner.do_call(options, downgrade_impl).await
835 }
836}