RelayURL.swift (2736B)
1 // 2 // RelayURL.swift 3 // damus 4 // 5 // Created by Daniel D’Aquino on 2023-09-29. 6 // 7 8 import Foundation 9 10 public struct RelayURL: Hashable, Equatable, Codable, CodingKeyRepresentable, Identifiable, Comparable, CustomStringConvertible { 11 private(set) var url: URL 12 13 public var id: URL { 14 return url 15 } 16 17 public var description: String { 18 return self.absoluteString 19 } 20 21 public var absoluteString: String { 22 return url.absoluteString 23 } 24 25 init?(_ str: String) { 26 var trimmed_url_str = str 27 while trimmed_url_str.hasSuffix("/") { 28 trimmed_url_str.removeLast() 29 } 30 31 guard let url = URL(string: trimmed_url_str) else { 32 return nil 33 } 34 35 guard let scheme = url.scheme else { 36 return nil 37 } 38 39 guard scheme == "ws" || scheme == "wss" else { 40 return nil 41 } 42 43 self.url = url 44 } 45 46 // MARK: - Codable 47 public init(from decoder: Decoder) throws { 48 let container = try decoder.singleValueContainer() 49 let urlString = try container.decode(String.self) 50 guard let instance = RelayURL(urlString) else { 51 throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid URL string.") 52 } 53 self = instance 54 } 55 56 public func encode(to encoder: Encoder) throws { 57 var container = encoder.singleValueContainer() 58 try container.encode(url.absoluteString) 59 } 60 61 // MARK: - CodingKeyRepresentable 62 // CodingKeyRepresentable conformance is necessary to ensure that 63 // a dictionary with type "[RelayURL: T] where T: Codable" can be encoded into a keyed container 64 // e.g. `{<URL>: <VALUE>, <URL>: <VALUE>}` instead of `[<URL>, <VALUE>, <URL>, <VALUE>]`, which is Swift's default for non-string-keyed dictionaries 65 66 public var codingKey: CodingKey { 67 return StringKey(stringValue: self.url.absoluteString) 68 } 69 70 public init?<T>(codingKey: T) where T : CodingKey { 71 self.init(codingKey.stringValue) 72 } 73 74 // MARK: - Equatable 75 public static func == (lhs: RelayURL, rhs: RelayURL) -> Bool { 76 return lhs.url == rhs.url 77 } 78 79 // MARK: - Hashable 80 public func hash(into hasher: inout Hasher) { 81 hasher.combine(self.url) 82 } 83 84 // MARK: - Comparable 85 public static func < (lhs: RelayURL, rhs: RelayURL) -> Bool { 86 return lhs.url.absoluteString < rhs.url.absoluteString 87 } 88 89 } 90 91 private struct StringKey: CodingKey { 92 var stringValue: String 93 init(stringValue: String) { 94 self.stringValue = stringValue 95 } 96 var intValue: Int? { return nil } 97 init?(intValue: Int) { return nil } 98 }