1use serde::de::Error as DeError;
2use serde::de::{Deserializer, Visitor};
3use serde::ser::Serializer;
4use serde::{Deserialize, Serialize};
5#[cfg(feature = "speedy")]
6use speedy::{Context, Readable, Reader, Writable, Writer};
7use std::convert::From;
8use std::fmt;
9
10macro_rules! define_event_kinds {
11 ($($comment:expr, $display:expr, $name:ident = $value:expr),*) => {
12 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
14 #[repr(u32)]
15 pub enum EventKind {
16 $(
17 #[doc = $comment]
18 $name = $value,
19 )*
20 JobRequest(u32),
22 JobResult(u32),
24 GroupControl(u32),
26 Replaceable(u32),
28 Ephemeral(u32),
30 GroupMetadata(u32),
32 Other(u32),
34 }
35
36 static WELL_KNOWN_KINDS: &[EventKind] = &[
37 $($name,)*
38 ];
39
40 impl fmt::Display for EventKind {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 match *self {
43 $($name => write!(f, $display),)*
44 JobRequest(u) => write!(f, "Job Request ({})", u),
45 JobResult(u) => write!(f, "Job Result ({})", u),
46 GroupControl(u) => write!(f, "Group Control ({})", u),
47 Replaceable(u) => write!(f, "Replaceable ({})", u),
48 Ephemeral(u) => write!(f, "Ephemeral ({})", u),
49 GroupMetadata(u) => write!(f, "Group Metadata ({})", u),
50 Other(u) => write!(f, "Other ({})", u),
51 }
52 }
53 }
54
55 impl From<u32> for EventKind {
56 fn from(u: u32) -> Self {
57 match u {
58 $($value => $name,)*
59 x if (5_000..5_999).contains(&x) => JobRequest(x),
60 x if (6_000..6_999).contains(&x) => JobResult(x),
61 x if (9_000..9_030).contains(&x) => GroupControl(x),
62 x if (10_000..20_000).contains(&x) => Replaceable(x),
63 x if (20_000..30_000).contains(&x) => Ephemeral(x),
64 x if (39_000..39_009).contains(&x) => GroupMetadata(x),
65 x => Other(x),
66 }
67 }
68 }
69
70 impl From<EventKind> for u32 {
71 fn from(e: EventKind) -> u32 {
72 match e {
73 $($name => $value,)*
74 JobRequest(u) => u,
75 JobResult(u) => u,
76 GroupControl(u) => u,
77 Replaceable(u) => u,
78 Ephemeral(u) => u,
79 GroupMetadata(u) => u,
80 Other(u) => u,
81 }
82 }
83 }
84 };
85}
86
87define_event_kinds!(
88 "Event sets the metadata associated with a public key (NIP-01)",
89 "User Metadata",
90 Metadata = 0,
91
92 "Event is a text note (NIP-01)",
93 "Short Text Note",
94 TextNote = 1,
95
96 "Event contains a relay URL which the author recommends",
97 "Recommend Relay",
98 RecommendRelay = 2,
99
100 "Event contains tags which represent the authors contacts including the authors pet names for them (NIP-02)",
101 "Follows",
102 ContactList = 3,
103
104 "Event is an encrypted direct message (NIP-04)",
105 "Encrypted Direct Messages",
106 EncryptedDirectMessage = 4,
107
108 "Event is an authors request to delete previous events (NIP-09)",
109 "Event Deletion Request",
110 EventDeletion = 5,
111
112 "Repost (NIP-18)",
113 "Repost",
114 Repost = 6,
115
116 "Event is a reaction to a `TextNote` event (NIP-25)",
117 "Reaction",
118 Reaction = 7,
119
120 "Badge Award (NIP-58)",
121 "Badge Award",
122 BadgeAward = 8,
123
124 "Group Chat Message (NIP-29)",
125 "Group Chat Message",
126 GroupChatMessage = 9,
127
128 "Group Chat Threaded Reply (NIP-29)",
129 "Group Chat Threaded Reply",
130 GroupChatThreadedReply = 10,
131
132 "Group Chat Thread (NIP-29)",
133 "Group Chat Thread",
134 GroupChatThread = 11,
135
136 "Group Chat Reply (NIP-29)",
137 "Group Chat Reply",
138 GroupChatReply = 12,
139
140 "Seal (NIP-59 PR 716)",
141 "Seal",
142 Seal = 13,
143
144 "Chat Message / DM (NIP-24 PR 686)",
145 "Direct Message",
146 DmChat = 14,
147
148 "Generic Repost (NIP-18)",
149 "Generic Repost",
150 GenericRepost = 16,
151
152 "Reaction to a website (NIP-25)",
153 "Reaction to a website",
154 ReactionToWebsite = 17,
155
156 "Picture (NIP-68)",
157 "Picture",
158 Picture = 20,
159
160 "Event creates a public channel (NIP-28)",
161 "Channel Creation",
162 ChannelCreation = 40,
163
164 "Event sets metadata on a public channel (NIP-28)",
165 "Channel Metadata",
166 ChannelMetadata = 41,
167
168 "Event creates a message on a public channel (NIP-28)",
169 "Channel Message",
170 ChannelMessage = 42,
171
172 "Event hides a message on a public channel (NIP-28)",
173 "Channel Hide Message",
174 ChannelHideMessage = 43,
175
176 "Event mutes a user on a public channel (NIP-28)",
177 "Channel Mute User",
178 ChannelMuteUser = 44,
179
180 "Request to Vanish (NIP-62)",
181 "Request to Vanish",
182 RequestToVanish = 62,
183
184 "Chess (PGN) (NIP-64)",
185 "Chess (PGN)",
186 ChessPgn = 64,
187
188 "Wiki article merge requests (NIP-54)",
189 "Wiki Merge Requests",
190 WikiMergeRequest = 818,
191
192 "Bid (NIP-15)",
193 "Bid",
194 Bid = 1021,
195
196 "Bid Confirmation (NIP-15)",
197 "Bid Confirmation",
198 BidConfirmation = 1022,
199
200 "Open Timestamps (NIP-03)",
201 "Open Timestamp",
202 Timestamp = 1040,
203
204 "Gift Wrap (NIP-59 PR 716)",
205 "Gift Wrap",
206 GiftWrap = 1059,
207
208 "File Metadata (NIP-94)",
209 "File Metadata",
210 FileMetadata = 1063,
211
212 "Comment (NIP-22 PR #1233)" ,
213 "Comment",
214 Comment = 1111,
215
216 "Live Chat Message (NIP-53)",
217 "Live Chat Message",
218 LiveChatMessage = 1311,
219
220 "Git Patches (NIP-34)",
221 "Git Patch",
222 Patches = 1617,
223
224 "Git Issue (NIP-34)",
225 "Git Issue",
226 GitIssue = 1621,
227
228 "Replies (NIP-34)",
229 "Git Reply",
230 GitReply = 1622,
231
232 "Status Open (NIP-34)",
233 "Git Status Open",
234 GitStatusOpen = 1630,
235
236 "Status Applied (NIP-34)",
237 "Git Status Applied",
238 GitStatusApplied = 1631,
239
240 "Status Closed (NIP-34)",
241 "Git Status Closed",
242 GitStatusClosed = 1632,
243
244 "Status Draft (NIP-34)",
245 "Git Status Draft",
246 GitStatusDraft = 1633,
247
248 "Problem Tracker (nostrocket-1971)",
249 "Problem Tracker",
250 ProblemTracker = 1971,
251
252 "Reporting (NIP-56)",
253 "Reporting",
254 Reporting = 1984,
255
256 "Label (NIP-32)",
257 "Label",
258 Label = 1985,
259
260 "Relay reviews",
261 "Relay reviews",
262 RelayReviews = 1986,
263
264 "AI Embeddings",
265 "AI Embeddings",
266 AiEmbeddings = 1987,
267
268 "Torrent",
269 "Torrent",
270 Torrent = 2003,
271
272 "Torrent Comment",
273 "Torrent Comment",
274 TorrentComment = 2004,
275
276 "Coinjoin Pool",
277 "Coinjoin Pool",
278 CoinjoinPool = 2022,
279
280 "Community Post Approval (NIP-72)",
281 "Community Post Approval",
282 CommunityPostApproval = 4550,
283
284 "Job Feedback (NIP-90)",
285 "Job Feedback",
286 JobFeedback = 7000,
287
288 "Zap Goal (NIP-75)",
289 "Zap Goal",
290 ZapGoal = 9041,
291
292 "Tidal Login",
293 "Tidal Login",
294 TidalLogin = 9467,
295
296 "Zap Request",
297 "Zap Request",
298 ZapRequest = 9734,
299
300 "Zap",
301 "Zap",
302 Zap = 9735,
303
304 "Highlights (NIP-84)",
305 "Highlights",
306 Highlights = 9802,
307
308 "Mute List (NIP-51)",
309 "Mute List",
310 MuteList = 10000,
311
312 "Pin List (NIP-51)",
313 "Pin List",
314 PinList = 10001,
315
316 "Relay List Metadata (NIP-65)",
317 "Relay List Metadata",
318 RelayList = 10002,
319
320 "Bookmarks List (NIP-51)",
321 "Bookmarks List",
322 BookmarkList = 10003,
323
324 "Communities List (NIP-51)",
325 "Communities List",
326 CommunityList = 10004,
327
328 "Public Chats List (NIP-51)",
329 "Public Chats List",
330 PublicChatsList = 10005,
331
332 "Blocked Relays List (NIP-51)",
333 "Blocked Relays List",
334 BlockedRelaysList = 10006,
335
336 "Search Relays List (NIP-51)",
337 "Search Relays List",
338 SearchRelaysList = 10007,
339
340 "User Groups (NIP-51, NIP-29)",
341 "User Groups",
342 UserGroups = 10009,
343
344 "Interests List (NIP-51)",
345 "Interests List",
346 InterestsList = 10015,
347
348 "User Emoji List (NIP-51)",
349 "User Emoji List",
350 UserEmojiList = 10030,
351
352 "Relay list to receive DMs (NIP-17)",
353 "DM Relay List",
354 DmRelayList = 10050,
355
356 "User Server List",
357 "User Server List",
358 UserServerList = 10063,
359
360 "File storage server list (NIP-96)",
361 "File Storage Server List",
362 FileStorageServerList = 10096,
363
364 "Wallet Info (NIP-47)",
365 "Wallet Info",
366 WalletInfo = 13194,
367
368 "Lightning Pub RPC (Lightning.Pub)",
369 "Lightning Pub RPC",
370 LightningPubRpc = 21000,
371
372 "Client Authentication (NIP-42)",
373 "Client Authentication",
374 Auth = 22242,
375
376 "Wallet Request (NIP-47)",
377 "Wallet Request",
378 WalletRequest = 23194,
379
380 "Wallet Response (NIP-47)",
381 "Wallet Response",
382 WalletResponse = 23195,
383
384 "Nostr Connect (NIP-46)",
385 "Nostr Connect",
386 NostrConnect = 24133,
387
388 "Blobs stored on mediaservers (Blossom)",
389 "Blossom",
390 Blossom = 24242,
391
392 "HTTP Auth (NIP-98)",
393 "HTTP Auth",
394 HttpAuth = 27235,
395
396 "Categorized People List (NIP-51)",
397 "Follow Sets",
398 FollowSets = 30000,
399
400 "Categorized Bookmark List (NIP-51)",
401 "Generic Lists",
402 GenericSets = 30001,
403
404 "Relay Sets (NIP-51)",
405 "Relay Sets",
406 RelaySets = 30002,
407
408 "Bookmark Sets (NIP-51)",
409 "Bookmark Sets",
410 BookmarkSets = 30003,
411
412 "Curation Sets (NIP-51)",
413 "Curation Sets",
414 CurationSets = 30004,
415
416 "Video Sets (NIP-51)",
417 "Video Sets",
418 VideoSets = 30005,
419
420 "Kind Mute Sets (NIP-51)",
421 "Kind Mute Sets",
422 KindMuteSets = 30007,
423
424 "Profile Badges (NIP-58)",
425 "Profile Badges",
426 ProfileBadges = 30008,
427
428 "Badge Definition (NIP-58)",
429 "Badge Definition",
430 BadgeDefinition = 30009,
431
432 "Interest Sets (NIP-51)",
433 "Interest Sets",
434 InterestSets = 30015,
435
436 "Create or update a stall (NIP-15)",
437 "Create Or Update Stall",
438 CreateUpdateStall = 30017,
439
440 "Create or update a product (NIP-15)",
441 "Create Or Update Product",
442 CreateUpdateProduct = 30018,
443
444 "Marketplace UI/UX (NIP-15)",
445 "Marketplace UI/UX",
446 MarketplaceUi = 30019,
447
448 "Product sold as auction (NIP-15)",
449 "Product Sold As Auction",
450 ProductSoldAuction = 30020,
451
452 "Long-form Content (NIP-23)",
453 "Long-form Content",
454 LongFormContent = 30023,
455
456 "Draft Long-form Content (NIP-23)",
457 "Draft Long-form Content",
458 DraftLongFormContent = 30024,
459
460 "Emoji Sets (NIP-51)",
461 "Emoji Sets",
462 EmojiSets = 30030,
463
464 "Modular Article Header",
465 "Modular Article Header",
466 ModularArticleHedaer = 30040,
467
468 "Modular Article Content",
469 "Modular Article Content",
470 ModularArticleContent = 30041,
471
472 "Release artifact sets (NIP-51)",
473 "Release Artifact Sets",
474 ReleaseArtifactSets = 30063,
475
476 "Application Specific Data, (NIP-78)",
477 "Application Specific Data",
478 AppSpecificData = 30078,
479
480 "Live Event (NIP-53)",
481 "Live Event",
482 LiveEvent = 30311,
483
484 "User Status (NIP-315 PR 737)",
485 "User Statuses",
486 UserStatus = 30315,
487
488 "Classified Listing (NIP-99)",
489 "Classified Listing",
490 ClassifiedListing = 30402,
491
492 "Draft Classified Listing (NIP-99)",
493 "Draft Classified Listing",
494 DraftClassifiedListing = 30403,
495
496 "Repository Announcement (NIP-34)",
497 "Repository Announcement",
498 RepositoryAnnouncement = 30617,
499
500 "Repository State Announcement (NIP-34)",
501 "Repository State Announcement",
502 RepositoryStateAnnouncement = 30618,
503
504 "Wiki Article (NIP-54)",
505 "Wiki Article",
506 WikiArticle = 30818,
507
508 "Redirects",
509 "Redirects",
510 Redirects = 30819,
511
512 "Link Set",
513 "Link Set",
514 LinkSet = 31388,
515
516 "Feed",
517 "Feed",
518 Feed = 31890,
519
520 "Date-Based Calendar Event (NIP-52)",
521 "Date-Based Calendar Event",
522 DateBasedCalendarEvent = 31922,
523
524 "Time-Based Calendar Event (NIP-52)",
525 "Time-Based Calendar Event",
526 TimeBasedCalendarEvent = 31923,
527
528 "Calendar (NIP-52)",
529 "Calendar",
530 Calendar = 31924,
531
532 "Calendar Event RSVP (NIP-52)",
533 "Calendar Event RSVP",
534 CalendarEventRsvp = 31925,
535
536 "Handler Recommendation (NIP-89)",
537 "Handler Recommendation",
538 HandlerRecommendation = 31989,
539
540 "Handler Information (NIP-89)",
541 "Handler Information",
542 HandlerInformation = 31990,
543
544 "Video Event",
545 "Video Event",
546 VideoEvent = 34235,
547
548 "Short-form Portrait Video Event",
549 "Short-Form Portrait Video Event",
550 ShortFormPortraitVideoEvent = 34236,
551
552 "Video View Event",
553 "Video View Event",
554 VideoViewEvent = 34237,
555
556 "Community Definition (NIP-72)",
557 "Community Definition",
558 CommunityDefinition = 34550
559);
560
561use EventKind::*;
562
563impl EventKind {
564 #[allow(dead_code)]
566 pub(crate) fn mock() -> EventKind {
567 TextNote
568 }
569
570 pub fn is_job_request(&self) -> bool {
572 let u: u32 = From::from(*self);
573 (5000..=5999).contains(&u)
574 }
575
576 pub fn is_job_result(&self) -> bool {
578 let u: u32 = From::from(*self);
579 (6000..=6999).contains(&u)
580 }
581
582 pub fn is_replaceable(&self) -> bool {
585 match *self {
586 Metadata => true, ContactList => true, _ => {
589 let u: u32 = From::from(*self);
590 (10000..=19999).contains(&u) || (30000..=39999).contains(&u)
591 }
592 }
593 }
594
595 pub fn is_ephemeral(&self) -> bool {
597 let u: u32 = From::from(*self);
598 (20000..=29999).contains(&u)
599 }
600
601 pub fn is_parameterized_replaceable(&self) -> bool {
603 let u: u32 = From::from(*self);
604 (30000..=39999).contains(&u)
605 }
606
607 #[inline]
609 pub fn is_addressable(&self) -> bool {
610 self.is_parameterized_replaceable()
611 }
612
613 pub fn is_feed_related(&self) -> bool {
615 self.is_feed_displayable() || self.augments_feed_related()
616 }
617
618 pub fn is_feed_displayable(&self) -> bool {
620 matches!(
621 *self,
622 TextNote
623 | GroupChatMessage
624 | GroupChatThreadedReply
625 | GroupChatThread
626 | GroupChatReply
627 | EncryptedDirectMessage
628 | Repost
629 | DmChat
630 | GenericRepost
631 | Picture
632 | ChannelMessage
633 | FileMetadata
634 | Comment
635 | LiveChatMessage
636 | Patches
637 | GitIssue
638 | GitReply
639 | GitStatusOpen
640 | GitStatusApplied
641 | GitStatusClosed
642 | GitStatusDraft
643 | LongFormContent
644 | DraftLongFormContent
645 )
646 }
647
648 pub fn is_textual(&self) -> bool {
650 matches!(
651 *self,
652 TextNote
653 | GroupChatMessage
654 | GroupChatThreadedReply
655 | GroupChatThread
656 | GroupChatReply
657 | ChannelMessage
663 | Comment
664 | LiveChatMessage )
671 }
672
673 pub fn is_direct_message_related(&self) -> bool {
675 matches!(*self, EncryptedDirectMessage | DmChat | GiftWrap)
676 }
677
678 pub fn augments_feed_related(&self) -> bool {
680 matches!(
681 *self,
682 EventDeletion | Reaction | Timestamp | Label | Reporting | Zap
683 )
684 }
685
686 pub fn contents_are_encrypted(&self) -> bool {
688 matches!(
689 *self,
690 EncryptedDirectMessage
691 | MuteList
692 | PinList
693 | BookmarkList
694 | CommunityList
695 | PublicChatsList
696 | BlockedRelaysList
697 | SearchRelaysList
698 | InterestsList
699 | UserEmojiList
700 | JobRequest(_)
701 | JobResult(_)
702 | WalletRequest
703 | WalletResponse
704 | NostrConnect
705 )
706 }
707
708 pub fn iter() -> EventKindIterator {
710 EventKindIterator::new()
711 }
712}
713
714#[derive(Clone, Copy, Debug)]
716pub struct EventKindIterator {
717 pos: usize,
718}
719
720impl EventKindIterator {
721 fn new() -> EventKindIterator {
722 EventKindIterator { pos: 0 }
723 }
724}
725
726impl Iterator for EventKindIterator {
727 type Item = EventKind;
728
729 fn next(&mut self) -> Option<EventKind> {
730 if self.pos == WELL_KNOWN_KINDS.len() {
731 None
732 } else {
733 let rval = WELL_KNOWN_KINDS[self.pos];
734 self.pos += 1;
735 Some(rval)
736 }
737 }
738
739 fn size_hint(&self) -> (usize, Option<usize>) {
740 (self.pos, Some(WELL_KNOWN_KINDS.len()))
741 }
742}
743
744impl Serialize for EventKind {
745 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
746 where
747 S: Serializer,
748 {
749 let u: u32 = From::from(*self);
750 serializer.serialize_u32(u)
751 }
752}
753
754impl<'de> Deserialize<'de> for EventKind {
755 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
756 where
757 D: Deserializer<'de>,
758 {
759 deserializer.deserialize_u32(EventKindVisitor)
760 }
761}
762
763struct EventKindVisitor;
764
765impl Visitor<'_> for EventKindVisitor {
766 type Value = EventKind;
767
768 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
769 write!(f, "an unsigned number that matches a known EventKind")
770 }
771
772 fn visit_u32<E>(self, v: u32) -> Result<EventKind, E>
773 where
774 E: DeError,
775 {
776 Ok(From::<u32>::from(v))
777 }
778
779 fn visit_u64<E>(self, v: u64) -> Result<EventKind, E>
781 where
782 E: DeError,
783 {
784 Ok(From::<u32>::from(v as u32))
785 }
786}
787
788#[cfg(feature = "speedy")]
789impl<'a, C: Context> Readable<'a, C> for EventKind {
790 #[inline]
791 fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
792 let value = u32::read_from(reader)?;
793 Ok(value.into())
794 }
795
796 #[inline]
797 fn minimum_bytes_needed() -> usize {
798 <u32 as Readable<'a, C>>::minimum_bytes_needed()
799 }
800}
801
802#[cfg(feature = "speedy")]
803impl<C: Context> Writable<C> for EventKind {
804 #[inline]
805 fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
806 writer.write_u32(u32::from(*self))
807 }
808
809 #[inline]
810 fn bytes_needed(&self) -> Result<usize, C::Error> {
811 Ok(std::mem::size_of::<u32>())
812 }
813}
814
815#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
817#[cfg_attr(feature = "speedy", derive(Readable, Writable))]
818#[serde(untagged)]
819pub enum EventKindOrRange {
820 EventKind(EventKind),
822
823 Range(Vec<EventKind>),
827}
828
829#[cfg(test)]
830mod test {
831 use super::*;
832
833 test_serde! {EventKind, test_event_kind_serde}
834
835 #[test]
836 fn test_replaceable_ephemeral() {
837 assert!(Metadata.is_replaceable());
838 assert!(!TextNote.is_replaceable());
839 assert!(!Zap.is_replaceable());
840 assert!(LongFormContent.is_replaceable());
841
842 assert!(!TextNote.is_ephemeral());
843 assert!(Auth.is_ephemeral());
844
845 assert!(!TextNote.is_parameterized_replaceable());
846 assert!(LongFormContent.is_parameterized_replaceable());
847 }
848
849 #[cfg(feature = "speedy")]
850 #[test]
851 fn test_speedy_event_kind() {
852 let ek = EventKind::mock();
853 let bytes = ek.write_to_vec().unwrap();
854 let ek2 = EventKind::read_from_buffer(&bytes).unwrap();
855 assert_eq!(ek, ek2);
856 }
857}