ServerMultiplex: Introduces a server mutiplexer
- Also moves all the existing Wemo* stuff over to support the multiplexer - Moves MainViewController to be the owner of the multiplexer, and its delegate
This commit is contained in:
136
XIONControlPanel/Servers/ServerMultiplex.swift
Normal file
136
XIONControlPanel/Servers/ServerMultiplex.swift
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// 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<AnyDevice>()
|
||||
|
||||
private var servers: [Server] = []
|
||||
public var numServers: Int { get { 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()
|
||||
{
|
||||
ensureConnection { (error: Error?) in
|
||||
if let error = error {
|
||||
self.handleError(error)
|
||||
} else {
|
||||
self.servers.forEach { (server: Server) in
|
||||
server.fetchDevices { (result: Result<[AnyDevice], Error>) in
|
||||
self.handleServerFetchResult(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerMultiplex
|
||||
{
|
||||
private func ensureConnection(then: @escaping (Error?) -> Void)
|
||||
{
|
||||
let disconnectedServers = servers.filter { $0.connected == false }
|
||||
var disconnectedServerCount = disconnectedServers.count
|
||||
|
||||
if disconnectedServerCount > 0 {
|
||||
disconnectedServers.forEach { (server: Server) in
|
||||
server.connect { (error: Error?) in
|
||||
disconnectedServerCount -= 1
|
||||
if disconnectedServerCount == 0 {
|
||||
then(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
then(nil)
|
||||
}
|
||||
}
|
||||
|
||||
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<AnyDevice>(devicesChanged)
|
||||
|
||||
let additions = newDevicesSet.subtracting(self.devices)
|
||||
if additions.count > 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.serverMultiplex(self, didAddDevices: Array(additions))
|
||||
}
|
||||
}
|
||||
|
||||
let changed = newDevicesSet.filter { (device: AnyDevice) in
|
||||
if let existing = (devices.first { $0.hashValue == device.hashValue }) {
|
||||
return existing.state != device.state
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if changed.count > 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.serverMultiplex(self, devicesStateChanged: Array(changed))
|
||||
}
|
||||
}
|
||||
|
||||
self.devices = self.devices.union(newDevicesSet)
|
||||
}
|
||||
|
||||
private func handleError(_ error: Error)
|
||||
{
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.serverMultiplex(self, didEncounterError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user