1use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10use crate::error::Result;
11use crate::DakeraClient;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct OpsStats {
20 pub version: String,
21 pub total_vectors: u64,
22 pub namespace_count: u64,
23 pub uptime_seconds: u64,
24 pub timestamp: u64,
25 pub state: String,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ClusterStatus {
31 pub cluster_id: String,
32 pub state: String,
33 pub node_count: u32,
34 pub total_vectors: u64,
35 pub namespace_count: u64,
36 pub version: String,
37 pub timestamp: u64,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct NodeInfo {
43 pub node_id: String,
44 pub address: String,
45 pub role: String,
46 pub status: String,
47 pub version: String,
48 pub uptime_seconds: u64,
49 pub vector_count: u64,
50 pub memory_bytes: u64,
51 #[serde(default)]
52 pub cpu_percent: f32,
53 #[serde(default)]
54 pub memory_percent: f32,
55 pub last_heartbeat: u64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct NodeListResponse {
61 pub nodes: Vec<NodeInfo>,
62 pub total: u32,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct IndexStats {
72 pub index_type: String,
73 pub is_built: bool,
74 pub size_bytes: u64,
75 pub indexed_vectors: u64,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub last_rebuild: Option<u64>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct NamespaceAdminInfo {
83 pub name: String,
84 pub vector_count: u64,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub dimension: Option<usize>,
87 pub index_type: String,
88 pub storage_bytes: u64,
89 pub document_count: u64,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub created_at: Option<u64>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub updated_at: Option<u64>,
94 pub index_stats: IndexStats,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct NamespaceListResponse {
100 pub namespaces: Vec<NamespaceAdminInfo>,
101 pub total: u64,
102 pub total_vectors: u64,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct OptimizeRequest {
108 #[serde(default)]
109 pub force: bool,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub target_index_type: Option<String>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct OptimizeResponse {
117 pub success: bool,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub job_id: Option<String>,
120 pub message: String,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct IndexStatsResponse {
130 pub namespaces: HashMap<String, IndexStats>,
131 pub total_indexed_vectors: u64,
132 pub total_size_bytes: u64,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct RebuildIndexRequest {
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub namespace: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub index_type: Option<String>,
142 #[serde(default)]
143 pub force: bool,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct RebuildIndexResponse {
149 pub success: bool,
150 pub job_id: String,
151 pub message: String,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct CacheStats {
161 pub enabled: bool,
162 pub cache_type: String,
163 pub entries: u64,
164 pub size_bytes: u64,
165 pub hits: u64,
166 pub misses: u64,
167 pub hit_rate: f64,
168 pub evictions: u64,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct ClearCacheRequest {
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub namespace: Option<String>,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct ClearCacheResponse {
181 pub success: bool,
182 pub entries_cleared: u64,
183 pub message: String,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct RuntimeConfig {
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub max_vectors_per_namespace: Option<u64>,
195 pub default_index_type: String,
196 pub cache_enabled: bool,
197 pub cache_max_size_bytes: u64,
198 pub rate_limit_enabled: bool,
199 pub rate_limit_rps: u32,
200 pub query_timeout_ms: u64,
201 #[serde(default = "default_true")]
203 pub autopilot_enabled: bool,
204 #[serde(default = "default_dedup_threshold")]
206 pub autopilot_dedup_threshold: f32,
207 #[serde(default = "default_dedup_interval")]
209 pub autopilot_dedup_interval_hours: u64,
210 #[serde(default = "default_consolidation_interval")]
212 pub autopilot_consolidation_interval_hours: u64,
213}
214
215fn default_true() -> bool {
216 true
217}
218fn default_dedup_threshold() -> f32 {
219 0.93
220}
221fn default_dedup_interval() -> u64 {
222 6
223}
224fn default_consolidation_interval() -> u64 {
225 12
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct UpdateConfigResponse {
231 pub success: bool,
232 pub config: RuntimeConfig,
233 pub message: String,
234 #[serde(default, skip_serializing_if = "Vec::is_empty")]
235 pub warnings: Vec<String>,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct QuotaConfig {
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub max_vectors: Option<u64>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub max_storage_bytes: Option<u64>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub max_queries_per_minute: Option<u64>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub max_writes_per_minute: Option<u64>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct QuotaUsage {
258 #[serde(default)]
259 pub current_vectors: u64,
260 #[serde(default)]
261 pub current_storage_bytes: u64,
262 #[serde(default)]
263 pub queries_this_minute: u64,
264 #[serde(default)]
265 pub writes_this_minute: u64,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct QuotaStatus {
271 pub namespace: String,
272 pub config: QuotaConfig,
273 pub usage: QuotaUsage,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct QuotaListResponse {
279 pub quotas: Vec<QuotaStatus>,
280 pub total: u64,
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub default_config: Option<QuotaConfig>,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
291pub struct SlowQueryEntry {
292 pub id: String,
293 pub timestamp: u64,
294 pub namespace: String,
295 pub query_type: String,
296 pub duration_ms: f64,
297 #[serde(default)]
298 pub parameters: Option<serde_json::Value>,
299 #[serde(default)]
300 pub results_count: u64,
301 #[serde(default)]
302 pub vectors_scanned: u64,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct SlowQueryListResponse {
308 pub queries: Vec<SlowQueryEntry>,
309 pub total: u64,
310 pub threshold_ms: f64,
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct BackupInfo {
320 pub backup_id: String,
321 pub name: String,
322 pub backup_type: String,
323 pub status: String,
324 pub namespaces: Vec<String>,
325 pub vector_count: u64,
326 pub size_bytes: u64,
327 pub created_at: u64,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub completed_at: Option<u64>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub duration_seconds: Option<u64>,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub storage_path: Option<String>,
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub error: Option<String>,
336 pub encrypted: bool,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub compression: Option<String>,
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct BackupListResponse {
344 pub backups: Vec<BackupInfo>,
345 pub total: u64,
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct CreateBackupRequest {
351 pub name: String,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub backup_type: Option<String>,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub namespaces: Option<Vec<String>>,
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub encrypt: Option<bool>,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub compression: Option<String>,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize)]
364pub struct CreateBackupResponse {
365 pub backup: BackupInfo,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub estimated_completion: Option<u64>,
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
372pub struct RestoreBackupRequest {
373 pub backup_id: String,
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub target_namespaces: Option<Vec<String>>,
376 #[serde(skip_serializing_if = "Option::is_none")]
377 pub overwrite: Option<bool>,
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub point_in_time: Option<u64>,
380}
381
382#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct RestoreBackupResponse {
385 pub restore_id: String,
386 pub status: String,
387 pub backup_id: String,
388 pub namespaces: Vec<String>,
389 pub started_at: u64,
390 #[serde(skip_serializing_if = "Option::is_none")]
391 pub estimated_completion: Option<u64>,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub progress_percent: Option<u8>,
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub vectors_restored: Option<u64>,
396 #[serde(skip_serializing_if = "Option::is_none")]
397 pub completed_at: Option<u64>,
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub duration_seconds: Option<u64>,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub error: Option<String>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct AutoPilotConfig {
411 pub enabled: bool,
412 pub dedup_threshold: f32,
413 pub dedup_interval_hours: u64,
414 pub consolidation_interval_hours: u64,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419pub struct DedupResultSnapshot {
420 pub namespaces_processed: usize,
421 pub memories_scanned: usize,
422 pub duplicates_removed: usize,
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct ConsolidationResultSnapshot {
428 pub namespaces_processed: usize,
429 pub memories_scanned: usize,
430 pub clusters_merged: usize,
431 pub memories_consolidated: usize,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct AutoPilotStatusResponse {
437 pub config: AutoPilotConfig,
438 #[serde(skip_serializing_if = "Option::is_none")]
439 pub last_dedup_at: Option<u64>,
440 #[serde(skip_serializing_if = "Option::is_none")]
441 pub last_consolidation_at: Option<u64>,
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub last_dedup: Option<DedupResultSnapshot>,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub last_consolidation: Option<ConsolidationResultSnapshot>,
446 pub total_dedup_removed: u64,
447 pub total_consolidated: u64,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, Default)]
452pub struct AutoPilotConfigRequest {
453 #[serde(skip_serializing_if = "Option::is_none")]
454 pub enabled: Option<bool>,
455 #[serde(skip_serializing_if = "Option::is_none")]
456 pub dedup_threshold: Option<f32>,
457 #[serde(skip_serializing_if = "Option::is_none")]
458 pub dedup_interval_hours: Option<u64>,
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub consolidation_interval_hours: Option<u64>,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct AutoPilotConfigResponse {
466 pub success: bool,
467 pub config: AutoPilotConfig,
468 pub message: String,
469}
470
471#[derive(Debug, Clone, Serialize, Deserialize)]
473#[serde(rename_all = "lowercase")]
474pub enum AutoPilotTriggerAction {
475 Dedup,
476 Consolidate,
477 All,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
482pub struct AutoPilotTriggerRequest {
483 pub action: AutoPilotTriggerAction,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct AutoPilotDedupResult {
489 pub namespaces_processed: usize,
490 pub memories_scanned: usize,
491 pub duplicates_removed: usize,
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize)]
496pub struct AutoPilotConsolidationResult {
497 pub namespaces_processed: usize,
498 pub memories_scanned: usize,
499 pub clusters_merged: usize,
500 pub memories_consolidated: usize,
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct AutoPilotTriggerResponse {
506 pub success: bool,
507 pub action: AutoPilotTriggerAction,
508 #[serde(skip_serializing_if = "Option::is_none")]
509 pub dedup: Option<AutoPilotDedupResult>,
510 #[serde(skip_serializing_if = "Option::is_none")]
511 pub consolidation: Option<AutoPilotConsolidationResult>,
512 pub message: String,
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize)]
521pub struct DecayConfigResponse {
522 pub strategy: String,
524 pub half_life_hours: f64,
526 pub min_importance: f32,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize, Default)]
532pub struct DecayConfigUpdateRequest {
533 #[serde(skip_serializing_if = "Option::is_none")]
535 pub strategy: Option<String>,
536 #[serde(skip_serializing_if = "Option::is_none")]
538 pub half_life_hours: Option<f64>,
539 #[serde(skip_serializing_if = "Option::is_none")]
541 pub min_importance: Option<f32>,
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize)]
546pub struct DecayConfigUpdateResponse {
547 pub success: bool,
548 pub config: DecayConfigResponse,
549 pub message: String,
550}
551
552#[derive(Debug, Clone, Serialize, Deserialize)]
554pub struct LastDecayCycleStats {
555 pub namespaces_processed: usize,
556 pub memories_processed: usize,
557 pub memories_decayed: usize,
558 pub memories_deleted: usize,
559}
560
561#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct DecayStatsResponse {
564 pub total_decayed: u64,
566 pub total_deleted: u64,
568 #[serde(skip_serializing_if = "Option::is_none")]
570 pub last_run_at: Option<u64>,
571 pub cycles_run: u64,
573 #[serde(skip_serializing_if = "Option::is_none")]
575 pub last_cycle: Option<LastDecayCycleStats>,
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize)]
584pub struct TtlCleanupRequest {
585 #[serde(skip_serializing_if = "Option::is_none")]
586 pub namespace: Option<String>,
587}
588
589#[derive(Debug, Clone, Serialize, Deserialize)]
591pub struct TtlCleanupResponse {
592 pub success: bool,
593 pub vectors_removed: u64,
594 pub namespaces_cleaned: Vec<String>,
595 pub message: String,
596}
597
598#[derive(Debug, Clone, Serialize, Deserialize)]
600pub struct TtlStats {
601 pub namespace: String,
602 pub vectors_with_ttl: u64,
603 pub expiring_within_hour: u64,
604 pub expiring_within_day: u64,
605 pub expired_pending_cleanup: u64,
606}
607
608#[derive(Debug, Clone, Serialize, Deserialize)]
610pub struct TtlStatsResponse {
611 pub namespaces: Vec<TtlStats>,
612 pub total_with_ttl: u64,
613 pub total_expired: u64,
614}
615
616impl DakeraClient {
621 pub async fn ops_stats(&self) -> Result<OpsStats> {
629 let url = format!("{}/v1/ops/stats", self.base_url);
630 let response = self.client.get(&url).send().await?;
631 self.handle_response(response).await
632 }
633
634 pub async fn cluster_status(&self) -> Result<ClusterStatus> {
636 let url = format!("{}/admin/cluster/status", self.base_url);
637 let response = self.client.get(&url).send().await?;
638 self.handle_response(response).await
639 }
640
641 pub async fn cluster_nodes(&self) -> Result<NodeListResponse> {
643 let url = format!("{}/admin/cluster/nodes", self.base_url);
644 let response = self.client.get(&url).send().await?;
645 self.handle_response(response).await
646 }
647
648 pub async fn list_namespaces_admin(&self) -> Result<NamespaceListResponse> {
654 let url = format!("{}/admin/namespaces", self.base_url);
655 let response = self.client.get(&url).send().await?;
656 self.handle_response(response).await
657 }
658
659 pub async fn delete_namespace_admin(&self, namespace: &str) -> Result<serde_json::Value> {
661 let url = format!("{}/admin/namespaces/{}", self.base_url, namespace);
662 let response = self.client.delete(&url).send().await?;
663 self.handle_response(response).await
664 }
665
666 pub async fn optimize_namespace(
668 &self,
669 namespace: &str,
670 request: OptimizeRequest,
671 ) -> Result<OptimizeResponse> {
672 let url = format!("{}/admin/namespaces/{}/optimize", self.base_url, namespace);
673 let response = self.client.post(&url).json(&request).send().await?;
674 self.handle_response(response).await
675 }
676
677 pub async fn index_stats(&self) -> Result<IndexStatsResponse> {
683 let url = format!("{}/admin/indexes/stats", self.base_url);
684 let response = self.client.get(&url).send().await?;
685 self.handle_response(response).await
686 }
687
688 pub async fn rebuild_indexes(
690 &self,
691 request: RebuildIndexRequest,
692 ) -> Result<RebuildIndexResponse> {
693 let url = format!("{}/admin/indexes/rebuild", self.base_url);
694 let response = self.client.post(&url).json(&request).send().await?;
695 self.handle_response(response).await
696 }
697
698 pub async fn cache_stats(&self) -> Result<CacheStats> {
704 let url = format!("{}/admin/cache/stats", self.base_url);
705 let response = self.client.get(&url).send().await?;
706 self.handle_response(response).await
707 }
708
709 pub async fn cache_clear(&self, namespace: Option<&str>) -> Result<ClearCacheResponse> {
711 let url = format!("{}/admin/cache/clear", self.base_url);
712 let request = ClearCacheRequest {
713 namespace: namespace.map(|s| s.to_string()),
714 };
715 let response = self.client.post(&url).json(&request).send().await?;
716 self.handle_response(response).await
717 }
718
719 pub async fn get_config(&self) -> Result<RuntimeConfig> {
725 let url = format!("{}/admin/config", self.base_url);
726 let response = self.client.get(&url).send().await?;
727 self.handle_response(response).await
728 }
729
730 pub async fn update_config(
732 &self,
733 updates: HashMap<String, serde_json::Value>,
734 ) -> Result<UpdateConfigResponse> {
735 let url = format!("{}/admin/config", self.base_url);
736 let response = self.client.put(&url).json(&updates).send().await?;
737 self.handle_response(response).await
738 }
739
740 pub async fn get_quotas(&self) -> Result<QuotaListResponse> {
746 let url = format!("{}/admin/quotas", self.base_url);
747 let response = self.client.get(&url).send().await?;
748 self.handle_response(response).await
749 }
750
751 pub async fn get_quota(&self, namespace: &str) -> Result<QuotaStatus> {
753 let url = format!("{}/admin/quotas/{}", self.base_url, namespace);
754 let response = self.client.get(&url).send().await?;
755 self.handle_response(response).await
756 }
757
758 pub async fn set_quota(
760 &self,
761 namespace: &str,
762 config: QuotaConfig,
763 ) -> Result<serde_json::Value> {
764 let url = format!("{}/admin/quotas/{}", self.base_url, namespace);
765 let request = serde_json::json!({ "config": config });
766 let response = self.client.put(&url).json(&request).send().await?;
767 self.handle_response(response).await
768 }
769
770 pub async fn delete_quota(&self, namespace: &str) -> Result<serde_json::Value> {
772 let url = format!("{}/admin/quotas/{}", self.base_url, namespace);
773 let response = self.client.delete(&url).send().await?;
774 self.handle_response(response).await
775 }
776
777 pub async fn update_quotas(&self, config: Option<QuotaConfig>) -> Result<serde_json::Value> {
779 let url = format!("{}/admin/quotas/default", self.base_url);
780 let request = serde_json::json!({ "config": config });
781 let response = self.client.put(&url).json(&request).send().await?;
782 self.handle_response(response).await
783 }
784
785 pub async fn slow_queries(
791 &self,
792 limit: Option<usize>,
793 namespace: Option<&str>,
794 query_type: Option<&str>,
795 ) -> Result<SlowQueryListResponse> {
796 let mut url = format!("{}/admin/slow-queries", self.base_url);
797 let mut params = Vec::new();
798 if let Some(l) = limit {
799 params.push(format!("limit={}", l));
800 }
801 if let Some(ns) = namespace {
802 params.push(format!("namespace={}", ns));
803 }
804 if let Some(qt) = query_type {
805 params.push(format!("query_type={}", qt));
806 }
807 if !params.is_empty() {
808 url.push('?');
809 url.push_str(¶ms.join("&"));
810 }
811 let response = self.client.get(&url).send().await?;
812 self.handle_response(response).await
813 }
814
815 pub async fn slow_query_summary(&self) -> Result<serde_json::Value> {
817 let url = format!("{}/admin/slow-queries/summary", self.base_url);
818 let response = self.client.get(&url).send().await?;
819 self.handle_response(response).await
820 }
821
822 pub async fn clear_slow_queries(&self) -> Result<serde_json::Value> {
824 let url = format!("{}/admin/slow-queries", self.base_url);
825 let response = self.client.delete(&url).send().await?;
826 self.handle_response(response).await
827 }
828
829 pub async fn create_backup(
835 &self,
836 request: CreateBackupRequest,
837 ) -> Result<CreateBackupResponse> {
838 let url = format!("{}/admin/backups", self.base_url);
839 let response = self.client.post(&url).json(&request).send().await?;
840 self.handle_response(response).await
841 }
842
843 pub async fn list_backups(&self) -> Result<BackupListResponse> {
845 let url = format!("{}/admin/backups", self.base_url);
846 let response = self.client.get(&url).send().await?;
847 self.handle_response(response).await
848 }
849
850 pub async fn get_backup(&self, backup_id: &str) -> Result<BackupInfo> {
852 let url = format!("{}/admin/backups/{}", self.base_url, backup_id);
853 let response = self.client.get(&url).send().await?;
854 self.handle_response(response).await
855 }
856
857 pub async fn restore_backup(
859 &self,
860 request: RestoreBackupRequest,
861 ) -> Result<RestoreBackupResponse> {
862 let url = format!("{}/admin/backups/restore", self.base_url);
863 let response = self.client.post(&url).json(&request).send().await?;
864 self.handle_response(response).await
865 }
866
867 pub async fn delete_backup(&self, backup_id: &str) -> Result<serde_json::Value> {
869 let url = format!("{}/admin/backups/{}", self.base_url, backup_id);
870 let response = self.client.delete(&url).send().await?;
871 self.handle_response(response).await
872 }
873
874 pub async fn ttl_cleanup(&self, namespace: Option<&str>) -> Result<TtlCleanupResponse> {
880 let url = format!("{}/admin/ttl/cleanup", self.base_url);
881 let request = TtlCleanupRequest {
882 namespace: namespace.map(|s| s.to_string()),
883 };
884 let response = self.client.post(&url).json(&request).send().await?;
885 self.handle_response(response).await
886 }
887
888 pub async fn ttl_stats(&self) -> Result<TtlStatsResponse> {
890 let url = format!("{}/admin/ttl/stats", self.base_url);
891 let response = self.client.get(&url).send().await?;
892 self.handle_response(response).await
893 }
894
895 pub async fn autopilot_status(&self) -> Result<AutoPilotStatusResponse> {
901 let url = format!("{}/admin/autopilot/status", self.base_url);
902 let response = self.client.get(&url).send().await?;
903 self.handle_response(response).await
904 }
905
906 pub async fn autopilot_update_config(
910 &self,
911 request: AutoPilotConfigRequest,
912 ) -> Result<AutoPilotConfigResponse> {
913 let url = format!("{}/admin/autopilot/config", self.base_url);
914 let response = self.client.put(&url).json(&request).send().await?;
915 self.handle_response(response).await
916 }
917
918 pub async fn autopilot_trigger(
923 &self,
924 action: AutoPilotTriggerAction,
925 ) -> Result<AutoPilotTriggerResponse> {
926 let url = format!("{}/admin/autopilot/trigger", self.base_url);
927 let request = AutoPilotTriggerRequest { action };
928 let response = self.client.post(&url).json(&request).send().await?;
929 self.handle_response(response).await
930 }
931
932 pub async fn decay_config(&self) -> Result<DecayConfigResponse> {
941 let url = format!("{}/admin/decay/config", self.base_url);
942 let response = self.client.get(&url).send().await?;
943 self.handle_response(response).await
944 }
945
946 pub async fn decay_update_config(
952 &self,
953 request: DecayConfigUpdateRequest,
954 ) -> Result<DecayConfigUpdateResponse> {
955 let url = format!("{}/admin/decay/config", self.base_url);
956 let response = self.client.put(&url).json(&request).send().await?;
957 self.handle_response(response).await
958 }
959
960 pub async fn decay_stats(&self) -> Result<DecayStatsResponse> {
965 let url = format!("{}/admin/decay/stats", self.base_url);
966 let response = self.client.get(&url).send().await?;
967 self.handle_response(response).await
968 }
969}