Add PromiseKit dependency

- Added PromiseKit dependency
This commit is contained in:
2018-11-15 22:08:00 -04:00
parent 2689d86c18
commit be7b6b5881
541 changed files with 46282 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import Foundation
import HomeKit
#if !PMKCocoaPods
import PromiseKit
#endif
#if !os(tvOS) && !os(watchOS)
public enum HMPromiseAccessoryBrowserError: Error {
case noAccessoryFound
}
public class HMPromiseAccessoryBrowser {
private var proxy: BrowserProxy?
public func start(scanInterval: ScanInterval) -> Promise<[HMAccessory]> {
proxy = BrowserProxy(scanInterval: scanInterval)
return proxy!.promise
}
public func stop() {
proxy?.cancel()
}
}
private class BrowserProxy: PromiseProxy<[HMAccessory]>, HMAccessoryBrowserDelegate {
let browser = HMAccessoryBrowser()
let scanInterval: ScanInterval
init(scanInterval: ScanInterval) {
self.scanInterval = scanInterval
super.init()
browser.delegate = self;
browser.startSearchingForNewAccessories()
//if we have a timeout, set it up
var timeout: TimeInterval? = nil
switch scanInterval {
case .returnAll(let interval): timeout = interval
case .returnFirst(let interval): timeout = interval
}
if let timeout = timeout {
after(seconds: timeout)
.done { [weak self] () -> Void in
guard let _self = self else { return }
_self.reject(HMPromiseAccessoryBrowserError.noAccessoryFound)
}
}
}
override func fulfill(_ value: [HMAccessory]) {
browser.stopSearchingForNewAccessories()
super.fulfill(value)
}
override func reject(_ error: Error ) {
browser.stopSearchingForNewAccessories()
super.reject(error)
}
override func cancel() {
browser.stopSearchingForNewAccessories()
super.cancel()
}
/**
HMAccessoryBrowser delegate
*/
func accessoryBrowser(_ browser: HMAccessoryBrowser, didFindNewAccessory accessory: HMAccessory) {
if case .returnFirst = scanInterval {
fulfill([accessory])
}
}
}
#endif

View File

@@ -0,0 +1,46 @@
import Foundation
import HomeKit
#if !PMKCocoaPods
import PromiseKit
#endif
public enum AccessoryError: Error {
case incorrectType
case serviceMissing
case characteristicMissing
}
@available(iOS 8.0, tvOS 10.0, *)
extension HMCharacteristic {
/**
A simple typesafe promise wrapper around readValue
*/
public func read<T>() -> Promise<T> {
return Promise { seal in
self.readValue { error in
if let error = error { seal.reject(error) }
else if let value = self.value as? T { seal.fulfill(value) }
else { seal.reject(AccessoryError.incorrectType) }
}
}
}
/// Because type inference is great... until you can't compile (thanks Swift)
public func readFloat() -> Promise<Float> { return read() }
public func readDouble() -> Promise<Double> { return read() }
public func readInt() -> Promise<Int> { return read() }
public func readString() -> Promise<String> { return read() }
/**
A simple promise wrapper around writeValue
*/
public func write(_ value: Any?) -> Promise<Void> {
return Promise { seal in
self.writeValue(value, completionHandler: seal.resolve)
}
}
/// Explicit is good
public func writeFloat(_ value: Float) -> Promise<Void> { return write(value) }
public func writeDouble(_ value: Double) -> Promise<Void> { return write(value) }
public func writeInt(_ value: Int) -> Promise<Void> { return write(value) }
public func writeString(_ value: String) -> Promise<Void> { return write(value) }
}

View File

@@ -0,0 +1,82 @@
import Foundation
import HomeKit
#if !PMKCocoaPods
import PromiseKit
#endif
#if !os(tvOS) && !os(watchOS)
extension HMHome {
@available(iOS 8.0, *)
public func updateName(_ name: String) -> Promise<Void> {
return Promise { seal in
self.updateName(name, completionHandler: seal.resolve)
}
}
/// Add and setup a new HMAccessory. Displays it's own UI
@available(iOS 11.3, *)
public func addAndSetupAccessories(with payload: HMAccessorySetupPayload) -> Promise<[HMAccessory]> {
return Promise { seal in
self.addAndSetupAccessories(with: payload, completionHandler: seal.resolve)
}
}
/// Add and setup a new HMAccessory. Displays it's own UI
@available(iOS 10.0, *)
public func addAndSetupAccessories() -> Promise<[HMAccessory]> {
// We need to compare what we have before the action to after to know what is new
let beforeAccessories = self.accessories
let home = self
return Promise { seal in
self.addAndSetupAccessories { error in
if let error = error { seal.reject(error) }
else {
let newAccessories = home.accessories.filter { beforeAccessories.contains($0) == false }
seal.fulfill(newAccessories)
}
}
}
}
@available(iOS 8.0, *)
public func addAccessory(_ accessory: HMAccessory) -> Promise<Void> {
return Promise { seal in
self.addAccessory(accessory, completionHandler: seal.resolve)
}
}
@available(iOS 8.0, *)
public func assignAccessory(_ accessory: HMAccessory, to room: HMRoom) -> Promise<Void> {
return Promise { seal in
self.assignAccessory(accessory, to: room, completionHandler: seal.resolve)
}
}
@available(iOS 8.0, *)
public func removeAccessory(_ accessory: HMAccessory) -> Promise<Void> {
return Promise { seal in
self.removeAccessory(accessory, completionHandler: seal.resolve)
}
}
/**
Rooms
*/
@available(iOS 8.0, *)
public func addRoom(withName name: String) -> Promise<HMRoom> {
return Promise { seal in
self.addRoom(withName: name, completionHandler: seal.resolve)
}
}
@available(iOS 8.0, *)
public func removeRoom(_ room: HMRoom) -> Promise<Void> {
return Promise { seal in
self.removeRoom(room, completionHandler: seal.resolve)
}
}
}
#endif

View File

@@ -0,0 +1,62 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
import HomeKit
@available(iOS 8.0, tvOS 10.0, *)
public enum HomeKitError: Error {
case permissionDeined
}
@available(iOS 8.0, tvOS 10.0, *)
extension HMHomeManager {
public func homes() -> Promise<[HMHome]> {
return HMHomeManagerProxy().promise
}
#if !os(tvOS) && !os(watchOS)
@available(iOS 8.0, *)
public func addHome(withName name: String) -> Promise<HMHome> {
return Promise { seal in
self.addHome(withName: name, completionHandler: seal.resolve)
}
}
@available(iOS 8.0, *)
public func removeHome(_ home: HMHome) -> Promise<Void> {
return Promise { seal in
self.removeHome(home, completionHandler: seal.resolve)
}
}
@available(iOS 8.0, *)
public func updatePrimaryHome(_ home: HMHome) -> Promise<Void> {
return Promise { seal in
self.updatePrimaryHome(home, completionHandler: seal.resolve)
}
}
#endif
}
@available(iOS 8.0, tvOS 10.0, *)
internal class HMHomeManagerProxy: PromiseProxy<[HMHome]>, HMHomeManagerDelegate {
fileprivate let manager: HMHomeManager
override init() {
self.manager = HMHomeManager()
super.init()
self.manager.delegate = self
DispatchQueue.main.asyncAfter(deadline: .now() + 20.0) { [weak self] in
self?.reject(HomeKitError.permissionDeined)
}
}
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
fulfill(manager.homes)
}
}

View File

@@ -0,0 +1,45 @@
#if !PMKCocoaPods
import PromiseKit
#endif
/**
Commonly used functionality when promisifying a delegate pattern
*/
internal class PromiseProxy<T>: NSObject {
internal let (promise, seal) = Promise<T>.pending();
private var retainCycle: PromiseProxy?
override init() {
super.init()
// Create a retain cycle
self.retainCycle = self
// And ensure we break it when the promise is resolved
_ = promise.ensure { self.retainCycle = nil }
}
/// These functions ensure we only resolve the promise once
internal func fulfill(_ value: T) {
guard self.promise.isResolved == false else { return }
seal.fulfill(value)
}
internal func reject(_ error: Error) {
guard self.promise.isResolved == false else { return }
seal.reject(error)
}
/// Cancel helper
internal func cancel() {
self.reject(PMKError.cancelled)
}
}
/**
Different ways to scan.
*/
public enum ScanInterval {
// Return after our first item with an optional time limit
case returnFirst(timeout: TimeInterval?)
// Scan for this duration before returning all
case returnAll(interval: TimeInterval)
}