notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

note.rs (3648B)


      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 
     51 /// Event is the struct used to represent a Nostr event
     52 #[derive(Serialize, Deserialize, Debug, Clone)]
     53 pub struct Note {
     54     /// 32-bytes sha256 of the the serialized event data
     55     pub id: NoteId,
     56     /// 32-bytes hex-encoded public key of the event creator
     57     pub pubkey: Pubkey,
     58     /// unix timestamp in seconds
     59     pub created_at: u64,
     60     /// integer
     61     /// 0: NostrEvent
     62     pub kind: u64,
     63     /// Tags
     64     pub tags: Vec<Vec<String>>,
     65     /// arbitrary string
     66     pub content: String,
     67     /// 64-bytes signature of the sha256 hash of the serialized event data, which is the same as the "id" field
     68     pub sig: String,
     69 }
     70 
     71 // Implement Hash trait
     72 impl Hash for Note {
     73     fn hash<H: Hasher>(&self, state: &mut H) {
     74         self.id.0.hash(state);
     75     }
     76 }
     77 
     78 impl PartialEq for Note {
     79     fn eq(&self, other: &Self) -> bool {
     80         self.id == other.id
     81     }
     82 }
     83 
     84 impl Eq for Note {}
     85 
     86 impl Note {
     87     pub fn from_json(s: &str) -> Result<Self, Error> {
     88         serde_json::from_str(s).map_err(Into::into)
     89     }
     90 
     91     pub fn verify(&self) -> Result<Self, Error> {
     92         Err(Error::InvalidSignature)
     93     }
     94 
     95     /// This is just for serde sanity checking
     96     #[allow(dead_code)]
     97     pub(crate) fn new_dummy(
     98         id: &str,
     99         pubkey: &str,
    100         created_at: u64,
    101         kind: u64,
    102         tags: Vec<Vec<String>>,
    103         content: &str,
    104         sig: &str,
    105     ) -> Result<Self, Error> {
    106         Ok(Note {
    107             id: NoteId::from_hex(id)?,
    108             pubkey: Pubkey::from_hex(pubkey)?,
    109             created_at,
    110             kind,
    111             tags,
    112             content: content.to_string(),
    113             sig: sig.to_string(),
    114         })
    115     }
    116 }
    117 
    118 impl std::str::FromStr for Note {
    119     type Err = Error;
    120 
    121     fn from_str(s: &str) -> Result<Self, Error> {
    122         Note::from_json(s)
    123     }
    124 }
    125 
    126 // Custom serialize function for Pubkey
    127 impl Serialize for NoteId {
    128     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    129     where
    130         S: Serializer,
    131     {
    132         serializer.serialize_str(&self.hex())
    133     }
    134 }
    135 
    136 // Custom deserialize function for Pubkey
    137 impl<'de> Deserialize<'de> for NoteId {
    138     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    139     where
    140         D: Deserializer<'de>,
    141     {
    142         let s = String::deserialize(deserializer)?;
    143         NoteId::from_hex(&s).map_err(serde::de::Error::custom)
    144     }
    145 }
    146 
    147 impl hashbrown::Equivalent<NoteId> for &[u8; 32] {
    148     fn equivalent(&self, key: &NoteId) -> bool {
    149         self.as_slice() == key.bytes()
    150     }
    151 }