feat: added Reachability plugin and moved Network module to it

This commit is contained in:
Serhiy Mytrovtsiy
2021-10-15 19:31:14 +02:00
parent 585014cba1
commit 77d1b5d274
5 changed files with 130 additions and 45 deletions

View File

@@ -0,0 +1,118 @@
//
// Reachability.swift
// Kit
//
// Created by Serhiy Mytrovtsiy on 15/10/2021.
// Using Swift 5.0.
// Running on macOS 10.15.
//
// Copyright © 2021 Serhiy Mytrovtsiy. All rights reserved.
// Inspired by https://gist.github.com/saeed-rz/d9827b312915e0dc145497532e514470 and https://github.com/ashleymills/Reachability.swift
import Foundation
import SystemConfiguration
public class Reachability {
public var isReachable: Bool = false
public var reachable: () -> Void = {}
public var unreachable: () -> Void = {}
private var isRunning = false
private var reachability: SCNetworkReachability?
private let reachabilitySerialQueue = DispatchQueue(label: "eu.exelban.ReachabilityQueue")
private let log: NextLog = NextLog.shared.copy(category: "Reachability")
public init(start: Bool = false) {
var zeroAddress = sockaddr()
zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
zeroAddress.sa_family = sa_family_t(AF_INET)
guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else {
error("SCNetworkReachability create with address")
return
}
self.reachability = ref
if start {
self.start()
}
}
public func start() {
guard let reachability = self.reachability, !self.isRunning else {
error("reachability is nil or already started")
return
}
let callback: SCNetworkReachabilityCallBack = { (_, flags, info) in
guard let info = info else { return }
Unmanaged<Reachability>.fromOpaque(info).takeUnretainedValue().setFlags(flags)
}
var context = SCNetworkReachabilityContext(
version: 0,
info: Unmanaged<Reachability>.passUnretained(self).toOpaque(),
retain: { (info: UnsafeRawPointer) -> UnsafeRawPointer in
let unmanagedReachability = Unmanaged<Reachability>.fromOpaque(info)
_ = unmanagedReachability.retain()
return UnsafeRawPointer(unmanagedReachability.toOpaque())
},
release: { (info: UnsafeRawPointer) -> Void in
Unmanaged<Reachability>.fromOpaque(info).release()
},
copyDescription: nil
)
guard SCNetworkReachabilitySetCallback(reachability, callback, &context) else {
error("SCNetworkReachability set dispatch callback")
self.stop()
return
}
guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else {
error("SCNetworkReachability set dispatch queue")
self.stop()
return
}
self.reachabilitySerialQueue.sync { [unowned self] in
guard let reachability = self.reachability else {
error("reachability is nil")
return
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
error("SCNetworkReachability get flags")
self.stop()
return
}
self.setFlags(flags)
}
self.isRunning = true
}
public func stop() {
defer { self.isRunning = false }
guard let reachability = self.reachability, self.isRunning else {
error("reachability is nil or already stopped")
return
}
SCNetworkReachabilitySetCallback(reachability, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachability, nil)
}
private func setFlags(_ flags: SCNetworkReachabilityFlags) {
self.isReachable = flags.contains(.reachable)
if self.isReachable {
self.reachable()
} else {
self.unreachable()
}
}
}

View File

@@ -12,7 +12,6 @@
import Cocoa
import Kit
import SystemConfiguration
import Reachability
import CoreWLAN
struct ipResponse: Decodable {
@@ -22,7 +21,7 @@ struct ipResponse: Decodable {
}
internal class UsageReader: Reader<Network_Usage> {
private var reachability: Reachability? = nil
private var reachability: Reachability = Reachability(start: true)
private var usage: Network_Usage = Network_Usage()
private var primaryInterface: String {
@@ -50,19 +49,12 @@ internal class UsageReader: Reader<Network_Usage> {
}
public override func setup() {
do {
self.reachability = try Reachability()
try self.reachability!.startNotifier()
} catch let err {
error("initialize Reachability error \(err)", log: self.log)
}
self.reachability!.whenReachable = { _ in
self.reachability.reachable = {
if self.active {
self.getDetails()
}
}
self.reachability!.whenUnreachable = { _ in
self.reachability.unreachable = {
if self.active {
self.usage.reset()
self.callback(self.usage)
@@ -73,6 +65,10 @@ internal class UsageReader: Reader<Network_Usage> {
NotificationCenter.default.addObserver(self, selector: #selector(resetTotalNetworkUsage), name: .resetTotalNetworkUsage, object: nil)
}
public override func terminate() {
self.reachability.stop()
}
public override func read() {
let current: Bandwidth = self.reader == "interface" ? self.readInterfaceBandwidth() : self.readProcessBandwidth()
@@ -90,7 +86,7 @@ internal class UsageReader: Reader<Network_Usage> {
self.usage.total.upload += self.usage.bandwidth.upload
self.usage.total.download += self.usage.bandwidth.download
self.usage.status = self.reachability?.connection != Optional.none
self.usage.status = self.reachability.isReachable
self.callback(self.usage)

View File

@@ -14,7 +14,6 @@
9A11AB26266FD828000C1C05 /* config.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A11AB25266FD828000C1C05 /* config.plist */; };
9A11AB36266FD9F4000C1C05 /* readers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A11AB35266FD9F4000C1C05 /* readers.swift */; };
9A11AB67266FDB69000C1C05 /* Kit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A2846F72666A9CC00EC1F6D /* Kit.framework */; };
9A27D5352538A456001BB651 /* Reachability in Frameworks */ = {isa = PBXBuildFile; productRef = 9A27D5342538A456001BB651 /* Reachability */; };
9A2846FE2666A9CC00EC1F6D /* Kit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A2846F72666A9CC00EC1F6D /* Kit.framework */; };
9A2846FF2666A9CC00EC1F6D /* Kit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A2846F72666A9CC00EC1F6D /* Kit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9A28475F2666AA2700EC1F6D /* LineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2847552666AA2700EC1F6D /* LineChart.swift */; };
@@ -69,6 +68,7 @@
9A58DE9E24B363D800716A9F /* popup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58DE9D24B363D800716A9F /* popup.swift */; };
9A58DEA024B363F300716A9F /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58DE9F24B363F300716A9F /* settings.swift */; };
9A58DEA424B3647600716A9F /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58DEA324B3647600716A9F /* settings.swift */; };
9A5A8447271895B700BC40A4 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5A8446271895B700BC40A4 /* Reachability.swift */; };
9A5AF11B2469CE9B00684737 /* popup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5AF11A2469CE9B00684737 /* popup.swift */; };
9A65654A253F20EF0096B607 /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A656549253F20EF0096B607 /* settings.swift */; };
9A656562253F788A0096B607 /* popup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A656561253F788A0096B607 /* popup.swift */; };
@@ -393,6 +393,7 @@
9A58DE9D24B363D800716A9F /* popup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = popup.swift; sourceTree = "<group>"; };
9A58DE9F24B363F300716A9F /* settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
9A58DEA324B3647600716A9F /* settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
9A5A8446271895B700BC40A4 /* Reachability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = "<group>"; };
9A5AF11A2469CE9B00684737 /* popup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = popup.swift; sourceTree = "<group>"; };
9A5F0503256A9135002FF75F /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = "<group>"; };
9A656549253F20EF0096B607 /* settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
@@ -516,7 +517,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9A27D5352538A456001BB651 /* Reachability in Frameworks */,
9A2847D62666AA9C00EC1F6D /* Kit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -826,6 +826,7 @@
9A2848072666AB3000EC1F6D /* Updater.swift */,
9A6EEBBD2685259500897371 /* Logger.swift */,
9A8AE0A226921A2A00B13054 /* Server.swift */,
9A5A8446271895B700BC40A4 /* Reachability.swift */,
);
path = plugins;
sourceTree = "<group>";
@@ -1080,7 +1081,6 @@
);
name = Net;
packageProductDependencies = (
9A27D5342538A456001BB651 /* Reachability */,
);
productName = Net;
productReference = 9A3E17CC247A94AF00449CD1 /* Net.framework */;
@@ -1340,7 +1340,6 @@
);
mainGroup = 9A1410EC229E721100D29793;
packageReferences = (
9A27D4D42538A37D001BB651 /* XCRemoteSwiftPackageReference "Reachability" */,
9A27D4D72538A38A001BB651 /* XCRemoteSwiftPackageReference "Repeat" */,
);
productRefGroup = 9A1410F6229E721100D29793 /* Products */;
@@ -1528,6 +1527,7 @@
9A28477A2666AA5000EC1F6D /* settings.swift in Sources */,
9A28475F2666AA2700EC1F6D /* LineChart.swift in Sources */,
9A28480E2666AB3000EC1F6D /* Updater.swift in Sources */,
9A5A8447271895B700BC40A4 /* Reachability.swift in Sources */,
9A2847622666AA2700EC1F6D /* Label.swift in Sources */,
9A28477C2666AA5000EC1F6D /* reader.swift in Sources */,
9A9B8C9D27149A3700218374 /* Tachometer.swift in Sources */,
@@ -2836,14 +2836,6 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
9A27D4D42538A37D001BB651 /* XCRemoteSwiftPackageReference "Reachability" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ashleymills/Reachability.swift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.1.0;
};
};
9A27D4D72538A38A001BB651 /* XCRemoteSwiftPackageReference "Repeat" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/malcommac/Repeat";
@@ -2855,11 +2847,6 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
9A27D5342538A456001BB651 /* Reachability */ = {
isa = XCSwiftPackageProductDependency;
package = 9A27D4D42538A37D001BB651 /* XCRemoteSwiftPackageReference "Reachability" */;
productName = Reachability;
};
9A2847AA2666AA7B00EC1F6D /* Repeat */ = {
isa = XCSwiftPackageProductDependency;
package = 9A27D4D72538A38A001BB651 /* XCRemoteSwiftPackageReference "Repeat" */;

View File

@@ -1,15 +1,6 @@
{
"object": {
"pins": [
{
"package": "Reachability",
"repositoryURL": "https://github.com/ashleymills/Reachability.swift",
"state": {
"branch": null,
"revision": "c01bbdf2d633cf049ae1ed1a68a2020a8bda32e2",
"version": "5.1.0"
}
},
{
"package": "Repeat",
"repositoryURL": "https://github.com/malcommac/Repeat",

View File

@@ -89,13 +89,6 @@
isEnabled = "NO">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Debug"