|
@@ -12,52 +12,24 @@ pub enum Error {
|
|
|
}
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
-pub enum TagType {
|
|
|
- Event,
|
|
|
- PubKey,
|
|
|
- Custom(String),
|
|
|
+pub enum Tag {
|
|
|
+ Event(Addr, Option<String>, Vec<String>),
|
|
|
+ PubKey(Addr, Option<String>, Vec<String>),
|
|
|
+ Unknown(String, Vec<String>),
|
|
|
}
|
|
|
|
|
|
-impl From<&str> for TagType {
|
|
|
- fn from(s: &str) -> Self {
|
|
|
- match s {
|
|
|
- "e" => TagType::Event,
|
|
|
- "p" => TagType::PubKey,
|
|
|
- e => TagType::Custom(e.to_owned()),
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl ToString for TagType {
|
|
|
- fn to_string(&self) -> String {
|
|
|
+impl Tag {
|
|
|
+ pub fn is_pubkey(&self) -> bool {
|
|
|
match self {
|
|
|
- TagType::Event => "e".to_owned(),
|
|
|
- TagType::PubKey => "p".to_owned(),
|
|
|
- TagType::Custom(x) => x.to_owned(),
|
|
|
+ Self::PubKey(_, _, _) => true,
|
|
|
+ _ => false,
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-#[derive(Debug, Clone)]
|
|
|
-pub struct Tag {
|
|
|
- pub typ: TagType,
|
|
|
- pub value: Addr,
|
|
|
- pub relayer_url: Option<String>,
|
|
|
- pub extra: Vec<String>,
|
|
|
-}
|
|
|
-
|
|
|
-impl Tag {
|
|
|
- pub fn new<T: Into<TagType>>(
|
|
|
- typ: T,
|
|
|
- value: Addr,
|
|
|
- relayer_url: Option<String>,
|
|
|
- extra: Vec<String>,
|
|
|
- ) -> Self {
|
|
|
- Self {
|
|
|
- typ: typ.into(),
|
|
|
- value,
|
|
|
- relayer_url,
|
|
|
- extra,
|
|
|
+ pub fn is_event(&self) -> bool {
|
|
|
+ match self {
|
|
|
+ Self::Event(_, _, _) => true,
|
|
|
+ _ => false,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -67,18 +39,29 @@ impl ser::Serialize for Tag {
|
|
|
where
|
|
|
S: Serializer,
|
|
|
{
|
|
|
- let len = if self.relayer_url.is_some() {
|
|
|
- 3 + self.extra.len()
|
|
|
- } else {
|
|
|
- 2
|
|
|
+ let typ = match self {
|
|
|
+ Tag::Event(_, _, _) => "e",
|
|
|
+ Tag::PubKey(_, _, _) => "p",
|
|
|
+ Tag::Unknown(u, _) => u,
|
|
|
};
|
|
|
- let mut seq = serializer.serialize_seq(Some(len))?;
|
|
|
- seq.serialize_element(&self.typ.to_string())?;
|
|
|
- seq.serialize_element(&self.value.to_hex())?;
|
|
|
- if let Some(addr) = self.relayer_url.as_ref() {
|
|
|
- seq.serialize_element(addr)?;
|
|
|
- for extra in self.extra.iter() {
|
|
|
- seq.serialize_element(extra)?;
|
|
|
+
|
|
|
+ let mut seq = serializer.serialize_seq(Some(2))?;
|
|
|
+ seq.serialize_element(typ)?;
|
|
|
+
|
|
|
+ match self {
|
|
|
+ Tag::Event(addr, relayer, extra) | Tag::PubKey(addr, relayer, extra) => {
|
|
|
+ seq.serialize_element(&addr.to_hex())?;
|
|
|
+ if let Some(relayer) = relayer {
|
|
|
+ seq.serialize_element(&relayer)?;
|
|
|
+ for extra in extra.iter() {
|
|
|
+ seq.serialize_element(extra)?;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Tag::Unknown(_, extra) => {
|
|
|
+ for extra in extra.iter() {
|
|
|
+ seq.serialize_element(extra)?;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
seq.end()
|
|
@@ -90,37 +73,67 @@ impl<'de> Deserialize<'de> for Tag {
|
|
|
where
|
|
|
D: Deserializer<'de>,
|
|
|
{
|
|
|
- let v: Vec<String> = Deserialize::deserialize(deserializer)?;
|
|
|
- if v.len() < 2 {
|
|
|
+ let parts: Vec<String> = Deserialize::deserialize(deserializer)?;
|
|
|
+ if parts.len() < 2 {
|
|
|
return Err(de::Error::custom("expected array of two strings"));
|
|
|
}
|
|
|
- let value: Addr = v[1]
|
|
|
- .as_str()
|
|
|
- .try_into()
|
|
|
- .map_err(|e: super::addr::Error| de::Error::custom(e.to_string()))?;
|
|
|
- let relayer_url = v.get(2).map(|x| x.to_owned());
|
|
|
|
|
|
- let extra = if v.len() > 3 {
|
|
|
- v[3..].to_owned()
|
|
|
- } else {
|
|
|
- vec![]
|
|
|
- };
|
|
|
+ Ok(match parts[0].as_str() {
|
|
|
+ "e" | "p" => {
|
|
|
+ let addr = parts[1]
|
|
|
+ .as_str()
|
|
|
+ .try_into()
|
|
|
+ .map_err(|e: super::addr::Error| de::Error::custom(e.to_string()))?;
|
|
|
|
|
|
- Ok(Self::new(v[0].as_str(), value, relayer_url, extra))
|
|
|
+ let relayer_addr = parts.get(2).cloned();
|
|
|
+ let extra = if parts.len() < 3 {
|
|
|
+ vec![]
|
|
|
+ } else {
|
|
|
+ parts[3..].to_owned()
|
|
|
+ };
|
|
|
+
|
|
|
+ if "e" == parts[0].as_str() {
|
|
|
+ Tag::Event(addr, relayer_addr, extra)
|
|
|
+ } else {
|
|
|
+ Tag::PubKey(addr, relayer_addr, extra)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ extra => Tag::Unknown(extra.to_owned(), parts[1..].to_owned()),
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod test {
|
|
|
use super::*;
|
|
|
+ use crate::Message;
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn bug_01() {
|
|
|
+ let json = r#"["EVENT","d45a98f898820258a3313f5cb14f5fe8a9263437931ac6309f23ae0324833f39",{"content":"Will fight under the light of lightnings! No darkness on nostr! 🐶🐾😂","created_at":1678685477,"id":"5462822032c16d32267ba40536409fd51ea188b20e7dd5f9e7a0aa5561346f79","kind":1,"pubkey":"8fb140b4e8ddef97ce4b821d247278a1a4353362623f64021484b372f948000c","sig":"62c8e09a0fedd8096a313ef12436b0f0bcad56e9058d4bc12f61ae6094c099bb966dce47efa2d721c5bfdf923614db46d1d1c248105cb99c4ec495292cc875b1","tags":[["e","5f63f9e7d37673e76ddf7448cd67c3d74f9be96c240a40199b59a30db32d7f43"],["e","c70894331986c66a2baf6fc12dd5c86280e4616cee0e57bbee90972ebbb4b735"],["p","ac3fb436a663b25893657f4b6a3d9d2f02d1974bb5ced603f4d0c8ee32d7e0a2"]]}]"#;
|
|
|
+ let message: Result<Message, _> = serde_json::from_str(json);
|
|
|
+ assert!(message.is_ok());
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn parse_unexpected_tag() {
|
|
|
+ let json = r#"["EVENT","f4e62282fda9c7d93a6e3b03fd1f1a3a34936f74584b0e021edf9659fd7da9d6",{"content":"1678682368","created_at":1678682368,"id":"7506ccd8ce4de835c61c04fd16f8489b2acb8cc052ed6730cba203188dfedf57","kind":30000,"pubkey":"228cc1e37a8fec2eee3dda3a3dbd04a60968086d8f42751a7632499d938eda8f","sig":"73ec91ee5d23a93287700f31274a57d84f46c0aa06523138c8f5b0cf2f20bd8a7db72346ecae9c717d9642cea81d72c35ea95ec615146b1640f62de5e3fbbb69","tags":[["d","chats/null/lastOpened"]]}]"#;
|
|
|
+ let message: Result<Message, _> = serde_json::from_str(json);
|
|
|
+ assert!(message.is_ok());
|
|
|
+ }
|
|
|
|
|
|
#[test]
|
|
|
fn serialize_deserialize() {
|
|
|
let json = "[\"p\",\"a0b0c0d0\"]";
|
|
|
let tag: Tag = serde_json::from_str(&json).expect("valid json");
|
|
|
- assert_eq!(tag.typ, TagType::PubKey);
|
|
|
- assert_eq!(tag.value.to_hex(), "a0b0c0d0".to_owned());
|
|
|
- assert!(tag.relayer_url.is_none());
|
|
|
- assert!(tag.extra.is_empty());
|
|
|
+ assert_eq!(
|
|
|
+ Tag::PubKey(
|
|
|
+ Addr::try_from_public_key_str(crate::types::addr::Type::Unknown, "a0b0c0d0")
|
|
|
+ .expect("valid addr"),
|
|
|
+ None,
|
|
|
+ vec![]
|
|
|
+ ),
|
|
|
+ tag
|
|
|
+ );
|
|
|
}
|
|
|
}
|