diff --git a/src/sbot.rs b/src/sbot.rs index 2c1abb3..0a3fe6d 100644 --- a/src/sbot.rs +++ b/src/sbot.rs @@ -1,4 +1,5 @@ //! Sbot type and associated methods. +use std::collections::HashMap; use async_std::{ net::TcpStream, stream::{Stream, StreamExt}, @@ -281,33 +282,87 @@ impl Sbot { // now we have a stream of about messages with most recent at the front of the vector pin_mut!(about_message_stream); // iterate through the vector looking for most recent about message with the given key - let latest_about_message: Result = about_message_stream + let latest_about_message_res: Option> = about_message_stream // find the first msg that contains the field `key` .find(|res| match res { Ok(msg) => msg.content.get(key).is_some(), Err(_) => false, }) - .await - .ok_or_else(|| { - GolgiError::Sbot("error while looking for about message with given key".to_string()) - })?; - let latest_about_value = match latest_about_message { - Ok(msg) => { - msg - // SsbMessageValue -> Option<&Value> - .content - .get(key) - // Option<&Value> -> - .and_then(|value| value.as_str()) - // Option<&str> -> Option - .map(|value| value.to_string()) - } - Err(_) => None, - }; + .await; + // Option> -> Option + let latest_about_message = latest_about_message_res.and_then(|msg| msg.ok()); + // Option -> Option + let latest_about_value = latest_about_message.and_then(|msg| { + msg + // SsbMessageValue -> Option<&Value> + .content + .get(key) + // Option<&Value> -> + .and_then(|value| value.as_str()) + // Option<&str> -> Option + .map(|value| value.to_string()) + }); // return value is either `Ok(Some(String))` or `Ok(None)` Ok(latest_about_value) } + /// Get HashMap of profile info for given user + /// by iteratively searching through a stream of about messages, + /// in order of recency, + /// until we find all about messages for all needed info + /// or reach the end of the stream. + pub async fn get_profile_info( + &mut self, + ssb_id: &str + ) -> Result, GolgiError> { + // get about_message_stream + let about_message_stream = self.get_about_message_stream(ssb_id).await?; + // now we have a stream of about messages with most recent at the front of the vector + pin_mut!(about_message_stream); // needed for iteration + let mut profile_info: HashMap = HashMap::new(); + // these are the about message keys we are looking for + // as we find values for each of these keys, + // we will remove them from this vector (as we are no longer searching for them) + let mut keys_to_search_for = vec!["name", "description", "profile"]; + // iterate through the stream while it still has more values and + // we still have keys we are looking for + while let Some(res) = about_message_stream.next().await { + println!("res: {:?}", res); + // if there are no more keys we are looking for, then we are done + if keys_to_search_for.len() == 0 { + break + } + // if there are still keys we are looking for, then continue searching + match res { + Ok(msg) => { + // for each key we are searching for, check if this about + // message contains a value for that key + for key in &keys_to_search_for.clone() { + let option_val = msg.content.get(key) + .and_then(|val| val.as_str()) + .map(|val| val.to_string()); + match option_val { + Some(val) => { + // if a value is found, then insert it + profile_info.insert(key.to_string(), val); + // remove this key fom keys_to_search_for, since we are no longer searching for it + keys_to_search_for.retain(|val| val != key) + } + None => { + continue + } + } + } + } + Err(err) => { + // skip errors + continue + } + } + } + Ok(profile_info) + } + /// Get latest about name from given user /// /// # Arguments