import Foundation struct QLog { private init() {} static func m(_ message: String) { write("", message) } static func Info(_ message: String) { write("[INFO] ", message) } #if DEBUG static func Debug(_ message: String) { write("[DEBUG] ", message) } #else static func Debug(_ _: String) {} #endif static func Error(_ message: String) { write("[ERROR] ", message) } static func Warning(_ message: String) { write("[WARN] ", message) } private static func write(_ tag: String, _ message: String) { print(String(format: "%1.3f %@%@", Date().timeIntervalSince1970, tag, message)) } } extension Collection { subscript(ifExist i: Index?) -> Iterator.Element? { guard let i = i else { return nil } return indices.contains(i) ? self[i] : nil } } var listOfSLDs: [String : [String : Bool]] = { let path = Bundle.main.url(forResource: "third-level", withExtension: "txt") let content = try! String(contentsOf: path!) var res: [String : [String : Bool]] = [:] content.enumerateLines { line, _ in let dom = line.split(separator: ".") let tld = String(dom.first!) let sld = String(dom.last!) if res[tld] == nil { res[tld] = [:] } res[tld]![sld] = true } return res }() extension String { /// Check if string is equal to `domain` or ends with `.domain` func isSubdomain(of domain: String) -> Bool { self == domain || self.hasSuffix("." + domain) } /// Split string into top level domain part and host part func splitDomainAndHost() -> (domain: String, host: String?) { let lastChr = last?.asciiValue ?? 0 guard lastChr > UInt8(ascii: "9") || lastChr < UInt8(ascii: "0") else { // IP address return (domain: "# IP connection", host: self) } var parts = components(separatedBy: ".") guard let tld = parts.popLast(), let sld = parts.popLast() else { return (domain: self, host: nil) // no subdomains, just plain SLD } var ending = sld + "." + tld if listOfSLDs[tld]?[sld] ?? false, let rld = parts.popLast() { ending = rld + "." + ending } return (domain: ending, host: parts.joined(separator: ".")) // var allDots = enumerated().compactMap { $1 == "." ? $0 : nil } // let d1 = allDots.popLast() // we dont care about TLD // guard let d2 = allDots.popLast() else { // return (domain: self, host: nil) // no subdomains, just plain SLD // } // // TODO: check third level domains //// let d3 = allDots.popLast() // return (String(suffix(count - d2 - 1)), String(prefix(d2))) } } extension Timer { @discardableResult static func repeating(_ interval: TimeInterval, call selector: Selector, on target: Any, userInfo: Any? = nil) -> Timer { Timer.scheduledTimer(timeInterval: interval, target: target, selector: selector, userInfo: userInfo, repeats: true) } } extension DateFormatter { convenience init(withFormat: String) { self.init() dateFormat = withFormat } func with(format: String) -> Self { dateFormat = format return self } func string(from ts: Timestamp) -> String { string(from: Date.init(timeIntervalSince1970: Double(ts))) } } func TimestampNow() -> Timestamp { Timestamp(Date().timeIntervalSince1970) }