Skip to content

Commit

Permalink
Add NostrEventBuilding protocol to enable flexible composition of sha…
Browse files Browse the repository at this point in the history
…red patterns across different kinds of NostrEvents
  • Loading branch information
tyiu committed Aug 9, 2024
1 parent e18ebda commit 2d2ac7f
Show file tree
Hide file tree
Showing 23 changed files with 474 additions and 81 deletions.
8 changes: 8 additions & 0 deletions Sources/NostrSDK/CustomEmoji.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public class CustomEmoji: CustomEmojiValidating, Equatable {
}
}

public protocol CustomEmojiBuilding: NostrEventBuilding {}
public extension CustomEmojiBuilding {
func customEmojis(_ customEmojis: [CustomEmoji]) -> Self {
_ = tags(customEmojis.map { $0.tag }, at: 0)
return self
}
}

public protocol CustomEmojiInterpreting: NostrEvent, CustomEmojiValidating {}
public extension CustomEmojiInterpreting {
/// Returns the list of well-formatted custom emojis derived from NostrEvent tags.
Expand Down
7 changes: 6 additions & 1 deletion Sources/NostrSDK/Events/AuthenticationEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ public final class AuthenticationEvent: NostrEvent, RelayProviding {
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .authentication, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/BookmarksListEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ public final class BookmarksListEvent: NostrEvent, HashtagInterpreting, PrivateT
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .bookmarksList, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/Calendars/CalendarEventRSVP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ public final class CalendarEventRSVP: NostrEvent, ParameterizedReplaceableEvent
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .calendarEventRSVP, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

/// Event coordinates to the calendar event this RSVP responds to.
public var calendarEventCoordinates: EventCoordinates? {
tags.compactMap { EventCoordinates(eventCoordinatesTag: $0) }
Expand Down
7 changes: 6 additions & 1 deletion Sources/NostrSDK/Events/Calendars/CalendarListEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ public final class CalendarListEvent: NostrEvent, ParameterizedReplaceableEvent,
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .calendar, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ public final class DateBasedCalendarEvent: NostrEvent, CalendarEventInterpreting
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .dateBasedCalendarEvent, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ public final class TimeBasedCalendarEvent: NostrEvent, CalendarEventInterpreting
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .timeBasedCalendarEvent, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/DeletionEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ public final class DeletionEvent: NostrEvent, EventCoordinatesTagInterpreting {
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .deletion, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/FollowListEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ public final class FollowListEvent: NostrEvent, NonParameterizedReplaceableEvent
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .followList, content: "", tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/GenericRepostEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ public class GenericRepostEvent: NostrEvent {
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: Self.kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
7 changes: 6 additions & 1 deletion Sources/NostrSDK/Events/GiftWrap/GiftWrapEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ public final class GiftWrapEvent: NostrEvent, NIP44v2Encrypting {
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970 - TimeInterval.random(in: 0...172800)), signedBy keypair: Keypair) throws {
try super.init(kind: .giftWrap, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
7 changes: 6 additions & 1 deletion Sources/NostrSDK/Events/GiftWrap/SealEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ public final class SealEvent: NostrEvent, NIP44v2Encrypting {
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

public init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970 - TimeInterval.random(in: 0...172800)), signedBy keypair: Keypair) throws {
try super.init(kind: .seal, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ public final class LegacyEncryptedDirectMessageEvent: NostrEvent, LegacyDirectMe
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .legacyEncryptedDirectMessage, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/NostrSDK/Events/LongformContentEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ public final class LongformContentEvent: NostrEvent, HashtagInterpreting, Parame
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .longformContent, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down
38 changes: 36 additions & 2 deletions Sources/NostrSDK/Events/MetadataEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,16 @@ public final class MetadataEvent: NostrEvent, CustomEmojiInterpreting, NonParame
}

@available(*, unavailable, message: "This initializer is unavailable for this class.")
override init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
required init(kind: EventKind, content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: kind, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}


@available(*, unavailable, message: "This initializer is unavailable for this class.")
required init(id: String, pubkey: String, createdAt: Int64, kind: EventKind, tags: [Tag], content: String, signature: String?) {
super.init(id: id, pubkey: pubkey, createdAt: createdAt, kind: kind, tags: tags, content: content, signature: signature)
}

@available(*, deprecated, message: "Deprecated in favor of MetadataEvent.Builder.")
init(content: String, tags: [Tag] = [], createdAt: Int64 = Int64(Date.now.timeIntervalSince1970), signedBy keypair: Keypair) throws {
try super.init(kind: .metadata, content: content, tags: tags, createdAt: createdAt, signedBy: keypair)
}
Expand Down Expand Up @@ -155,3 +161,31 @@ public extension EventCreating {
return try MetadataEvent(content: allUserMetadataAsString, tags: customEmojiTags, signedBy: keypair)
}
}

public extension MetadataEvent {
final class Builder: NostrEvent.Builder<MetadataEvent>, CustomEmojiBuilding {
public typealias EventType = MetadataEvent

public init() {
super.init(kind: .metadata)
}

public func userMetadata(_ userMetadata: UserMetadata, rawUserMetadata: [String: Any] = [:]) throws -> Self {
let userMetadataAsData = try JSONEncoder().encode(userMetadata)

let allUserMetadataAsData: Data
if rawUserMetadata.isEmpty {
allUserMetadataAsData = userMetadataAsData
} else {
var userMetadataAsDictionary = try JSONSerialization.jsonObject(with: userMetadataAsData, options: []) as? [String: Any] ?? [:]
userMetadataAsDictionary.merge(rawUserMetadata) { (current, _) in current }
allUserMetadataAsData = try JSONSerialization.data(withJSONObject: userMetadataAsDictionary, options: .sortedKeys)
}

let allUserMetadataAsString = String(decoding: allUserMetadataAsData, as: UTF8.self)
content = allUserMetadataAsString

return self
}
}
}
Loading

0 comments on commit 2d2ac7f

Please sign in to comment.