//! Message types and conversion methods for `golgi`. use kuska_ssb::api::dto::content::TypedMessage; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::fmt::Debug; use crate::error::GolgiError; /// This is an alias to TypedMessage in kuska, /// which is renamed as SsbMessageContent in golgi to fit the naming convention /// of the other types (SsbMessageKVT and SsbMessageValue) pub type SsbMessageContent = TypedMessage; /// Data type representing the `value` of a message object (`KVT`). More information concerning the /// data model can be found /// in the [`Metadata` documentation](https://spec.scuttlebutt.nz/feed/messages.html#metadata). #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[allow(missing_docs)] pub struct SsbMessageValue { pub previous: Option, pub author: String, pub sequence: u64, pub timestamp: f64, pub hash: String, pub content: Value, pub signature: String, } // Enum representing the different possible message content types #[derive(Debug)] #[allow(missing_docs)] pub enum SsbMessageContentType { About, Vote, Post, Contact, Unrecognized, } impl SsbMessageValue { /// Gets the type field of the message content as an enum, if found. /// 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") .ok_or_else(|| GolgiError::ContentType("type field not found".to_string()))?; let mtype_str: &str = msg_type.as_str().ok_or_else(|| { 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) } /// Helper function which returns true if this message is of the given type, /// and false if the type does not match or is not found pub fn is_message_type(&self, message_type: SsbMessageContentType) -> bool { let self_message_type = self.get_message_type(); match self_message_type { Ok(mtype) => { matches!(mtype, message_type) } Err(_err) => false, } } /// Converts the content json value into an SsbMessageContent enum, /// using the "type" field as a tag to select which variant of the enum /// to deserialize into. /// /// See more info on this here https://serde.rs/enum-representations.html#internally-tagged pub fn into_ssb_message_content(self) -> Result { let m: SsbMessageContent = serde_json::from_value(self.content)?; Ok(m) } } /// Data type representing the `value` of a message object (`KVT`). More information concerning the /// data model can be found /// in the [`Metadata` documentation](https://spec.scuttlebutt.nz/feed/messages.html#metadata). #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[allow(missing_docs)] pub struct SsbMessageKVT { pub key: String, pub value: SsbMessageValue, pub timestamp: f64, pub rts: Option, }