diff --git a/stmx.tests/Services/LinuxSystemStatsServiceTest.cs b/stmx.tests/Services/LinuxSystemStatsServiceTest.cs index 29b80f9..de18e3e 100644 --- a/stmx.tests/Services/LinuxSystemStatsServiceTest.cs +++ b/stmx.tests/Services/LinuxSystemStatsServiceTest.cs @@ -30,7 +30,7 @@ public void Setup() [Test] public async Task TestGetBatteryCapacity_ReturnsParsedValue() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns("85"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync("85"); var result = await _service.GetBatteryCapacity(); @@ -40,18 +40,18 @@ public async Task TestGetBatteryCapacity_ReturnsParsedValue() [Test] public async Task TestGetBatteryCapacity_ReturnsNull_WhenIOException() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Throws(new IOException()); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).Throws(new IOException()); var result = await _service.GetBatteryCapacity(); - Assert.Throws(() => _service.ReadBatteryCapacityFromSysFile()); + Assert.ThrowsAsync(() => _service.ReadBatteryCapacityFromSysFile()); Assert.That(result, Is.Null); } [Test] public async Task TestGetBatteryStatus_Charging_ReturnsOneWhenCharging() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns("Charging"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync("Charging"); var result = await _service.GetBatteryStatus(); @@ -61,7 +61,7 @@ public async Task TestGetBatteryStatus_Charging_ReturnsOneWhenCharging() [Test] public async Task TestGetBatteryStatus_Charging_ReturnsOneWhenFull() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns("Full"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync("Full"); var result = await _service.GetBatteryStatus(); @@ -71,7 +71,7 @@ public async Task TestGetBatteryStatus_Charging_ReturnsOneWhenFull() [Test] public async Task TestGetBatteryStatus_Discharging_ReturnsZero() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns("Discharging"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync("Discharging"); var result = await _service.GetBatteryStatus(); @@ -81,7 +81,7 @@ public async Task TestGetBatteryStatus_Discharging_ReturnsZero() [Test] public async Task TestGetBatteryStatus_Unknown_ReturnsTwo() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns("BadValue"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync("BadValue"); var result = await _service.GetBatteryStatus(); @@ -115,16 +115,16 @@ public void TestGetBatterySysDirectory_ReturnsNullWhenNoBattery() } [Test] - public void ReadMemoryUsageFromProcFile_ParsesCorrectly() + public async Task ReadMemoryUsageFromProcFile_ParsesCorrectly() { string mockMemInfo = @" MemTotal: 16384256 kB MemAvailable: 12345678 kB "; - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns(mockMemInfo); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync(mockMemInfo); - var data = _service.ReadMemoryUsageFromProcFile(); + var data = await _service.ReadMemoryUsageFromProcFile(); Assert.That(data.Total, Is.EqualTo(16384256)); Assert.That(data.Available, Is.EqualTo(12345678)); @@ -156,7 +156,7 @@ public async Task GetMemoryUsageNumber_ReturnsFormattedString() MemAvailable: 1048576 kB "; - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns(mockMemInfo); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync(mockMemInfo); string? result = await _service.GetMemoryUsageNumber(MemoryUnits.MibiBytes); @@ -171,7 +171,7 @@ public async Task GetMemoryUsagePercent_ReturnsCorrectValue() MemAvailable: 500 kB "; - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Returns(mockMemInfo); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).ReturnsAsync(mockMemInfo); double? percent = await _service.GetMemoryUsagePercent(); @@ -181,7 +181,7 @@ public async Task GetMemoryUsagePercent_ReturnsCorrectValue() [Test] public async Task GetMemoryUsageNumber_ReturnsNull_OnIOException() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Throws(new IOException()); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).Throws(new IOException()); var result = await _service.GetMemoryUsageNumber(MemoryUnits.KiloBytes); @@ -191,7 +191,7 @@ public async Task GetMemoryUsageNumber_ReturnsNull_OnIOException() [Test] public async Task GetMemoryUsagePercent_ReturnsNull_OnIOException() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())).Throws(new IOException()); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())).Throws(new IOException()); var result = await _service.GetMemoryUsagePercent(); @@ -199,14 +199,14 @@ public async Task GetMemoryUsagePercent_ReturnsNull_OnIOException() } [Test] - public void ReadCpuUsageFromProcFile_ParsesCorrectly() + public async Task ReadCpuUsageFromProcFile_ParsesCorrectly() { string mockCpuStat = "cpu 100 200 300 400 50 60 70 80 90 100\n"; - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())) - .Returns(mockCpuStat); + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(mockCpuStat); - var cpu = _service.ReadCpuUsageFromProcFile(); + var cpu = await _service.ReadCpuUsageFromProcFile(); Assert.That(cpu.User, Is.EqualTo(100)); Assert.That(cpu.Nice, Is.EqualTo(200)); @@ -229,9 +229,9 @@ public async Task GetCpuUsagePercent_ComputesCorrectly() // Second sample slightly increased after delay string stat2 = "cpu 110 210 310 420 55 65 75 85 95 105\n"; - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns(stat1) - .Returns(stat2); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(stat1) + .ReturnsAsync(stat2); double? result = await _service.GetCpuUsagePercent(); @@ -246,9 +246,9 @@ public async Task GetCpuUsagePercent_ReturnsZero_WhenNoTimePasses() // No difference between samples: totalDiff = 0 string stat = "cpu 100 200 300 400 50 60 70 80 90 100\n"; - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns(stat) - .Returns(stat); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(stat) + .ReturnsAsync(stat); double? percent = await _service.GetCpuUsagePercent(); @@ -258,7 +258,7 @@ public async Task GetCpuUsagePercent_ReturnsZero_WhenNoTimePasses() [Test] public async Task GetCpuUsagePercent_ReturnsNull_OnIOException() { - _fileReaderMock.Setup(f => f.ReadAllText(It.IsAny())) + _fileReaderMock.Setup(f => f.ReadAllTextAsync(It.IsAny())) .Throws(new IOException()); var result = await _service.GetCpuUsagePercent(); @@ -267,25 +267,25 @@ public async Task GetCpuUsagePercent_ReturnsNull_OnIOException() } [Test] - public void ReadNetworkSpeedFromSysFile_ParsesCorrectly() + public async Task ReadNetworkSpeedFromSysFile_ParsesCorrectly() { _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true); - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("1000") // tx_bytes - .Returns("2000"); // rx_bytes + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("1000") // tx_bytes + .ReturnsAsync("2000"); // rx_bytes - var (upload, download) = _service.ReadNetworkSpeedFromSysFile("wlo1"); + var (upload, download) = await _service.ReadNetworkSpeedFromSysFile("wlo1"); Assert.That(upload, Is.EqualTo(1000 * 8)); Assert.That(download, Is.EqualTo(2000 * 8)); } [Test] - public void ReadNetworkSpeedFromSysFile_ThrowsIOException_WhenInterfaceNotFound() + public async Task ReadNetworkSpeedFromSysFile_ThrowsIOException_WhenInterfaceNotFound() { _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/eth99")).Returns(false); - Assert.Throws(() => _service.ReadNetworkSpeedFromSysFile("eth99")); + Assert.ThrowsAsync(() => _service.ReadNetworkSpeedFromSysFile("eth99")); } [Test] @@ -296,11 +296,11 @@ public async Task GetNetworkSpeed_ComputesCorrectBitsPerSecond() // First sample: 1000 tx, 2000 rx bytes // Second sample: 4000 tx, 7000 rx bytes // Over 1 second delay: upload = (4000-1000)*8 = 24000 bps, download = (7000-2000)*8 = 40000 bps - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("1000") - .Returns("2000") - .Returns("4000") - .Returns("7000"); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("1000") + .ReturnsAsync("2000") + .ReturnsAsync("4000") + .ReturnsAsync("7000"); var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Bits, "wlo1", 1); @@ -317,11 +317,11 @@ public async Task GetNetworkSpeed_ConvertsToKiloBits() // upload = (4000-1000)*8 = 24000 bps = ~23.4375 kbps // download = (7000-2000)*8 = 40000 bps = ~39.0625 kbps - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("1000") - .Returns("2000") - .Returns("4000") - .Returns("7000"); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("1000") + .ReturnsAsync("2000") + .ReturnsAsync("4000") + .ReturnsAsync("7000"); var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.KiloBits, "wlo1", 1); @@ -337,11 +337,11 @@ public async Task GetNetworkSpeed_Auto_ReturnsKiloBitsAtMinimum() _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true); // Very low speed — should still return KiloBits not Bits - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("1000") - .Returns("2000") - .Returns("1001") - .Returns("2001"); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("1000") + .ReturnsAsync("2000") + .ReturnsAsync("1001") + .ReturnsAsync("2001"); var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Auto, "wlo1", 1); @@ -355,11 +355,11 @@ public async Task GetNetworkSpeed_Auto_SelectsMegaBits_WhenSpeedIsHigh() _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true); // delta = 200_000 bytes = 1_600_000 bits > 1_048_576 → MegaBits - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("0") - .Returns("0") - .Returns("200000") - .Returns("200000"); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("0") + .ReturnsAsync("0") + .ReturnsAsync("200000") + .ReturnsAsync("200000"); var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Auto, "wlo1", 1); @@ -373,11 +373,11 @@ public async Task GetNetworkSpeed_HandlesCounterReset_Gracefully() _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true); // Counter went backwards (interface reset) - _fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny())) - .Returns("5000") - .Returns("5000") - .Returns("100") - .Returns("100"); + _fileReaderMock.SetupSequence(f => f.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync("5000") + .ReturnsAsync("5000") + .ReturnsAsync("100") + .ReturnsAsync("100"); var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Bits, "wlo1", 1); @@ -387,17 +387,17 @@ public async Task GetNetworkSpeed_HandlesCounterReset_Gracefully() } [Test] - public void ReadNetworkSpeedFromSysFile_UsesDefaultInterface_WhenPassedDefault() + public async Task ReadNetworkSpeedFromSysFile_UsesDefaultInterface_WhenPassedDefault() { string mockRoute = "Iface\tDestination\tGateway\n" + "eth0\t00000000\t0101A8C0\n"; _fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/eth0")).Returns(true); - _fileReaderMock.Setup(f => f.ReadAllText("/proc/net/route")).Returns(mockRoute); - _fileReaderMock.Setup(f => f.ReadAllText("/sys/class/net/eth0/statistics/tx_bytes")).Returns("1000"); - _fileReaderMock.Setup(f => f.ReadAllText("/sys/class/net/eth0/statistics/rx_bytes")).Returns("2000"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync("/proc/net/route")).ReturnsAsync(mockRoute); + _fileReaderMock.Setup(f => f.ReadAllTextAsync("/sys/class/net/eth0/statistics/tx_bytes")).ReturnsAsync("1000"); + _fileReaderMock.Setup(f => f.ReadAllTextAsync("/sys/class/net/eth0/statistics/rx_bytes")).ReturnsAsync("2000"); - var (upload, download) = _service.ReadNetworkSpeedFromSysFile("default"); + var (upload, download) = await _service.ReadNetworkSpeedFromSysFile("default"); Assert.That(upload, Is.EqualTo(1000 * 8)); Assert.That(download, Is.EqualTo(2000 * 8)); diff --git a/stmx/Services/LinuxSystemStatsService.cs b/stmx/Services/LinuxSystemStatsService.cs index 023f190..8d0cf65 100644 --- a/stmx/Services/LinuxSystemStatsService.cs +++ b/stmx/Services/LinuxSystemStatsService.cs @@ -8,6 +8,9 @@ public class LinuxSystemStatsService : ISystemStatsService { private readonly IFileReader _fileReader; private readonly IFileSystem _fileSystem; + private readonly Regex TotalMemoryRegex = new (@"MemTotal:\s+(\d+)"); + private readonly Regex AvailableMemoryRegex = new (@"MemAvailable:\s+(\d+)"); + private readonly Regex CpuTimesRegex = new (@"cpu\s+(\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)"); public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) { @@ -21,7 +24,7 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) { try { - return ReadBatteryCapacityFromSysFile(); + return await ReadBatteryCapacityFromSysFile(); } catch (IOException) { @@ -29,20 +32,20 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) } } - public int? ReadBatteryCapacityFromSysFile() + public async Task ReadBatteryCapacityFromSysFile() { string? batteryDir = GetBatterySysDirectory(); if (batteryDir == null) throw new IOException("No directory found for battery in /sys/class/power_supply"); - string batteryCapacity = _fileReader.ReadAllText($"/sys/class/power_supply/{batteryDir}/capacity"); + string batteryCapacity = await _fileReader.ReadAllTextAsync($"/sys/class/power_supply/{batteryDir}/capacity"); return int.Parse(batteryCapacity); } public async Task GetBatteryStatus() { try { - return ReadBatteryStatusFromSysFile(); + return await ReadBatteryStatusFromSysFile(); } catch (IOException) { @@ -50,13 +53,13 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) } } - public int? ReadBatteryStatusFromSysFile() + public async Task ReadBatteryStatusFromSysFile() { string? batteryDir = GetBatterySysDirectory(); if (batteryDir == null) throw new IOException("No directory found for battery in /sys/class/power_supply"); - string batteryStatus = _fileReader.ReadAllText($"/sys/class/power_supply/{batteryDir}/status").Trim('\n', '\r'); + string batteryStatus = (await _fileReader.ReadAllTextAsync($"/sys/class/power_supply/{batteryDir}/status")).Trim('\n', '\r'); if (batteryStatus == "Charging" || batteryStatus == "Full") return 1; else if (batteryStatus == "Discharging") @@ -82,7 +85,7 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) { try { - MemoryUsageData data = ReadMemoryUsageFromProcFile().ConvertTo(unit); + MemoryUsageData data = (await ReadMemoryUsageFromProcFile()).ConvertTo(unit); return $"{data.Used} / {data.Total}"; } catch (IOException) @@ -95,7 +98,7 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) { try { - MemoryUsageData data = ReadMemoryUsageFromProcFile(); + MemoryUsageData data = await ReadMemoryUsageFromProcFile(); double percent = ((double)data.Used / data.Total) * 100; return Math.Round(percent, 2); } @@ -106,15 +109,12 @@ public LinuxSystemStatsService(IFileReader fileReader, IFileSystem fileSystem) } // This data is always in KiloBytes - public MemoryUsageData ReadMemoryUsageFromProcFile() + public async Task ReadMemoryUsageFromProcFile() { - string totalMemoryPattern = @"MemTotal:\s+(\d+)"; - string availableMemoryPattern = @"MemAvailable:\s+(\d+)"; + string memoryInfo = await _fileReader.ReadAllTextAsync("/proc/meminfo"); - string memoryInfo = _fileReader.ReadAllText("/proc/meminfo"); - - long totalMemory = long.Parse(Regex.Matches(memoryInfo, totalMemoryPattern)[0].Groups[1].Value); - long availableMemory = long.Parse(Regex.Matches(memoryInfo, availableMemoryPattern)[0].Groups[1].Value); + long totalMemory = long.Parse(TotalMemoryRegex.Match(memoryInfo).Groups[1].Value); + long availableMemory = long.Parse(AvailableMemoryRegex.Match(memoryInfo).Groups[1].Value); return new MemoryUsageData(totalMemory, availableMemory, MemoryUnits.KiloBytes); } @@ -123,9 +123,9 @@ public MemoryUsageData ReadMemoryUsageFromProcFile() NetworkUnits unit, string network, int delaySecs) { // take two samples - var dataOld = ReadNetworkSpeedFromSysFile(network); - await Task.Delay(delaySecs * 1000); - var dataNew = ReadNetworkSpeedFromSysFile(network); + var dataOld = await ReadNetworkSpeedFromSysFile(network); + await Task.Delay(delaySecs * 1000).ConfigureAwait(false); + var dataNew = await ReadNetworkSpeedFromSysFile(network); // compute speed in bits per second // If the counter was reset to 0 for second sample @@ -151,26 +151,26 @@ public MemoryUsageData ReadMemoryUsageFromProcFile() } // Returns current values of tx and rx counters - public (long Upload, long Download) ReadNetworkSpeedFromSysFile(string network_interface = "wlo1") + public async Task<(long Upload, long Download)> ReadNetworkSpeedFromSysFile(string network_interface = "wlo1") { if (network_interface == "default") - network_interface = GetDefaultNetworkInterface(); + network_interface = await GetDefaultNetworkInterface(); string basePath = $"/sys/class/net/{network_interface}"; if (!_fileSystem.DirectoryExists(basePath)) throw new IOException($"No entry found for network {network_interface}"); - var upload = long.Parse(_fileReader.ReadAllText( + var upload = long.Parse(await _fileReader.ReadAllTextAsync( $"/sys/class/net/{network_interface}/statistics/tx_bytes")) * 8; - var download = long.Parse(_fileReader.ReadAllText( + var download = long.Parse(await _fileReader.ReadAllTextAsync( $"/sys/class/net/{network_interface}/statistics/rx_bytes")) * 8; return (upload, download); } - public string GetDefaultNetworkInterface() + public async Task GetDefaultNetworkInterface() { - var lines = _fileReader.ReadAllText("/proc/net/route").Split('\n', StringSplitOptions.RemoveEmptyEntries); + var lines = (await _fileReader.ReadAllTextAsync("/proc/net/route")).Split('\n', StringSplitOptions.RemoveEmptyEntries); // skip header line, find route with destination 00000000 (default) foreach (var line in lines.Skip(1)) { @@ -187,9 +187,9 @@ public string GetDefaultNetworkInterface() try { - var oldValue = ReadCpuUsageFromProcFile(); - await Task.Delay(delayMs); - var newValue = ReadCpuUsageFromProcFile(); + var oldValue = await ReadCpuUsageFromProcFile(); + await Task.Delay(delayMs).ConfigureAwait(false);; + var newValue = await ReadCpuUsageFromProcFile(); // compute cpu usage long idleOld = oldValue.Idle + oldValue.IOWait; @@ -220,13 +220,12 @@ public string GetDefaultNetworkInterface() } } - public CpuTimesData ReadCpuUsageFromProcFile() + public async Task ReadCpuUsageFromProcFile() { - string cpuTimesPattern = @"cpu\s+(\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)"; - - string cpuInfo = _fileReader.ReadAllText("/proc/stat"); + string cpuInfo = await _fileReader.ReadAllTextAsync("/proc/stat"); - var values = Regex.Matches(cpuInfo, cpuTimesPattern)[0].Groups; + // var values = Regex.Matches(cpuInfo, cpuTimesPattern)[0].Groups; + var values = CpuTimesRegex.Match(cpuInfo).Groups; return new CpuTimesData { @@ -244,34 +243,23 @@ public CpuTimesData ReadCpuUsageFromProcFile() } } -public class CpuTimesData -{ - public long User { set; get; } - public long Nice { set; get; } - public long System { set; get; } - public long Idle { set; get; } - public long IOWait {set; get; } - public long IRQ { set; get; } - public long SoftIRQ { set; get; } - public long Steal { get; set; } - public long Guest { get; set; } - public long GuestNice { get; set; } -} - -public class MemoryUsageData +public record struct CpuTimesData +( + long User, + long Nice, + long System, + long Idle, + long IOWait, + long IRQ, + long SoftIRQ, + long Steal, + long Guest, + long GuestNice +); + +public record MemoryUsageData(long Total, long Available, MemoryUnits Unit) { - public long Total { set; get; } - public long Available { set; get; } - public long Used { set; get; } - public MemoryUnits Unit { set; get; } - - public MemoryUsageData(long total, long available, MemoryUnits unit) - { - Total = total; - Available = available; - Used = total - available; - Unit = unit; - } + public long Used => Total - Available; public MemoryUsageData ConvertTo(MemoryUnits targetUnit) { @@ -312,17 +300,8 @@ private static double UnitToBytesFactor(MemoryUnits unit) } } -public class NetworkSpeed +public record struct NetworkSpeed(double Value, NetworkUnits Unit) { - public double Value { set; get; } - public NetworkUnits Unit { set; get; } - - public NetworkSpeed(double value, NetworkUnits unit) - { - Value = value; - Unit = unit; - } - public NetworkSpeed ConvertTo(NetworkUnits targetUnit) { return new NetworkSpeed( diff --git a/stmx/Utils/FileReader.cs b/stmx/Utils/FileReader.cs index c6367ab..91392d0 100644 --- a/stmx/Utils/FileReader.cs +++ b/stmx/Utils/FileReader.cs @@ -2,6 +2,6 @@ namespace stmx.Utils; public class FileReader : IFileReader { - public string ReadAllText(string path) => File.ReadAllText(path); + public Task ReadAllTextAsync(string path) => File.ReadAllTextAsync(path); } diff --git a/stmx/Utils/IFileReader.cs b/stmx/Utils/IFileReader.cs index 75db967..e443351 100644 --- a/stmx/Utils/IFileReader.cs +++ b/stmx/Utils/IFileReader.cs @@ -2,6 +2,6 @@ namespace stmx.Utils; public interface IFileReader { - string ReadAllText(string path); + Task ReadAllTextAsync(string path); } diff --git a/stmx/stmx.csproj b/stmx/stmx.csproj index 8973f3f..6511a34 100644 --- a/stmx/stmx.csproj +++ b/stmx/stmx.csproj @@ -29,10 +29,9 @@ true true + true true true - - true