// // AttractorServer.swift // App // // Created by James Magahern on 8/5/22. // import Foundation class AttractorServer { public enum Error: Swift.Error { case missingEndpointURL } static let shared = AttractorServer() private var endpointURL: URL? { get { if let syncServer = Settings.shared.syncServer { return URL(string: syncServer) } return nil } } private func getHostname() -> String { // Need an entitlement for this... return UIDevice.current.name } public func publishTabInfo(_ tabInfos: [TabInfo]) { guard let endpointURL else { return } let hostName = getHostname() let rpcURL = endpointURL.appendingPathComponent("publishTabInfo") var components = URLComponents(url: rpcURL, resolvingAgainstBaseURL: false)! components.queryItems = [ URLQueryItem(name: "host", value: hostName) ] let encoder = JSONEncoder() if let bodyData = try? encoder.encode(tabInfos) { var request = URLRequest(url: components.url!) request.httpBody = bodyData request.httpMethod = "POST" let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in if let error { print("Error publishing tab info: \(error.localizedDescription)") } } dataTask.resume() } } public func getTabInfos(_ completion: @escaping(Result<[String: [TabInfo]], Swift.Error>) -> Void) { guard let endpointURL else { completion(.failure(Self.Error.missingEndpointURL)) return } let rpcURL = endpointURL.appendingPathComponent("getTabInfos") let request = URLRequest(url: rpcURL) let myHostname = getHostname() let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in if let error { print("Error getting tab infos: \(error.localizedDescription)") DispatchQueue.main.async { completion(.failure(error)) } } let decoder = JSONDecoder() if let data { do { let result = try decoder.decode([String: [TabInfo]].self, from: data) .filter({ (host, tabInfo) in // Filter out tabs from the same machine. return host != myHostname }) DispatchQueue.main.async { completion(.success(result)) } } catch { print("Error decoding tabs: \(error.localizedDescription)") DispatchQueue.main.async { completion(.failure(error)) } } } } dataTask.resume() } }