damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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 }