diff --git a/Sparkle/updates/appcast.xml b/Sparkle/updates/appcast.xml
index 4b450ee..082545a 100644
--- a/Sparkle/updates/appcast.xml
+++ b/Sparkle/updates/appcast.xml
@@ -81,5 +81,22 @@
+ -
+ 2.0.6
+
+ https://iglance.github.io/release-notes.html
+
+ Mon, 20 Apr 2020 19:00:38 +0200
+ 10.12
+
+
+
+
+
+
+
+
+
+
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.1.delta b/Sparkle/updates/iGlance2.0.6-2.0.1.delta
new file mode 100644
index 0000000..d136e38
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.1.delta differ
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.2.delta b/Sparkle/updates/iGlance2.0.6-2.0.2.delta
new file mode 100644
index 0000000..0a9f038
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.2.delta differ
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.3.delta b/Sparkle/updates/iGlance2.0.6-2.0.3.delta
new file mode 100644
index 0000000..5db2c9b
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.3.delta differ
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.4.delta b/Sparkle/updates/iGlance2.0.6-2.0.4.delta
new file mode 100644
index 0000000..19810ac
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.4.delta differ
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.5.delta b/Sparkle/updates/iGlance2.0.6-2.0.5.delta
new file mode 100644
index 0000000..0aada3c
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.5.delta differ
diff --git a/Sparkle/updates/iGlance2.0.6-2.0.delta b/Sparkle/updates/iGlance2.0.6-2.0.delta
new file mode 100644
index 0000000..681cb95
Binary files /dev/null and b/Sparkle/updates/iGlance2.0.6-2.0.delta differ
diff --git a/iGlance/iGlance/iGlance.xcodeproj/project.pbxproj b/iGlance/iGlance/iGlance.xcodeproj/project.pbxproj
index bf851a0..827d135 100644
--- a/iGlance/iGlance/iGlance.xcodeproj/project.pbxproj
+++ b/iGlance/iGlance/iGlance.xcodeproj/project.pbxproj
@@ -44,6 +44,7 @@
B472EC20243101DB002F7504 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = B472EC1F243101DB002F7504 /* Logger.swift */; };
B47D3C8D23ABEDF100DE911F /* CustomDashboardBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = B47D3C8C23ABEDF100DE911F /* CustomDashboardBox.swift */; };
B48BD19123E73F8E00152931 /* CpuUsageMenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B48BD19023E73F8E00152931 /* CpuUsageMenuBarItem.swift */; };
+ B4924F09244A2492000D8BDD /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4924F08244A2492000D8BDD /* RepeatingTimer.swift */; };
B49CD58F23EB17D9009711E6 /* CodableColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49CD58E23EB17D9009711E6 /* CodableColor.swift */; };
B49CDFF523E1E18A0070D664 /* AppMover.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B49CDFF223E1DB9B0070D664 /* AppMover.framework */; };
B49CDFF623E1E18A0070D664 /* AppMover.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B49CDFF223E1DB9B0070D664 /* AppMover.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -61,6 +62,7 @@
B4C37E6D23A8D811008C7FC0 /* ContentManagerViewControllerHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C37E6C23A8D811008C7FC0 /* ContentManagerViewControllerHolder.swift */; };
B4C37E7023A91F3C008C7FC0 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C37E6F23A91F3C008C7FC0 /* ThemeManager.swift */; };
B4C8DD2523AA3DB8008DAE45 /* ContentManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C8DD2423AA3DB8008DAE45 /* ContentManagerView.swift */; };
+ B4C985E3244CB694002F8D3F /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C985E2244CB694002F8D3F /* Utils.swift */; };
B4CF2F7823C4F5CD00544511 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CF2F7723C4F5CD00544511 /* AppDelegate.swift */; };
B4CF2F7C23C4F5CE00544511 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B4CF2F7B23C4F5CE00544511 /* Assets.xcassets */; };
B4CF2F7F23C4F5CE00544511 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B4CF2F7D23C4F5CE00544511 /* Main.storyboard */; };
@@ -161,6 +163,7 @@
B472EC1F243101DB002F7504 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; };
B47D3C8C23ABEDF100DE911F /* CustomDashboardBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDashboardBox.swift; sourceTree = ""; };
B48BD19023E73F8E00152931 /* CpuUsageMenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CpuUsageMenuBarItem.swift; sourceTree = ""; };
+ B4924F08244A2492000D8BDD /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = ""; };
B49CD58E23EB17D9009711E6 /* CodableColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableColor.swift; sourceTree = ""; };
B49CDFF223E1DB9B0070D664 /* AppMover.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AppMover.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B49CDFF723E1E1950070D664 /* SMCKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SMCKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -176,6 +179,7 @@
B4C37E6C23A8D811008C7FC0 /* ContentManagerViewControllerHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentManagerViewControllerHolder.swift; sourceTree = ""; };
B4C37E6F23A91F3C008C7FC0 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = ""; };
B4C8DD2423AA3DB8008DAE45 /* ContentManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentManagerView.swift; sourceTree = ""; };
+ B4C985E2244CB694002F8D3F /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
B4CF2F7523C4F5CD00544511 /* iGlanceLauncher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iGlanceLauncher.app; sourceTree = BUILT_PRODUCTS_DIR; };
B4CF2F7723C4F5CD00544511 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
B4CF2F7B23C4F5CE00544511 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
@@ -305,6 +309,7 @@
B4DE727F23C2644A0001CF46 /* BatteryInfo.swift */,
B415FF2B23F45F6000ED6567 /* MemoryInfo.swift */,
B4F4AF3A23FAFBD60033B5CE /* FanInfo.swift */,
+ B4C985E2244CB694002F8D3F /* Utils.swift */,
);
path = SystemInfo;
sourceTree = "";
@@ -392,6 +397,7 @@
B4C37E6E23A91F2F008C7FC0 /* Theme */,
B4FE0DAD23EF1BCB00AE94E6 /* Utils */,
B46789B523A69ECA00CE572D /* AppDelegate.swift */,
+ B4924F08244A2492000D8BDD /* RepeatingTimer.swift */,
B472EC1F243101DB002F7504 /* Logger.swift */,
B4DE725E23C257610001CF46 /* Extensions.swift */,
B49F5D5623C5BCAF009E9BE6 /* UserSettings.swift */,
@@ -718,9 +724,11 @@
B4E909112427B33F00260479 /* BatteryMenuBarItem.swift in Sources */,
B4C37E6D23A8D811008C7FC0 /* ContentManagerViewControllerHolder.swift in Sources */,
B48BD19123E73F8E00152931 /* CpuUsageMenuBarItem.swift in Sources */,
+ B4C985E3244CB694002F8D3F /* Utils.swift in Sources */,
B4CFC47623FC393300A0ED15 /* FanViewController.swift in Sources */,
B4A0D37A242E5FD500690098 /* NetworkStatisticsMenuView.swift in Sources */,
B4E909132427B5EA00260479 /* BatteryViewController.swift in Sources */,
+ B4924F09244A2492000D8BDD /* RepeatingTimer.swift in Sources */,
B4FE0DB123EF1E0100AE94E6 /* LineGraph.swift in Sources */,
B4FE0DB323EF210500AE94E6 /* Graph.swift in Sources */,
B43ABF2A23AA32FA007F93BA /* SidebarViewController.swift in Sources */,
@@ -908,7 +916,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2.0.5;
+ CURRENT_PROJECT_VERSION = 2.0.6;
DEVELOPMENT_TEAM = J6GXEPK4NG;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = iGlance/Info.plist;
@@ -917,7 +925,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
- MARKETING_VERSION = 2.0.5;
+ MARKETING_VERSION = 2.0.6;
PRODUCT_BUNDLE_IDENTIFIER = io.github.iglance.iGlance;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -935,7 +943,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2.0.5;
+ CURRENT_PROJECT_VERSION = 2.0.6;
DEVELOPMENT_TEAM = J6GXEPK4NG;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = iGlance/Info.plist;
@@ -944,7 +952,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
- MARKETING_VERSION = 2.0.5;
+ MARKETING_VERSION = 2.0.6;
PRODUCT_BUNDLE_IDENTIFIER = io.github.iglance.iGlance;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/iGlance/iGlance/iGlance/AppDelegate.swift b/iGlance/iGlance/iGlance/AppDelegate.swift
index 10be5a7..a1eb6af 100644
--- a/iGlance/iGlance/iGlance/AppDelegate.swift
+++ b/iGlance/iGlance/iGlance/AppDelegate.swift
@@ -35,7 +35,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindow: MainWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "MainWindowController") as! MainWindowController
- var currentUpdateLoopTimer: Timer!
+ var currentUpdateLoopTimer: RepeatingTimer!
// MARK: -
// MARK: Lifecycle Functions
@@ -92,8 +92,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
*/
@objc
private func onWakeUp(notification: NSNotification) {
- // invalidate the old timer and start a new timer
- changeUpdateLoopTimeInterval(interval: AppDelegate.userSettings.settings.updateInterval)
+ // resume the timer
+ currentUpdateLoopTimer.resume()
DDLogInfo("Create a new timer after waking up from sleep")
}
@@ -102,8 +102,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
*/
@objc
private func onSleep(notification: NSNotification) {
- // invalidate currently used timer
- currentUpdateLoopTimer.invalidate()
+ // suspend the current timer
+ currentUpdateLoopTimer.suspend()
DDLogInfo("Invalidated the current timer")
}
@@ -214,8 +214,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
*
* - Returns: The newly created timer.
*/
- func createUpdateLoopTimer(interval: Double) -> Timer {
- let timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(updateLoop), userInfo: nil, repeats: true)
+ func createUpdateLoopTimer(interval: Double) -> RepeatingTimer {
+ let timer = RepeatingTimer(timeInterval: interval)
+ timer.eventHandler = updateLoop
+ timer.resume()
return timer
}
@@ -223,23 +225,20 @@ class AppDelegate: NSObject, NSApplicationDelegate {
/**
* The main update loop for the whole app. This function is called every user defined time interval.
*/
- @objc
func updateLoop() {
- AppDelegate.menuBarItemManager.updateMenuBarItems()
+ DispatchQueue.main.async {
+ AppDelegate.menuBarItemManager.updateMenuBarItems()
+ }
}
/**
* Changes the update interval of the main loop to the given time interval.
*/
func changeUpdateLoopTimeInterval(interval: Double) {
- // invalidate the currently used timer to stop it
- currentUpdateLoopTimer.invalidate()
-
- // create a new timer object
- let timer = createUpdateLoopTimer(interval: interval)
- RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
-
- currentUpdateLoopTimer = timer
+ // create a new timer instance
+ let timer = RepeatingTimer(timeInterval: interval)
+ timer.eventHandler = updateLoop
+ timer.resume()
}
// MARK: -
diff --git a/iGlance/iGlance/iGlance/Graphs/BarGraph.swift b/iGlance/iGlance/iGlance/Graphs/BarGraph.swift
index 77c11c6..5751765 100644
--- a/iGlance/iGlance/iGlance/Graphs/BarGraph.swift
+++ b/iGlance/iGlance/iGlance/Graphs/BarGraph.swift
@@ -104,13 +104,16 @@ class BarGraph: Graph {
* Takes an image and draws the bar on the given image
*/
private func drawBarGraph(image: inout NSImage, currentValue: Double, barColor: NSColor, gradientColor: NSColor?) {
+ // if the current value is zero we don't have to draw anything and can return immediately
+ if currentValue == 0 {
+ return
+ }
+
// lock the focus on the image in order to draw on it
image.lockFocus()
// get the height of the bar
- // prevent a value of zero since this would cause a bug when drawing the bar
- let value = (currentValue == 0 ? 0.1 : currentValue)
- let barHeight = Double((maxBarHeight / self.maxValue) * value)
+ let barHeight = Double((maxBarHeight / self.maxValue) * currentValue)
// draw the gradient if necessary
if gradientColor != nil {
diff --git a/iGlance/iGlance/iGlance/Graphs/LineGraph.swift b/iGlance/iGlance/iGlance/Graphs/LineGraph.swift
index c58a51f..fd84bc9 100644
--- a/iGlance/iGlance/iGlance/Graphs/LineGraph.swift
+++ b/iGlance/iGlance/iGlance/Graphs/LineGraph.swift
@@ -84,6 +84,11 @@ class LineGraph: Graph {
// iterate the values and draw a bar for each value on the correct position
var nextValuePosition = self.imageSize.width - self.borderWidth - 1
for value in valueHistory.makeIterator().reversed() {
+ // if the value is zero we don't have to draw anything and can continue with the loop
+ if value == 0 {
+ continue
+ }
+
// calculate the height of the bar
let barHeight = Double((self.maxbarHeight / self.maxValue) * value)
diff --git a/iGlance/iGlance/iGlance/Logger.swift b/iGlance/iGlance/iGlance/Logger.swift
index 207ff0f..e02758c 100644
--- a/iGlance/iGlance/iGlance/Logger.swift
+++ b/iGlance/iGlance/iGlance/Logger.swift
@@ -56,6 +56,7 @@ class Logger {
let savePanel = NSSavePanel()
savePanel.nameFieldStringValue = mostRecentLogFileUrl.lastPathComponent
+ DDLogInfo("Saving the most recent log file")
savePanel.begin { result in
if result == .OK {
var success = false
diff --git a/iGlance/iGlance/iGlance/MainWindow/MainViews/NetworkViewController.swift b/iGlance/iGlance/iGlance/MainWindow/MainViews/NetworkViewController.swift
index 6c1155a..6f70718 100644
--- a/iGlance/iGlance/iGlance/MainWindow/MainViews/NetworkViewController.swift
+++ b/iGlance/iGlance/iGlance/MainWindow/MainViews/NetworkViewController.swift
@@ -19,7 +19,11 @@ import CocoaLumberjack
class NetworkViewController: MainViewViewController {
// MARK: -
// MARK: Outlets
- @IBOutlet private var networkUsageCheckbox: NSButton!
+ @IBOutlet private var networkUsageCheckbox: NSButton! {
+ didSet {
+ networkUsageCheckbox.state = AppDelegate.userSettings.settings.network.showBandwidth ? .on : .off
+ }
+ }
// MARK: -
// MARK: Actions
diff --git a/iGlance/iGlance/iGlance/MainWindow/MainWindowController.swift b/iGlance/iGlance/iGlance/MainWindow/MainWindowController.swift
index 3f1ed3a..d3d4424 100644
--- a/iGlance/iGlance/iGlance/MainWindow/MainWindowController.swift
+++ b/iGlance/iGlance/iGlance/MainWindow/MainWindowController.swift
@@ -34,6 +34,13 @@ class MainWindowController: NSWindowController {
required init?(coder: NSCoder) {
super.init(coder: coder)
+
+ // show the dock icon if no menu bar item is visible
+ // this prevents that the app is running but the user has no means to interact with the app
+ if !AppDelegate.menuBarItemManager.menuBarItems.contains(where: { $0.statusItem.isVisible == true }) {
+ NSApp.setActivationPolicy(.regular)
+ DDLogInfo("Dock icon is shown because no menu bar icon is visible")
+ }
}
// MARK: -
diff --git a/iGlance/iGlance/iGlance/Modals/PreferenceModal/PreferenceModalViewController.swift b/iGlance/iGlance/iGlance/Modals/PreferenceModal/PreferenceModalViewController.swift
index 800edf1..40de421 100644
--- a/iGlance/iGlance/iGlance/Modals/PreferenceModal/PreferenceModalViewController.swift
+++ b/iGlance/iGlance/iGlance/Modals/PreferenceModal/PreferenceModalViewController.swift
@@ -16,7 +16,6 @@
import Cocoa
import ServiceManagement
import CocoaLumberjack
-import Sparkle
class PreferenceModalViewController: ModalViewController {
// MARK: -
@@ -153,6 +152,8 @@ class PreferenceModalViewController: ModalViewController {
AppDelegate.userSettings.settings.updateInterval = 2.0
}
+ DDLogInfo("Set the update interval to \(updateIntervalSelector.indexOfSelectedItem + 1) seconds")
+
// update the update loop timer
guard let appDelegate = AppDelegate.getInstance() else {
DDLogError("Could not retrieve the App Delegate Instance")
diff --git a/iGlance/iGlance/iGlance/RepeatingTimer.swift b/iGlance/iGlance/iGlance/RepeatingTimer.swift
new file mode 100644
index 0000000..11c4ad3
--- /dev/null
+++ b/iGlance/iGlance/iGlance/RepeatingTimer.swift
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 D0miH & Contributors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import Foundation
+
+
+/**
+ * This class is a timer that is reaping a given event handler every time interval.
+ *
+ * This class is taken from https://gist.github.com/danielgalasko/1da90276f23ea24cb3467c33d2c05768#file-repeatingtimer-swift.
+ * Huge thanks to Daniel Galasko for providing this code.
+ */
+class RepeatingTimer {
+ let timeInterval: TimeInterval
+
+ init(timeInterval: TimeInterval) {
+ self.timeInterval = timeInterval
+ }
+
+ private lazy var timer: DispatchSourceTimer = {
+ let timer = DispatchSource.makeTimerSource()
+ timer.schedule(deadline: .now() + self.timeInterval, repeating: self.timeInterval)
+ timer.setEventHandler { [weak self] in
+ self?.eventHandler?()
+ }
+ return timer
+ }()
+
+ var eventHandler: (() -> Void)?
+
+ private enum State {
+ case suspended
+ case resumed
+ }
+
+ private var state: State = .suspended
+
+ deinit {
+ timer.setEventHandler {}
+ timer.cancel()
+ /*
+ If the timer is suspended, calling cancel without resuming
+ triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
+ */
+ resume()
+ eventHandler = nil
+ }
+
+ func resume() {
+ if state == .resumed {
+ return
+ }
+ state = .resumed
+ timer.resume()
+ }
+
+ func suspend() {
+ if state == .suspended {
+ return
+ }
+ state = .suspended
+ timer.suspend()
+ }
+}
diff --git a/iGlance/iGlance/iGlance/SystemInfo/DiskInfo.swift b/iGlance/iGlance/iGlance/SystemInfo/DiskInfo.swift
index dbc1106..bbab8d4 100644
--- a/iGlance/iGlance/iGlance/SystemInfo/DiskInfo.swift
+++ b/iGlance/iGlance/iGlance/SystemInfo/DiskInfo.swift
@@ -22,17 +22,9 @@ class DiskInfo {
* disk and the second element beeing the unit (e.g. MB, GB, TB...).
*/
func getInternalDiskSize() -> (Int, String) {
- let task = Process()
- let outputPipe = Pipe()
+ guard let output = executeCommand(launchPath: "/usr/sbin/system_profiler", arguments: ["SPNVMeDataType", "SPSerialATADataType"]) else {
+ DDLogError("An error occurred while executing the system_profiler command")
- // execute the system_profiler command
- task.launchPath = "/usr/sbin/system_profiler"
- task.arguments = ["SPNVMeDataType", "SPSerialATADataType"]
- task.standardOutput = outputPipe
- task.launch()
- let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
- guard let output = String(data: outputData, encoding: String.Encoding.utf8) else {
- DDLogError("An error occurred while casting the command output to a string")
return (0, "")
}
diff --git a/iGlance/iGlance/iGlance/SystemInfo/GpuInfo.swift b/iGlance/iGlance/iGlance/SystemInfo/GpuInfo.swift
index f2982a1..375dde9 100644
--- a/iGlance/iGlance/iGlance/SystemInfo/GpuInfo.swift
+++ b/iGlance/iGlance/iGlance/SystemInfo/GpuInfo.swift
@@ -29,17 +29,8 @@ class GpuInfo {
*/
func getGpuName() -> String {
// pretty similar to https://github.com/sebhildebrandt/systeminformation/blob/master/lib/graphics.js
- let task = Process()
- let outputPipe = Pipe()
-
- // execute the system_profiler command
- task.launchPath = "/usr/sbin/system_profiler"
- task.arguments = ["SPDisplaysDataType"]
- task.standardOutput = outputPipe
- task.launch()
- let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
- guard let output = String(data: outputData, encoding: String.Encoding.utf8) else {
- DDLogError("An error occurred while casting the command output to a string")
+ guard let output = executeCommand(launchPath: "/usr/sbin/system_profiler", arguments: ["SPDisplaysDataType"]) else {
+ DDLogError("An error occurred while executing the system_profiler command")
return ""
}
diff --git a/iGlance/iGlance/iGlance/SystemInfo/NetworkInfo.swift b/iGlance/iGlance/iGlance/SystemInfo/NetworkInfo.swift
index 2444fe8..19da449 100644
--- a/iGlance/iGlance/iGlance/SystemInfo/NetworkInfo.swift
+++ b/iGlance/iGlance/iGlance/SystemInfo/NetworkInfo.swift
@@ -62,19 +62,8 @@ class NetworkInfo {
*/
func getTotalTransmittedBytesOf(interface: String) -> (up: UInt64, down: UInt64) {
// create the process to call the netstat commandline tool
- let process = Process()
- process.launchPath = "/usr/bin/env"
- process.arguments = ["netstat", "-bdnI", interface]
-
- // create a pipe to get the output of the command
- let pipe = Pipe()
- process.standardOutput = pipe
- process.launch()
-
- // get the output as a string
- let data = pipe.fileHandleForReading.readDataToEndOfFile()
- guard let commandOutput = String(data: data, encoding: String.Encoding.utf8) else {
- DDLogError("An error occurred while casting the command output to a string")
+ guard let commandOutput = executeCommand(launchPath: "/usr/bin/env", arguments: ["netstat", "-bdnI", interface]) else {
+ DDLogError("An error occurred while executing the netstat command")
return (up: 0, down: 0)
}
@@ -115,30 +104,61 @@ class NetworkInfo {
* Returns the name of the currently used network interface as a string. If something went wrong the default network interface "en0" is returned.
*/
func getCurrentlyUsedInterface() -> String {
- // create the process for the command
- let process = Process()
- process.launchPath = "/bin/bash"
- process.arguments = ["-c", "route get 0.0.0.0 2>/dev/null | grep interface: | awk '{print $2}'"]
-
- // create the pipe for the output
- let pipe = Pipe()
- process.standardOutput = pipe
- process.launch()
-
- // get the command output
- let commandOutput = pipe.fileHandleForReading.readDataToEndOfFile()
-
- DDLogInfo("Output of the network interface command: \n\(commandOutput)")
-
- // get the currently used interface
- guard let commandString = String(data: commandOutput, encoding: String.Encoding.utf8) else {
- DDLogError("Something went wrong while casting the command output to a string")
+ // idea is from https://apple.stackexchange.com/a/223446
+ // get the srvice list
+ let arguments = ["networksetup", "-listallhardwareports"]
+ guard let netCmdOutput = executeCommand(launchPath: "/usr/bin/env", arguments: arguments) else {
+ DDLogError("Something went wrong while executing the networksetup command")
return "en0"
}
+ let interfaceList = netCmdOutput.split(separator: "\n")
+ .filter { $0.contains("Device:") }
+ .map { $0.replacingOccurrences(of: "Device: ", with: "") }
- // get the interface name
- let interfaceName = commandString.trimmingCharacters(in: .whitespacesAndNewlines)
+ // the default interface is en0
+ var activeInterfaces = ["en0"]
+
+ // get all the network interfaces of ifconfig
+ guard let ifconfigInterfacesCommand = executeCommand(launchPath: "/usr/bin/env", arguments: ["ifconfig", "-lu"]) else {
+ DDLogError("Something went wrong while executing the ifconfig command to retrieve all interfaces")
+ return activeInterfaces[0]
+ }
+ let ifconfigInterfacesList = ifconfigInterfacesCommand
+ .replacingOccurrences(of: "\n", with: "")
+ .split(separator: " ")
+ .map { String($0) }
+
+ // iterate the list from top to bottom
+ for interfaceName in interfaceList where ifconfigInterfacesList.contains(interfaceName) {
+ // get more info about the current network interface
+ guard let ifconfOutput = executeCommand(launchPath: "/usr/bin/env", arguments: ["ifconfig", interfaceName]) else {
+ DDLogError("Something went wrong while executing the ifconfig command for interface \(interfaceName)")
+ continue
+ }
+
+ // get the status line
+ let statusString = ifconfOutput.split(separator: "\n")
+ .filter { $0.contains("status:") }
+ .map { $0.replacingOccurrences(of: "\tstatus: ", with: "") }
+
+ // check if the string array is empty
+ if statusString.isEmpty {
+ DDLogInfo("Could not find a status string for interface \(interfaceName)")
+ continue
+ }
+
+ // if we got more values log it, but proceed and check if one of them is active
+ if statusString.count > 1 {
+ DDLogError("Read more than one status string for interface \(interfaceName)")
+ }
+
+ if statusString.contains("active") && !activeInterfaces.contains(interfaceName) {
+ // add the active interface to the list
+ activeInterfaces.insert(interfaceName, at: 0)
+ }
+ }
- return interfaceName.isEmpty ? "en0" : interfaceName
+ // return the first interface in the list
+ return activeInterfaces[0]
}
}
diff --git a/iGlance/iGlance/iGlance/SystemInfo/Utils.swift b/iGlance/iGlance/iGlance/SystemInfo/Utils.swift
new file mode 100644
index 0000000..3269ed2
--- /dev/null
+++ b/iGlance/iGlance/iGlance/SystemInfo/Utils.swift
@@ -0,0 +1,33 @@
+//
+// Utils.swift
+// iGlance
+//
+// Created by Dominik on 19.04.20.
+// Copyright © 2020 D0miH. All rights reserved.
+//
+
+import Foundation
+import CocoaLumberjack
+
+/**
+ * Executes the program that is located at the given launch path with the given arguments.
+ *
+ * - Returns: The output of the command as a string.
+ */
+func executeCommand(launchPath: String, arguments: [String]) -> String? {
+ let task = Process()
+ let outputPipe = Pipe()
+
+ // execute the command
+ task.launchPath = launchPath
+ task.arguments = arguments
+ task.standardOutput = outputPipe
+ task.launch()
+ let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
+ guard let output = String(data: outputData, encoding: String.Encoding.utf8) else {
+ DDLogError("An error occurred while casting the command output to a string")
+ return nil
+ }
+
+ return output
+}