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 SecretPromptQueue {
49 pub fn new() -> Self {
50 Self {
51 active: None,
52 pending: std::collections::VecDeque::new(),
53 }
54 }
55
56 pub fn poll_requests(
57 &mut self,
58 rx: &Arc<Mutex<tokio::sync::mpsc::UnboundedReceiver<SecretPromptRequest>>>,
59 ) {
60 if let Ok(mut rx) = rx.lock() {
61 while let Ok(req) = rx.try_recv() {
62 self.pending.push_back(req);
63 }
64 }
65 self.activate_next();
66 }
67
68 fn activate_next(&mut self) {
69 if self.active.is_some() {
70 return;
71 }
72 if let Some(req) = self.pending.pop_front() {
73 self.active = Some(PendingSecretPrompt {
74 title: req.title,
75 prompt: req.prompt,
76 buffer: String::new(),
77 response_tx: req.response_tx,
78 });
79 }
80 }
81
82 pub fn is_active(&self) -> bool {
83 self.active.is_some()
84 }
85
86 pub fn active(&self) -> Option<&PendingSecretPrompt> {
87 self.active.as_ref()
88 }
89
90 pub fn push_char(&mut self, ch: char) {
91 if let Some(active) = self.active.as_mut() {
92 active.buffer.push(ch);
93 }
94 }
95
96 pub fn backspace(&mut self) {
97 if let Some(active) = self.active.as_mut() {
98 active.buffer.pop();
99 }
100 }
101
102 pub fn submit(&mut self) {
103 if let Some(mut active) = self.active.take() {
104 let secret = std::mem::take(&mut active.buffer);
105 let _ = active.response_tx.send(Some(secret));
106 }
107 self.activate_next();
108 }
109
110 pub fn cancel(&mut self) {
111 if let Some(mut active) = self.active.take() {
112 active.buffer.clear();
113 let _ = active.response_tx.send(None);
114 }
115 self.activate_next();
116 }
117}