Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix tags #58

Merged
merged 1 commit into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Sources/NostrSDK/Events/TextNoteEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public final class TextNoteEvent: NostrEvent {

/// Pubkeys mentioned in the note content.
public var mentionedPubkeys: [String] {
let pubkeyTags = tags.filter { $0.identifier == .pubkey }
return pubkeyTags.map { $0.contentIdentifier }
let pubkeyTags = tags.filter { $0.name == .pubkey }
return pubkeyTags.map { $0.value }
}

/// Events mentioned in the note content.
public var mentionedEventIds: [String] {
let eventTags = tags.filter { $0.identifier == .event }
return eventTags.map { $0.contentIdentifier }
let eventTags = tags.filter { $0.name == .event }
return eventTags.map { $0.value }
}
}
167 changes: 47 additions & 120 deletions Sources/NostrSDK/Tag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
import Foundation

/// A constant that describes the type of a ``Tag``.
public enum TagIdentifier: Codable, Equatable {
public enum TagName: Codable, Equatable {

/// points to the id of an event this event is quoting, replying to or referring to somehow
case event

/// points to a pubkey of someone that is referred to in the event
case pubkey

/// a stringified kind number
case kind

/// a tag of unknown type
case unknown(String)

Expand All @@ -25,14 +28,16 @@ public enum TagIdentifier: Codable, Equatable {
return "e"
case .pubkey:
return "p"
case .kind:
return "k"
case .unknown(let id):
return id
}
}

public static func == (lhs: TagIdentifier, rhs: TagIdentifier) -> Bool {
public static func == (lhs: TagName, rhs: TagName) -> Bool {
switch (lhs, rhs) {
case (.event, .event), (.pubkey, .pubkey): return true
case (.event, .event), (.pubkey, .pubkey), (.kind, .kind): return true
case (.unknown(let id1), .unknown(let id2)): return id1 == id2
default: return false
}
Expand Down Expand Up @@ -95,30 +100,36 @@ public enum EventTagMarker: Codable, Equatable {
}
}

/// A reference to an event, pubkey, or other content
/// A reference to an event, pubkey, or other content.
///
/// See [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) for an initial definition of tags.
/// See [NIP-10](https://github.com/nostr-protocol/nips/blob/master/01.md) for further refinement and additions to tags.
/// See https://github.com/nostr-protocol/nips/tree/b4cdc1a73d415c79c35655fa02f5e55cd1f2a60c#standardized-tags for a list of all standardized tags.
public class Tag: Codable, Equatable {
public static func == (lhs: Tag, rhs: Tag) -> Bool {
lhs.isEqual(to: rhs)
}

/// The type of tag: event, pubkey, or other unknown type.
let identifier: TagIdentifier
/// The name of the tag: event, pubkey, kind etc.
let name: TagName

/// The main value associated with the tag. For example, for the
/// pubkey name, the `value` is the 32-byte, hex-encoded pubkey.
let value: String

/// The content identifier associated with the type. For example, for the
/// pubkey type, the `contentIdentifier` is the 32-byte, hex-encoded pubkey.
let contentIdentifier: String
/// The remaining parameters in the array of strings the tag consists of.
let otherParameters: [String]

/// Creates and returns a tag object that references some piece of content.
/// Creates and returns a ``Tag`` object that references some piece of content.
/// - Parameters:
/// - identifier: The type of tag: event, pubkey, or other unknown type.
/// - contentIdentifier: The content identifier associated with the type. For example, for the
/// pubkey type, the `contentIdentifier` is the 32-byte, hex-encoded pubkey.
init(identifier: TagIdentifier, contentIdentifier: String) {
self.identifier = identifier
self.contentIdentifier = contentIdentifier
/// - name: The name of the tag: event, pubkey, or other unknown type.
/// - value: The content identifier associated with the type. For example, for the
/// pubkey type, the `value` is the 32-byte, hex-encoded pubkey.
/// - otherParameters: The remaining parameters in the array of strings the tag consists of.
init(name: TagName, value: String, otherParameters: [String] = []) {
self.name = name
self.value = value
self.otherParameters = otherParameters
}

required public init(from decoder: Decoder) throws {
Expand All @@ -127,121 +138,37 @@ public class Tag: Codable, Equatable {
let type = try container.decode(String.self)
switch type {
case "p":
identifier = .pubkey
name = .pubkey
case "e":
identifier = .event
name = .event
case "k":
name = .kind
default:
identifier = .unknown(type)
name = .unknown(type)
}

contentIdentifier = try container.decode(String.self)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(identifier.rawValue)
try container.encode(contentIdentifier)
}

func isEqual(to tag: Tag) -> Bool {
identifier == tag.identifier &&
contentIdentifier == tag.contentIdentifier
}
}

/// A tag referencing a pubkey
///
/// See [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) and [NIP-02](https://github.com/nostr-protocol/nips/blob/master/02.md#contact-list-and-petnames)
public class PubkeyTag: Tag {
/// The URL of a recommended relay associated with the reference.
let recommendedRelayURL: String?

/// A local name for the profile (can also be set to an empty string or not provided).
let petname: String?

/// Creates and returns a tag for a pubkey.
/// - Parameters:
/// - contentIdentifier: The content identifier associated with the type. For example, for the
/// pubkey type, the `contentIdentifier` is the 32-byte, hex-encoded pubkey.
/// - recommendedRelayURL: The URL of a recommended relay associated with the reference.
/// - petname: A local name for the profile (can also be set to an empty string or not provided).
init(contentIdentifier: String, recommendedRelayURL: String? = nil, petname: String? = nil) {
self.recommendedRelayURL = recommendedRelayURL
self.petname = petname
super.init(identifier: .pubkey, contentIdentifier: contentIdentifier)
}

public required init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
recommendedRelayURL = try container.decodeIfPresent(String.self)
petname = try container.decodeIfPresent(String.self)

try super.init(from: decoder)
}

public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
value = try container.decode(String.self)

var container = encoder.unkeyedContainer()
if let recommendedRelayURL {
try container.encode(recommendedRelayURL)
}
if let petname {
try container.encode(petname)
}
}

override func isEqual(to tag: Tag) -> Bool {
guard let pTag = tag as? PubkeyTag else {
return false
}
return super.isEqual(to: tag) &&
recommendedRelayURL == pTag.recommendedRelayURL &&
petname == pTag.petname
}
}

/// A tag referencing an event
///
/// See [NIP-10](https://github.com/nostr-protocol/nips/blob/master/10.md#marked-e-tags-preferred)
public class EventTag: Tag {
/// The type of the ``EventTag``.
let marker: EventTagMarker?

/// Creates and returns tag referencing an event.
/// - Parameters:
/// - contentIdentifier: The event id.
/// - marker: The type of reference. See [NIP-10](https://github.com/nostr-protocol/nips/blob/master/10.md#marked-e-tags-preferred) for a description of marked "e" tags.
init(contentIdentifier: String, marker: EventTagMarker? = nil) {
self.marker = marker
super.init(identifier: .event, contentIdentifier: contentIdentifier)
}

public required init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
if let rawMarker = try container.decodeIfPresent(String.self) {
marker = EventTagMarker(rawValue: rawMarker)
} else {
marker = nil
var otherParameters = [String]()
while !container.isAtEnd {
let value = try container.decode(String.self)
otherParameters.append(value)
}

try super.init(from: decoder)
self.otherParameters = otherParameters
}

public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)

public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
if let marker {
try container.encode(marker)
try container.encode(name.rawValue)
try container.encode(value)
for value in otherParameters {
try container.encode(value)
}
}

override func isEqual(to tag: Tag) -> Bool {
guard let eTag = tag as? EventTag else {
return false
}
return super.isEqual(to: tag) &&
marker == eTag.marker
func isEqual(to tag: Tag) -> Bool {
name == tag.name &&
value == tag.value &&
otherParameters == tag.otherParameters
}
}
12 changes: 6 additions & 6 deletions Tests/NostrSDKTests/EventDecodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ final class EventDecodingTests: XCTestCase, FixtureLoading {
XCTAssertEqual(event.kind, .textNote)

let expectedTags = [
EventTag(contentIdentifier: "93930d65435d49db723499335473920795e7f13c45600dcfad922135cf44bd63"),
PubkeyTag(contentIdentifier: "f8e6c64342f1e052480630e27e1016dce35fc3a614e60434fef4aa2503328ca9")
Tag(name: .event, value: "93930d65435d49db723499335473920795e7f13c45600dcfad922135cf44bd63"),
Tag(name: .pubkey, value: "f8e6c64342f1e052480630e27e1016dce35fc3a614e60434fef4aa2503328ca9")
]
XCTAssertEqual(event.tags, expectedTags)
XCTAssertEqual(event.content, "I think it stays persistent on your profile, but interface setting doesn’t persist. Bug. ")
Expand Down Expand Up @@ -86,8 +86,8 @@ final class EventDecodingTests: XCTestCase, FixtureLoading {
XCTAssertEqual(event.kind, .contactList)

let expectedTags: [Tag] = [
PubkeyTag(contentIdentifier: "pubkey1", recommendedRelayURL: "wss://relay1.com", petname: "alice"),
PubkeyTag(contentIdentifier: "pubkey2", recommendedRelayURL: "wss://relay2.com", petname: "bob")
Tag(name: .pubkey, value: "pubkey1", otherParameters: ["wss://relay1.com", "alice"]),
Tag(name: .pubkey, value: "pubkey2", otherParameters: ["wss://relay2.com", "bob"])
]
XCTAssertEqual(event.tags, expectedTags)
XCTAssertEqual(event.signature, "hex-signature")
Expand All @@ -103,8 +103,8 @@ final class EventDecodingTests: XCTestCase, FixtureLoading {
XCTAssertEqual(event.kind, .repost)

let expectedTags = [
EventTag(contentIdentifier: "6663efd8ffb35325af90a84cb223dc388e9d355abf7319fe5c4c5ca7f37e9a34"),
PubkeyTag(contentIdentifier: "33eecd2e2fae31f36c0bdb843d43611426ee5c023889f0401c1b8f5008e59689")
Tag(name: .event, value: "6663efd8ffb35325af90a84cb223dc388e9d355abf7319fe5c4c5ca7f37e9a34"),
Tag(name: .pubkey, value: "33eecd2e2fae31f36c0bdb843d43611426ee5c023889f0401c1b8f5008e59689")
]
XCTAssertEqual(event.tags, expectedTags)
XCTAssertTrue(event.content.hasPrefix("{\"pubkey\":\"33eecd2e2fae31f36c0bdb843d43611426ee5c023889f0401c1b8f5008e59689\""))
Expand Down
4 changes: 2 additions & 2 deletions Tests/NostrSDKTests/RelayRequestEncodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ final class RelayRequestEncodingTests: XCTestCase, FixtureLoading, JSONTesting {
}

func testEncodeEvent() throws {
let eventTag = EventTag(contentIdentifier: "93930d65435d49db723499335473920795e7f13c45600dcfad922135cf44bd63")
let pubkeyTag = PubkeyTag(contentIdentifier: "f8e6c64342f1e052480630e27e1016dce35fc3a614e60434fef4aa2503328ca9")
let eventTag = Tag(name: .event, value: "93930d65435d49db723499335473920795e7f13c45600dcfad922135cf44bd63")
let pubkeyTag = Tag(name: .pubkey, value: "f8e6c64342f1e052480630e27e1016dce35fc3a614e60434fef4aa2503328ca9")
let event = NostrEvent(id: "fa5ed84fc8eeb959fd39ad8e48388cfc33075991ef8e50064cfcecfd918bb91b",
pubkey: "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2",
createdAt: 1682080184,
Expand Down
Loading