// // ServerMultiplex.swift // XIONControlPanel // // Created by James Magahern on 3/14/20. // Copyright © 2020 XION. All rights reserved. // import Foundation protocol ServerMultiplexDelegate { func serverMultiplex(_ multiplex: ServerMultiplex, didAddDevices devices: [AnyDevice]) func serverMultiplex(_ multiplex: ServerMultiplex, devicesStateChanged devices: [AnyDevice]) func serverMultiplex(_ multiplex: ServerMultiplex, didEncounterError error: Error) } enum ServerMultiplexError : Error { case unknownDevice } class ServerMultiplex { public var delegate: ServerMultiplexDelegate? public private(set) var devices = Set() private var servers: [Server] = [] public var numServers: Int { return servers.count } public func addServer(_ server: Server) { servers.append(server) } public func numberOfConnectedServers() -> Int { return servers.filter { $0.connected == true }.count } public func toggleDeviceState(_ device: AnyDevice, state: DeviceState, completion: @escaping (Error?) -> Void) { if let server = (servers.first { $0.responsibleForDevice(device) }) { server.toggleDevice(device, state: state, completion: completion) // Update internal state if let index = devices.firstIndex(of: device) { devices[index].state = state } } else { completion(ServerMultiplexError.unknownDevice) } } public func refreshDevices() { self.servers.forEach { (server: Server) in server.fetchDevices { (result: Result<[AnyDevice], Error>) in self.handleServerFetchResult(result) } } } } extension ServerMultiplex { private func handleServerFetchResult(_ result: Result<[AnyDevice], Error>) { switch result { case .success(let devices): handleDevicesChanged(devices) case .failure(let error): handleError(error) } } private func handleDevicesChanged(_ devicesChanged: [AnyDevice]) { let newDevicesSet = Set(devicesChanged) let additions = newDevicesSet.subtracting(self.devices) let changed = newDevicesSet.filter { (device: AnyDevice) in if let existing = (devices.first { $0.hashValue == device.hashValue }) { return existing.state != device.state } return false } self.devices = self.devices.union(newDevicesSet) if additions.count > 0 { DispatchQueue.main.async { self.delegate?.serverMultiplex(self, didAddDevices: Array(additions)) } } if changed.count > 0 { DispatchQueue.main.async { self.delegate?.serverMultiplex(self, devicesStateChanged: Array(changed)) } } } private func handleError(_ error: Error) { DispatchQueue.main.async { self.delegate?.serverMultiplex(self, didEncounterError: error) } } }