synaps_cli/tools/
secret_prompt.rs1use std::sync::{Arc, Mutex};
2
3#[derive(Clone)]
9pub struct SecretPromptHandle {
10 tx: tokio::sync::mpsc::UnboundedSender<SecretPromptRequest>,
11}
12
13impl SecretPromptHandle {
14 pub fn new(tx: tokio::sync::mpsc::UnboundedSender<SecretPromptRequest>) -> Self {
15 Self { tx }
16 }
17
18 pub async fn prompt(&self, title: String, prompt: String) -> Option<String> {
19 let (response_tx, response_rx) = tokio::sync::oneshot::channel();
20 let request = SecretPromptRequest {
21 title,
22 prompt,
23 response_tx,
24 };
25 self.tx.send(request).ok()?;
26 response_rx.await.ok().flatten()
27 }
28}
29
30pub struct SecretPromptRequest {
31 pub title: String,
32 pub prompt: String,
33 pub response_tx: tokio::sync::oneshot::Sender<Option<String>>,
34}
35
36pub struct PendingSecretPrompt {
37 pub title: String,
38 pub prompt: String,
39 pub buffer: String,
40 pub response_tx: tokio::sync::oneshot::Sender<Option<String>>,
41}
42
43pub struct SecretPromptQueue {
44 active: Option<PendingSecretPrompt>,
45 pending: std::collections::VecDeque<SecretPromptRequest>,
46}
47
48impl Default for SecretPromptQueue {
49 fn default() -> Self { Self::new() }
50}
51
52impl SecretPromptQueue {
53 pub fn new() -> Self {
54 Self {
55 active: None,
56 pending: std::collections::VecDeque::new(),
57 }
58 }
59
60 pub fn poll_requests(
61 &mut self,
62 rx: &Arc<Mutex<tokio::sync::mpsc::UnboundedReceiver<SecretPromptRequest>>>,
63 ) {
64 if let Ok(mut rx) = rx.lock() {
65 while let Ok(req) = rx.try_recv() {
66 self.pending.push_back(req);
67 }
68 }
69 self.activate_next();
70 }
71
72 fn activate_next(&mut self) {
73 if self.active.is_some() {
74 return;
75 }
76 if let Some(req) = self.pending.pop_front() {
77 self.active = Some(PendingSecretPrompt {
78 title: req.title,
79 prompt: req.prompt,
80 buffer: String::new(),
81 response_tx: req.response_tx,
82 });
83 }
84 }
85
86 pub fn is_active(&self) -> bool {
87 self.active.is_some()
88 }
89
90 pub fn active(&self) -> Option<&PendingSecretPrompt> {
91 self.active.as_ref()
92 }
93
94 pub fn push_char(&mut self, ch: char) {
95 if let Some(active) = self.active.as_mut() {
96 active.buffer.push(ch);
97 }
98 }
99
100 pub fn backspace(&mut self) {
101 if let Some(active) = self.active.as_mut() {
102 active.buffer.pop();
103 }
104 }
105
106 pub fn submit(&mut self) {
107 if let Some(mut active) = self.active.take() {
108 let secret = std::mem::take(&mut active.buffer);
109 let _ = active.response_tx.send(Some(secret));
110 }
111 self.activate_next();
112 }
113
114 pub fn cancel(&mut self) {
115 if let Some(mut active) = self.active.take() {
116 active.buffer.clear();
117 let _ = active.response_tx.send(None);
118 }
119 self.activate_next();
120 }
121}