diff --git a/src/error.rs b/src/error.rs index ac8fab5..7060222 100644 --- a/src/error.rs +++ b/src/error.rs @@ -37,7 +37,7 @@ pub enum GolgiError { /// JSON serialization or deserialization error. SerdeJson(JsonError), /// Error decoding typed ssb message from content. - ContentTypeDecode(String), + ContentType(String), /// Error decoding UTF8 string from bytes Utf8Parse { /// The underlying parse error. @@ -56,7 +56,7 @@ impl std::error::Error for GolgiError { GolgiError::Rpc(ref err) => Some(err), GolgiError::Sbot(_) => None, GolgiError::SerdeJson(ref err) => Some(err), - GolgiError::ContentTypeDecode(_) => None, + GolgiError::ContentType(_) => None, GolgiError::Utf8Parse{ ref source} => Some(source), } } @@ -77,7 +77,7 @@ impl std::fmt::Display for GolgiError { GolgiError::Sbot(ref err) => write!(f, "Sbot returned an error response: {}", err), GolgiError::SerdeJson(_) => write!(f, "Failed to serialize JSON slice"), //GolgiError::WhoAmI(ref err) => write!(f, "{}", err), - GolgiError::ContentTypeDecode(ref err) => write!( + GolgiError::ContentType(ref err) => write!( f, "Failed to decode typed message from ssb message content: {}", err diff --git a/src/messages.rs b/src/messages.rs index d839e94..6ea9cc3 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -36,32 +36,26 @@ pub enum SsbMessageContentType { Vote, Post, Contact, - None + Unrecognized } impl SsbMessageValue { /// Gets the type field of the message content as an enum, if found. - /// if no type field is found, it returns a SsbMessageContentType::None - /// if a type field is found with an invalid format it returns a GolgiError::ContentTypeDecode + /// if no type field is found or the type field is not a string, it returns an Err(GolgiError::ContentType) + /// if a type field is found but with an unknown string it returns an Ok(SsbMessageContentType::Unrecognized) pub fn get_message_type(&self) -> Result { let msg_type = self .content - .get("type"); - let enum_type = match msg_type { - Some(mtype) => { - let mtype_str: &str = mtype.as_str().ok_or(GolgiError::ContentTypeDecode("type field with invalid format".to_string()))?; - match mtype_str { - "about" => SsbMessageContentType::About, - "post" => SsbMessageContentType::Post, - "vote" => SsbMessageContentType::Vote, - "contact" => SsbMessageContentType::Contact, - _ => return Err(GolgiError::ContentTypeDecode("type field with unknown value".to_string())) - } - }, - None => { - SsbMessageContentType::None - } + .get("type") + .ok_or(GolgiError::ContentType("type field not found".to_string()))?; + let mtype_str: &str = msg_type.as_str().ok_or(GolgiError::ContentType("type field value is not a string as expected".to_string()))?; + let enum_type = match mtype_str { + "about" => SsbMessageContentType::About, + "post" => SsbMessageContentType::Post, + "vote" => SsbMessageContentType::Vote, + "contact" => SsbMessageContentType::Contact, + _ => SsbMessageContentType::Unrecognized, }; Ok(enum_type) } diff --git a/src/sbot.rs b/src/sbot.rs index 5fbafa5..a7b2250 100644 --- a/src/sbot.rs +++ b/src/sbot.rs @@ -195,31 +195,24 @@ impl Sbot { pub async fn get_latest_about_message(&mut self, ssb_id: &str, key: &str) -> Result, GolgiError> { // vector of about messages with most recent at the front of the vector let about_messages = self.get_about_messages(ssb_id).await?; - // iterate through the vector looking for an about message with the given key - // the first one we find is the most recent - for msg in about_messages { - let value = msg.content.get(key); - match value { - Some(val) => { - let val_as_str_option = val.as_str(); - match val_as_str_option { - Some(val_as_str) => { - return Ok(Some(val_as_str.to_string())) - }, - None => { - // if it is an improperly formatted field (not a string) - // then just continue - continue - } - } - }, - None => { - continue - } - } - } - // if no about message with given key was found, then return None - Ok(None) + // iterate through the vector looking for most recent about message with the given key + let latest_about = about_messages + .iter() + // find the first msg that contains the field `key` + .find(|msg| msg.content.get(key).is_some()) + // map the found msg (`Some(SsbMessageValue)`) to a `Some(Some(&Value))` + .map(|msg| msg.content.get(key)) + // flatten `Some(Some(&Value))` into `Some(&Value)` + .flatten() + // map `Some(&Value)` to `Some(Some(&str))` + .map(|msg_val| msg_val.as_str()) + // flatten `Some(Some(&str))` to `Some(&str)` + .flatten() + // map `Some(&str))` to `Some(String)` + .map(|msg_str| msg_str.to_string()); + + // return value is either `Ok(Some(String))` or `Ok(None)` + Ok(latest_about) } pub async fn get_name(&mut self, ssb_id: &str) -> Result, GolgiError> { diff --git a/src/utils.rs b/src/utils.rs index c840610..34f5ec6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -140,6 +140,8 @@ where Ok(messages) } + + /// Takes in an rpc request number, and a handling function, /// and calls the handling function on all responses which match the request number, /// and prints out the result of the handling function.