Skip to content

Commit 9c32217

Browse files
committed
Merge #101: add support for NIP-58 Badges
2 parents 7da104f + 0915d9c commit 9c32217

File tree

3 files changed

+551
-12
lines changed

3 files changed

+551
-12
lines changed

crates/nostr/src/event/tag.rs

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ pub enum TagKind {
171171
Title,
172172
/// Image (NIP23)
173173
Image,
174+
/// Thumbnail
175+
Thumb,
174176
/// Summary (NIP23)
175177
Summary,
176178
/// PublishedAt (NIP23)
@@ -187,6 +189,8 @@ pub enum TagKind {
187189
Amount,
188190
/// Lnurl (NIP57)
189191
Lnurl,
192+
/// Name tag
193+
Name,
190194
/// Custom tag kind
191195
Custom(String),
192196
}
@@ -210,6 +214,7 @@ impl fmt::Display for TagKind {
210214
Self::Challenge => write!(f, "challenge"),
211215
Self::Title => write!(f, "title"),
212216
Self::Image => write!(f, "image"),
217+
Self::Thumb => write!(f, "thumb"),
213218
Self::Summary => write!(f, "summary"),
214219
Self::PublishedAt => write!(f, "published_at"),
215220
Self::Description => write!(f, "description"),
@@ -218,6 +223,7 @@ impl fmt::Display for TagKind {
218223
Self::Relays => write!(f, "relays"),
219224
Self::Amount => write!(f, "amount"),
220225
Self::Lnurl => write!(f, "lnurl"),
226+
Self::Name => write!(f, "name"),
221227
Self::Custom(tag) => write!(f, "{tag}"),
222228
}
223229
}
@@ -246,6 +252,7 @@ where
246252
"challenge" => Self::Challenge,
247253
"title" => Self::Title,
248254
"image" => Self::Image,
255+
"thumb" => Self::Thumb,
249256
"summary" => Self::Summary,
250257
"published_at" => Self::PublishedAt,
251258
"description" => Self::Description,
@@ -254,6 +261,7 @@ where
254261
"relays" => Self::Relays,
255262
"amount" => Self::Amount,
256263
"lnurl" => Self::Lnurl,
264+
"name" => Self::Name,
257265
tag => Self::Custom(tag.to_string()),
258266
}
259267
}
@@ -276,7 +284,7 @@ pub enum Tag {
276284
kind: Kind,
277285
public_key: XOnlyPublicKey,
278286
identifier: String,
279-
relay_url: UncheckedUrl,
287+
relay_url: Option<UncheckedUrl>,
280288
},
281289
Relay(UncheckedUrl),
282290
ContactList {
@@ -300,14 +308,16 @@ pub enum Tag {
300308
Subject(String),
301309
Challenge(String),
302310
Title(String),
303-
Image(String),
311+
Image(String, Option<(u64, u64)>),
312+
Thumb(String, Option<(u64, u64)>),
304313
Summary(String),
305314
Description(String),
306315
Bolt11(String),
307316
Preimage(String),
308317
Relays(Vec<UncheckedUrl>),
309318
Amount(u64),
310319
Lnurl(String),
320+
Name(String),
311321
PublishedAt(Timestamp),
312322
}
313323

@@ -349,13 +359,15 @@ impl Tag {
349359
Tag::Challenge(..) => TagKind::Challenge,
350360
Tag::Title(..) => TagKind::Title,
351361
Tag::Image(..) => TagKind::Image,
362+
Tag::Thumb(..) => TagKind::Thumb,
352363
Tag::Summary(..) => TagKind::Summary,
353364
Tag::PublishedAt(..) => TagKind::PublishedAt,
354365
Tag::Description(..) => TagKind::Description,
355366
Tag::Bolt11(..) => TagKind::Bolt11,
356367
Tag::Preimage(..) => TagKind::Preimage,
357368
Tag::Relays(..) => TagKind::Relays,
358369
Tag::Amount(..) => TagKind::Amount,
370+
Tag::Name(..) => TagKind::Name,
359371
Tag::Lnurl(..) => TagKind::Lnurl,
360372
}
361373
}
@@ -390,7 +402,21 @@ where
390402
}
391403
} else if tag_len == 2 {
392404
let content: &str = &tag[1];
405+
393406
match tag_kind {
407+
TagKind::A => {
408+
let kpi: Vec<&str> = tag[1].split(':').collect();
409+
if kpi.len() == 3 {
410+
Ok(Self::A {
411+
kind: Kind::from_str(kpi[0])?,
412+
public_key: XOnlyPublicKey::from_str(kpi[1])?,
413+
identifier: kpi[2].to_string(),
414+
relay_url: None,
415+
})
416+
} else {
417+
Err(Error::InvalidLength)
418+
}
419+
}
394420
TagKind::P => Ok(Self::PubKey(XOnlyPublicKey::from_str(content)?, None)),
395421
TagKind::E => Ok(Self::Event(EventId::from_hex(content)?, None, None)),
396422
TagKind::R => Ok(Self::Reference(content.to_string())),
@@ -405,14 +431,16 @@ where
405431
TagKind::Subject => Ok(Self::Subject(content.to_string())),
406432
TagKind::Challenge => Ok(Self::Challenge(content.to_string())),
407433
TagKind::Title => Ok(Self::Title(content.to_string())),
408-
TagKind::Image => Ok(Self::Image(content.to_string())),
434+
TagKind::Image => Ok(Self::Image(content.to_string(), None)),
435+
TagKind::Thumb => Ok(Self::Thumb(content.to_string(), None)),
409436
TagKind::Summary => Ok(Self::Summary(content.to_string())),
410437
TagKind::PublishedAt => Ok(Self::PublishedAt(Timestamp::from_str(content)?)),
411438
TagKind::Description => Ok(Self::Description(content.to_string())),
412439
TagKind::Bolt11 => Ok(Self::Bolt11(content.to_string())),
413440
TagKind::Preimage => Ok(Self::Preimage(content.to_string())),
414441
TagKind::Amount => Ok(Self::Amount(content.parse()?)),
415442
TagKind::Lnurl => Ok(Self::Lnurl(content.to_string())),
443+
TagKind::Name => Ok(Self::Name(content.to_string())),
416444
_ => Ok(Self::Generic(tag_kind, vec![content.to_string()])),
417445
}
418446
} else if tag_len == 3 {
@@ -457,12 +485,32 @@ where
457485
kind: Kind::from_str(kpi[0])?,
458486
public_key: XOnlyPublicKey::from_str(kpi[1])?,
459487
identifier: kpi[2].to_string(),
460-
relay_url: UncheckedUrl::from(tag[2].clone()),
488+
relay_url: Some(UncheckedUrl::from(tag[2].clone())),
461489
})
462490
} else {
463491
Err(Error::InvalidLength)
464492
}
465493
}
494+
TagKind::Image => {
495+
let image = tag[1].clone();
496+
let dimensions: Vec<&str> = tag[2].split('x').collect();
497+
if dimensions.len() == 2 {
498+
let (width, height) = (dimensions[0], dimensions[1]);
499+
Ok(Self::Image(image, Some((width.parse()?, height.parse()?))))
500+
} else {
501+
Err(Error::InvalidLength)
502+
}
503+
}
504+
TagKind::Thumb => {
505+
let thumb = tag[1].clone();
506+
let dimensions: Vec<&str> = tag[2].split('x').collect();
507+
if dimensions.len() == 2 {
508+
let (width, height) = (dimensions[0], dimensions[1]);
509+
Ok(Self::Thumb(thumb, Some((width.parse()?, height.parse()?))))
510+
} else {
511+
Err(Error::InvalidLength)
512+
}
513+
}
466514
_ => Ok(Self::Generic(tag_kind, tag[1..].to_vec())),
467515
}
468516
} else if tag_len == 4 {
@@ -536,11 +584,16 @@ impl From<Tag> for Vec<String> {
536584
public_key,
537585
identifier,
538586
relay_url,
539-
} => vec![
540-
TagKind::A.to_string(),
541-
format!("{}:{public_key}:{identifier}", kind.as_u64()),
542-
relay_url.to_string(),
543-
],
587+
} => {
588+
let mut vec = vec![
589+
TagKind::A.to_string(),
590+
format!("{}:{public_key}:{identifier}", kind.as_u64()),
591+
];
592+
if let Some(relay) = relay_url {
593+
vec.push(relay.to_string());
594+
}
595+
vec
596+
}
544597
Tag::Relay(url) => vec![TagKind::Relay.to_string(), url.to_string()],
545598
Tag::ContactList {
546599
pk,
@@ -580,7 +633,22 @@ impl From<Tag> for Vec<String> {
580633
Tag::Subject(sub) => vec![TagKind::Subject.to_string(), sub],
581634
Tag::Challenge(challenge) => vec![TagKind::Challenge.to_string(), challenge],
582635
Tag::Title(title) => vec![TagKind::Title.to_string(), title],
583-
Tag::Image(image) => vec![TagKind::Image.to_string(), image],
636+
Tag::Image(image, dimensions) => match dimensions {
637+
None => vec![TagKind::Image.to_string(), image],
638+
Some((width, height)) => vec![
639+
TagKind::Image.to_string(),
640+
image,
641+
format!("{}x{}", height, width),
642+
],
643+
},
644+
Tag::Thumb(thumb, dimensions) => match dimensions {
645+
None => vec![TagKind::Thumb.to_string(), thumb],
646+
Some((width, height)) => vec![
647+
TagKind::Thumb.to_string(),
648+
thumb,
649+
format!("{}x{}", height, width),
650+
],
651+
},
584652
Tag::Summary(summary) => vec![TagKind::Summary.to_string(), summary],
585653
Tag::PublishedAt(timestamp) => {
586654
vec![TagKind::PublishedAt.to_string(), timestamp.to_string()]
@@ -601,6 +669,9 @@ impl From<Tag> for Vec<String> {
601669
Tag::Amount(amount) => {
602670
vec![TagKind::Amount.to_string(), amount.to_string()]
603671
}
672+
Tag::Name(name) => {
673+
vec![TagKind::Name.to_string(), name]
674+
}
604675
Tag::Lnurl(lnurl) => {
605676
vec![TagKind::Lnurl.to_string(), lnurl]
606677
}
@@ -846,7 +917,7 @@ mod tests {
846917
"a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919"
847918
)?,
848919
identifier: String::from("ipsum"),
849-
relay_url: UncheckedUrl::from("wss://relay.nostr.org")
920+
relay_url: Some(UncheckedUrl::from_str("wss://relay.nostr.org")?)
850921
}
851922
.as_vec()
852923
);
@@ -1067,7 +1138,7 @@ mod tests {
10671138
"a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919"
10681139
)?,
10691140
identifier: String::from("ipsum"),
1070-
relay_url: UncheckedUrl::from("wss://relay.nostr.org")
1141+
relay_url: Some(UncheckedUrl::from_str("wss://relay.nostr.org")?)
10711142
}
10721143
);
10731144

crates/nostr/src/nips/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ pub mod nip21;
2121
pub mod nip26;
2222
#[cfg(feature = "nip46")]
2323
pub mod nip46;
24+
pub mod nip58;
2425
pub mod nip65;

0 commit comments

Comments
 (0)