note.rs (3964B)
1 use crate::{Error, Pubkey}; 2 3 use serde::{Deserialize, Deserializer, Serialize, Serializer}; 4 use std::fmt; 5 use std::hash::{Hash, Hasher}; 6 7 #[derive(Clone, Copy, Eq, PartialEq, Hash)] 8 pub struct NoteId([u8; 32]); 9 10 impl fmt::Debug for NoteId { 11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12 write!(f, "NoteId({})", self.hex()) 13 } 14 } 15 16 static HRP_NOTE: bech32::Hrp = bech32::Hrp::parse_unchecked("note"); 17 18 impl NoteId { 19 pub fn new(bytes: [u8; 32]) -> Self { 20 NoteId(bytes) 21 } 22 23 pub fn bytes(&self) -> &[u8; 32] { 24 &self.0 25 } 26 27 pub fn hex(&self) -> String { 28 hex::encode(self.bytes()) 29 } 30 31 pub fn from_hex(hex_str: &str) -> Result<Self, Error> { 32 let evid = NoteId(hex::decode(hex_str)?.as_slice().try_into()?); 33 Ok(evid) 34 } 35 36 pub fn to_bech(&self) -> Option<String> { 37 bech32::encode::<bech32::Bech32>(HRP_NOTE, &self.0).ok() 38 } 39 40 pub fn from_bech(bech: &str) -> Option<Self> { 41 let (hrp, data) = bech32::decode(bech).ok()?; 42 43 if hrp != HRP_NOTE { 44 return None; 45 } 46 47 Some(NoteId::new(data.try_into().ok()?)) 48 } 49 50 /// Parse a NIP-19 nevent1 bech32 string and extract the event ID. 51 pub fn from_nevent_bech(bech: &str) -> Option<Self> { 52 use nostr::nips::nip19::{FromBech32, Nip19Event}; 53 let nip19_event = Nip19Event::from_bech32(bech).ok()?; 54 Some(NoteId::new(nip19_event.event_id.to_bytes())) 55 } 56 } 57 58 /// Event is the struct used to represent a Nostr event 59 #[derive(Serialize, Deserialize, Debug, Clone)] 60 pub struct Note { 61 /// 32-bytes sha256 of the the serialized event data 62 pub id: NoteId, 63 /// 32-bytes hex-encoded public key of the event creator 64 pub pubkey: Pubkey, 65 /// unix timestamp in seconds 66 pub created_at: u64, 67 /// integer 68 /// 0: NostrEvent 69 pub kind: u64, 70 /// Tags 71 pub tags: Vec<Vec<String>>, 72 /// arbitrary string 73 pub content: String, 74 /// 64-bytes signature of the sha256 hash of the serialized event data, which is the same as the "id" field 75 pub sig: String, 76 } 77 78 // Implement Hash trait 79 impl Hash for Note { 80 fn hash<H: Hasher>(&self, state: &mut H) { 81 self.id.0.hash(state); 82 } 83 } 84 85 impl PartialEq for Note { 86 fn eq(&self, other: &Self) -> bool { 87 self.id == other.id 88 } 89 } 90 91 impl Eq for Note {} 92 93 impl Note { 94 pub fn from_json(s: &str) -> Result<Self, Error> { 95 serde_json::from_str(s).map_err(Into::into) 96 } 97 98 pub fn verify(&self) -> Result<Self, Error> { 99 Err(Error::InvalidSignature) 100 } 101 102 /// This is just for serde sanity checking 103 #[allow(dead_code)] 104 pub(crate) fn new_dummy( 105 id: &str, 106 pubkey: &str, 107 created_at: u64, 108 kind: u64, 109 tags: Vec<Vec<String>>, 110 content: &str, 111 sig: &str, 112 ) -> Result<Self, Error> { 113 Ok(Note { 114 id: NoteId::from_hex(id)?, 115 pubkey: Pubkey::from_hex(pubkey)?, 116 created_at, 117 kind, 118 tags, 119 content: content.to_string(), 120 sig: sig.to_string(), 121 }) 122 } 123 } 124 125 impl std::str::FromStr for Note { 126 type Err = Error; 127 128 fn from_str(s: &str) -> Result<Self, Error> { 129 Note::from_json(s) 130 } 131 } 132 133 // Custom serialize function for Pubkey 134 impl Serialize for NoteId { 135 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 136 where 137 S: Serializer, 138 { 139 serializer.serialize_str(&self.hex()) 140 } 141 } 142 143 // Custom deserialize function for Pubkey 144 impl<'de> Deserialize<'de> for NoteId { 145 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 146 where 147 D: Deserializer<'de>, 148 { 149 let s = String::deserialize(deserializer)?; 150 NoteId::from_hex(&s).map_err(serde::de::Error::custom) 151 } 152 } 153 154 impl hashbrown::Equivalent<NoteId> for &[u8; 32] { 155 fn equivalent(&self, key: &NoteId) -> bool { 156 self.as_slice() == key.bytes() 157 } 158 }