login_manager.rs (4821B)
1 use crate::key_parsing::perform_key_retrieval; 2 use crate::key_parsing::AcquireKeyError; 3 use egui::{TextBuffer, TextEdit}; 4 use enostr::Keypair; 5 use poll_promise::Promise; 6 7 /// The state data for acquiring a nostr key 8 #[derive(Default)] 9 pub struct AcquireKeyState { 10 desired_key: String, 11 promise_query: Option<(String, Promise<Result<Keypair, AcquireKeyError>>)>, 12 error: Option<AcquireKeyError>, 13 key_on_error: Option<String>, 14 should_create_new: bool, 15 } 16 17 impl<'a> AcquireKeyState { 18 pub fn new() -> Self { 19 AcquireKeyState::default() 20 } 21 22 /// Get the textedit for the UI without exposing the key variable 23 pub fn get_acquire_textedit( 24 &'a mut self, 25 textedit_closure: fn(&'a mut dyn TextBuffer) -> TextEdit<'a>, 26 ) -> TextEdit<'a> { 27 textedit_closure(&mut self.desired_key) 28 } 29 30 /// User pressed the 'acquire' button 31 pub fn apply_acquire(&'a mut self) { 32 let new_promise = match &self.promise_query { 33 Some((query, _)) => { 34 if query != &self.desired_key { 35 Some(perform_key_retrieval(&self.desired_key)) 36 } else { 37 None 38 } 39 } 40 None => Some(perform_key_retrieval(&self.desired_key)), 41 }; 42 43 if let Some(new_promise) = new_promise { 44 self.promise_query = Some((self.desired_key.clone(), new_promise)); 45 } 46 } 47 48 /// Whether to indicate to the user that there is a network operation occuring 49 pub fn is_awaiting_network(&self) -> bool { 50 self.promise_query.is_some() 51 } 52 53 /// Whether to indicate to the user that a login error occured 54 pub fn check_for_error(&'a mut self) -> Option<&'a AcquireKeyError> { 55 if let Some(error_key) = &self.key_on_error { 56 if self.desired_key != *error_key { 57 self.error = None; 58 self.key_on_error = None; 59 } 60 } 61 62 self.error.as_ref() 63 } 64 65 /// Whether to indicate to the user that a successful login occured 66 pub fn check_for_successful_login(&mut self) -> Option<Keypair> { 67 if let Some((_, promise)) = &mut self.promise_query { 68 if promise.ready().is_some() { 69 if let Some((_, promise)) = self.promise_query.take() { 70 match promise.block_and_take() { 71 Ok(key) => { 72 return Some(key); 73 } 74 Err(e) => { 75 self.error = Some(e); 76 self.key_on_error = Some(self.desired_key.clone()); 77 } 78 }; 79 } 80 } 81 } 82 None 83 } 84 85 pub fn should_create_new(&mut self) { 86 self.should_create_new = true; 87 } 88 89 pub fn check_for_create_new(&self) -> bool { 90 self.should_create_new 91 } 92 } 93 94 #[cfg(test)] 95 mod tests { 96 use enostr::Pubkey; 97 98 use super::*; 99 use std::time::{Duration, Instant}; 100 101 #[tokio::test(flavor = "multi_thread", worker_threads = 2)] 102 async fn test_retrieve_key() { 103 let mut manager = AcquireKeyState::new(); 104 let expected_str = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"; 105 let expected_key = Keypair::only_pubkey(Pubkey::from_hex(expected_str).unwrap()); 106 107 let start_time = Instant::now(); 108 109 while start_time.elapsed() < Duration::from_millis(50u64) { 110 let cur_time = start_time.elapsed(); 111 112 if cur_time < Duration::from_millis(10u64) { 113 let _ = manager.get_acquire_textedit(|text| { 114 text.clear(); 115 text.insert_text("test", 0); 116 egui::TextEdit::singleline(text) 117 }); 118 manager.apply_acquire(); 119 } else if cur_time < Duration::from_millis(30u64) { 120 let _ = manager.get_acquire_textedit(|text| { 121 text.clear(); 122 text.insert_text("test2", 0); 123 egui::TextEdit::singleline(text) 124 }); 125 manager.apply_acquire(); 126 } else { 127 let _ = manager.get_acquire_textedit(|text| { 128 text.clear(); 129 text.insert_text( 130 "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681", 131 0, 132 ); 133 egui::TextEdit::singleline(text) 134 }); 135 manager.apply_acquire(); 136 } 137 138 if let Some(key) = manager.check_for_successful_login() { 139 assert_eq!(expected_key, key); 140 return; 141 } 142 } 143 144 panic!("Test failed to get expected key."); 145 } 146 }