@@ -49,6 +49,8 @@ pub enum Error {
49
49
/// NIP04 error
50
50
#[ cfg( feature = "nip04" ) ]
51
51
NIP04 ( nip04:: Error ) ,
52
+ /// NIP21 error
53
+ NIP21 ( nip21:: Error ) ,
52
54
/// NIP44 error
53
55
#[ cfg( all( feature = "std" , feature = "nip44" ) ) ]
54
56
NIP44 ( nip44:: Error ) ,
@@ -80,6 +82,7 @@ impl fmt::Display for Error {
80
82
Self :: NIP03 ( e) => e. fmt ( f) ,
81
83
#[ cfg( feature = "nip04" ) ]
82
84
Self :: NIP04 ( e) => e. fmt ( f) ,
85
+ Self :: NIP21 ( e) => e. fmt ( f) ,
83
86
#[ cfg( all( feature = "std" , feature = "nip44" ) ) ]
84
87
Self :: NIP44 ( e) => e. fmt ( f) ,
85
88
Self :: NIP58 ( e) => e. fmt ( f) ,
@@ -125,6 +128,12 @@ impl From<nip04::Error> for Error {
125
128
}
126
129
}
127
130
131
+ impl From < nip21:: Error > for Error {
132
+ fn from ( e : nip21:: Error ) -> Self {
133
+ Self :: NIP21 ( e)
134
+ }
135
+ }
136
+
128
137
#[ cfg( all( feature = "std" , feature = "nip44" ) ) ]
129
138
impl From < nip44:: Error > for Error {
130
139
fn from ( e : nip44:: Error ) -> Self {
@@ -1706,6 +1715,67 @@ impl EventBuilder {
1706
1715
pub fn poll_response ( response : PollResponse ) -> Self {
1707
1716
response. to_event_builder ( )
1708
1717
}
1718
+
1719
+ /// Chat message
1720
+ ///
1721
+ /// <https://github.com/nostr-protocol/nips/blob/master/C7.md>
1722
+ #[ inline]
1723
+ pub fn chat_message < S > ( content : S ) -> Self
1724
+ where
1725
+ S : Into < String > ,
1726
+ {
1727
+ Self :: new ( Kind :: ChatMessage , content)
1728
+ }
1729
+
1730
+ /// Chat message reply
1731
+ ///
1732
+ /// <https://github.com/nostr-protocol/nips/blob/master/C7.md>
1733
+ pub fn chat_message_reply < S > (
1734
+ content : S ,
1735
+ reply_to : & Event ,
1736
+ relay_url : Option < RelayUrl > ,
1737
+ ) -> Result < Self , Error >
1738
+ where
1739
+ S : Into < String > ,
1740
+ {
1741
+ let mut content = content. into ( ) ;
1742
+
1743
+ if !has_nostr_event_uri ( & content, & reply_to. id ) {
1744
+ let nevent = Nip19Event {
1745
+ event_id : reply_to. id ,
1746
+ author : None ,
1747
+ kind : None ,
1748
+ relays : relay_url. clone ( ) . into_iter ( ) . collect ( ) ,
1749
+ } ;
1750
+ content = format ! ( "{}\n {content}" , nevent. to_nostr_uri( ) ?) ;
1751
+ }
1752
+
1753
+ Ok (
1754
+ Self :: new ( Kind :: ChatMessage , content) . tag ( Tag :: from_standardized_without_cell (
1755
+ TagStandard :: Quote {
1756
+ event_id : reply_to. id ,
1757
+ relay_url,
1758
+ public_key : Some ( reply_to. pubkey ) ,
1759
+ } ,
1760
+ ) ) ,
1761
+ )
1762
+ }
1763
+ }
1764
+
1765
+ fn has_nostr_event_uri ( content : & str , event_id : & EventId ) -> bool {
1766
+ const OPTS : NostrParserOptions = NostrParserOptions :: disable_all ( ) . nostr_uris ( true ) ;
1767
+
1768
+ let parser = NostrParser :: new ( ) . parse ( content) . opts ( OPTS ) ;
1769
+
1770
+ for token in parser. into_iter ( ) {
1771
+ if let Token :: Nostr ( nip21) = token {
1772
+ if nip21. event_id ( ) . as_ref ( ) == Some ( event_id) {
1773
+ return true ;
1774
+ }
1775
+ }
1776
+ }
1777
+
1778
+ false
1709
1779
}
1710
1780
1711
1781
#[ cfg( test) ]
0 commit comments