diff --git a/Cartfile b/Cartfile index 2bfea98..c517d21 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1,2 @@ -github "mxcl/PromiseKit" ~> 6.0 +#github "mxcl/PromiseKit" ~> 6.0 +github "dougzilla32/PromiseKit" "CoreCancel" diff --git a/Cartfile.resolved b/Cartfile.resolved index a1be206..80a4000 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "mxcl/PromiseKit" "6.3.3" +github "dougzilla32/PromiseKit" "087b3cf470890ff9ea841212e2f3e285fecf3988" diff --git a/PMKSystemConfiguration.xcodeproj/project.pbxproj b/PMKSystemConfiguration.xcodeproj/project.pbxproj index f59f77d..7dabf8d 100644 --- a/PMKSystemConfiguration.xcodeproj/project.pbxproj +++ b/PMKSystemConfiguration.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 6362F84F1D5D934C0021D2DD /* SCNetworkReachability+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 6362F84D1D5D934C0021D2DD /* SCNetworkReachability+AnyPromise.m */; }; 6383E14B1D611E0D00897651 /* SCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6383E14A1D611E0D00897651 /* SCTests.swift */; }; 63C7FFF71D5C020D003BAE60 /* PMKSystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKSystemConfiguration.framework */; }; + 911E6FC820F578E2006F49B9 /* SCNetworkReachability+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911E6FC720F578E2006F49B9 /* SCNetworkReachability+Promise.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -34,6 +35,7 @@ 63C7FFF21D5C020D003BAE60 /* PMKSCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKSCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63CCF8121D5C0C4E00503216 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; 63CCF8171D5C11B500503216 /* Carthage.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Carthage.xcconfig; sourceTree = ""; }; + 911E6FC720F578E2006F49B9 /* SCNetworkReachability+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SCNetworkReachability+Promise.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,6 +84,7 @@ 6358AB791D5D4B6700B9B157 /* PMKSystemConfiguration.h */, 6362F84C1D5D934C0021D2DD /* SCNetworkReachability+AnyPromise.h */, 6362F84D1D5D934C0021D2DD /* SCNetworkReachability+AnyPromise.m */, + 911E6FC720F578E2006F49B9 /* SCNetworkReachability+Promise.swift */, ); path = Sources; sourceTree = ""; @@ -208,6 +211,7 @@ buildActionMask = 2147483647; files = ( 6362F84F1D5D934C0021D2DD /* SCNetworkReachability+AnyPromise.m in Sources */, + 911E6FC820F578E2006F49B9 /* SCNetworkReachability+Promise.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/SCNetworkReachability+Promise.swift b/Sources/SCNetworkReachability+Promise.swift index d2d8291..b22e827 100644 --- a/Sources/SCNetworkReachability+Promise.swift +++ b/Sources/SCNetworkReachability+Promise.swift @@ -7,25 +7,35 @@ public extension SCNetworkReachability { case couldNotInitializeReachability } + /// - Note: cancelling this promise will cancel the underlying task + /// - SeeAlso: [Cancellation](http://promisekit.org/docs/) static func promise() -> Promise { do { - var zeroAddress = sockaddr() - zeroAddress.sa_len = UInt8(MemoryLayout.size) - zeroAddress.sa_family = sa_family_t(AF_INET) - guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { - throw PMKError.couldNotInitializeReachability - } - - var flags = SCNetworkReachabilityFlags() - if SCNetworkReachabilityGetFlags(ref, &flags), flags.contains(.reachable) { + if let promise = try pending()?.promise { + return promise + } else { return Promise() } - - return try Helper(ref: ref).pending.promise } catch { return Promise(error: error) } } + + fileprivate static func pending() throws -> (promise: Promise, resolver: Resolver)? { + var zeroAddress = sockaddr() + zeroAddress.sa_len = UInt8(MemoryLayout.size) + zeroAddress.sa_family = sa_family_t(AF_INET) + guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { + throw PMKError.couldNotInitializeReachability + } + + var flags = SCNetworkReachabilityFlags() + if SCNetworkReachabilityGetFlags(ref, &flags), flags.contains(.reachable) { + return nil + } + + return try Helper(ref: ref).pending + } } private func callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) { @@ -40,6 +50,10 @@ private class Helper { init(ref: SCNetworkReachability) throws { self.ref = ref + + // Set 'reject' for cancellation so that the promise will be rejected if cancelled. The 'ensure' block + // below will automatically clean up the callback and dispatch queue when the promise is rejected. + pending.promise.setCancellableTask(nil, reject: pending.resolver.reject) var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())