Skip to content

Commit 1c66cfd

Browse files
committed
nostr: add nip25::ReactionTarget and update EventBuilder::reaction
Fixes https://gitworkshop.dev/yukikishimoto.com/rust-nostr/issues/note1065nmxmzlympsvzexddma4czwnuvxygfpe9akyr0ulujv2zhgfkqkvw8kv Pull-Request: #1063 Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 762b6f7 commit 1c66cfd

File tree

5 files changed

+83
-29
lines changed

5 files changed

+83
-29
lines changed

crates/nostr/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
- Set `payment_hash` as optional in `MakeInvoiceResponse` (https://github.com/rust-nostr/nostr/pull/1045)
3131
- Remove `hex` module (https://github.com/rust-nostr/nostr/pull/1051)
3232
- Use `Cow` for non-copy fields in `nip22::CommentTarget` enum (https://github.com/rust-nostr/nostr/pull/1053)
33+
- Change `EventBuilder::reaction` args (https://github.com/rust-nostr/nostr/pull/1063)
34+
- Remove `EventBuilder::reaction_extended` (https://github.com/rust-nostr/nostr/pull/1063)
3335

3436
### Added
3537

@@ -45,6 +47,7 @@
4547
- Add `CommentTarget::as_vec` to convert the comment target into a vector of tags (https://github.com/rust-nostr/nostr/pull/1038)
4648
- Support NIP-A0 (Voice Messages) (https://github.com/rust-nostr/nostr/pull/1032)
4749
- Add `hex` dependency (https://github.com/rust-nostr/nostr/pull/1051)
50+
- Add `nip25::ReactionTarget` (https://github.com/rust-nostr/nostr/pull/1063)
4851

4952
### Changed
5053

crates/nostr/src/event/builder.rs

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -691,38 +691,11 @@ impl EventBuilder {
691691
///
692692
/// <https://github.com/nostr-protocol/nips/blob/master/25.md>
693693
#[inline]
694-
pub fn reaction<S>(event: &Event, reaction: S) -> Self
694+
pub fn reaction<S>(target: ReactionTarget, reaction: S) -> Self
695695
where
696696
S: Into<String>,
697697
{
698-
Self::reaction_extended(event.id, event.pubkey, Some(event.kind), reaction)
699-
}
700-
701-
/// Add reaction (like/upvote, dislike/downvote or emoji) to an event
702-
///
703-
/// <https://github.com/nostr-protocol/nips/blob/master/25.md>
704-
pub fn reaction_extended<S>(
705-
event_id: EventId,
706-
public_key: PublicKey,
707-
kind: Option<Kind>,
708-
reaction: S,
709-
) -> Self
710-
where
711-
S: Into<String>,
712-
{
713-
let mut tags: Vec<Tag> = Vec::with_capacity(2 + usize::from(kind.is_some()));
714-
715-
tags.push(Tag::event(event_id));
716-
tags.push(Tag::public_key(public_key));
717-
718-
if let Some(kind) = kind {
719-
tags.push(Tag::from_standardized_without_cell(TagStandard::Kind {
720-
kind,
721-
uppercase: false,
722-
}));
723-
}
724-
725-
Self::new(Kind::Reaction, reaction).tags(tags)
698+
Self::new(Kind::Reaction, reaction).tags(target.into_tags())
726699
}
727700

728701
/// Create a new channel

crates/nostr/src/nips/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod nip17;
2222
pub mod nip19;
2323
pub mod nip21;
2424
pub mod nip22;
25+
pub mod nip25;
2526
pub mod nip34;
2627
pub mod nip35;
2728
pub mod nip38;

crates/nostr/src/nips/nip25.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (c) 2022-2023 Yuki Kishimoto
2+
// Copyright (c) 2023-2025 Rust Nostr Developers
3+
// Distributed under the MIT software license
4+
5+
//! NIP25: Reactions
6+
//!
7+
//! <https://github.com/nostr-protocol/nips/blob/master/25.md>
8+
9+
use super::nip01::Coordinate;
10+
use crate::{Event, EventId, Kind, PublicKey, RelayUrl, Tag, TagStandard, Tags};
11+
12+
/// Reaction target
13+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14+
pub struct ReactionTarget {
15+
/// Event ID
16+
pub event_id: EventId,
17+
/// Public Key
18+
pub public_key: PublicKey,
19+
/// Coordinate
20+
pub coordinate: Option<Coordinate>,
21+
/// Kind
22+
pub kind: Option<Kind>,
23+
/// Relay hint
24+
pub relay_hint: Option<RelayUrl>,
25+
}
26+
27+
impl ReactionTarget {
28+
/// Construct a new reaction target
29+
pub fn new(event: &Event, relay_hint: Option<RelayUrl>) -> Self {
30+
Self {
31+
event_id: event.id,
32+
public_key: event.pubkey,
33+
coordinate: event.coordinate().map(|c| c.into_owned()),
34+
kind: Some(event.kind),
35+
relay_hint,
36+
}
37+
}
38+
39+
pub(crate) fn into_tags(self) -> Tags {
40+
let mut tags: Tags = Tags::with_capacity(
41+
2 + usize::from(self.coordinate.is_some()) + usize::from(self.kind.is_some()),
42+
);
43+
44+
// Serialization order: keep the `e` and `a` tags together, followed by the `p` and other tags.
45+
46+
tags.push(Tag::from_standardized_without_cell(TagStandard::Event {
47+
event_id: self.event_id,
48+
relay_url: self.relay_hint.clone(),
49+
public_key: Some(self.public_key),
50+
marker: None,
51+
uppercase: false,
52+
}));
53+
54+
if let Some(coordinate) = self.coordinate {
55+
tags.push(Tag::coordinate(coordinate, self.relay_hint.clone()));
56+
}
57+
58+
tags.push(Tag::from_standardized_without_cell(
59+
TagStandard::PublicKey {
60+
public_key: self.public_key,
61+
relay_url: self.relay_hint,
62+
alias: None,
63+
uppercase: false,
64+
},
65+
));
66+
67+
if let Some(kind) = self.kind {
68+
tags.push(Tag::from_standardized_without_cell(TagStandard::Kind {
69+
kind,
70+
uppercase: false,
71+
}));
72+
}
73+
74+
tags
75+
}
76+
}

crates/nostr/src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub use crate::nips::nip17::{self, *};
4444
pub use crate::nips::nip19::{self, *};
4545
pub use crate::nips::nip21::{self, *};
4646
pub use crate::nips::nip22::{self, *};
47+
pub use crate::nips::nip25::{self, *};
4748
pub use crate::nips::nip34::{self, *};
4849
pub use crate::nips::nip35::{self, *};
4950
pub use crate::nips::nip38::{self, *};

0 commit comments

Comments
 (0)