notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

login_manager.rs (4697B)


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