Skip to content

Commit 4c6d764

Browse files
committed
fix: Unable to obtain network card information
1 parent 6f0874e commit 4c6d764

File tree

2 files changed

+72
-96
lines changed

2 files changed

+72
-96
lines changed

lib/data/model/app/scripts/cmd_types.dart

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -166,18 +166,17 @@ enum WindowsStatusCmdType implements ShellCmdType {
166166
echo('echo ${SystemType.windowsSign}'),
167167
time('[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()'),
168168

169-
/// Get network interface statistics using Windows Performance Counters
169+
/// Get network interface statistics using WMI
170170
///
171-
/// Uses Get-Counter to collect network I/O metrics from all network interfaces:
172-
/// - Collects bytes received and sent per second for all network interfaces
171+
/// Uses WMI Win32_PerfRawData_Tcpip_NetworkInterface for cross-language compatibility:
173172
/// - Takes 2 samples with 1 second interval to calculate rates
174-
/// - Outputs results in JSON format for easy parsing
175-
/// - Counter paths use double backslashes to escape PowerShell string literals
176173
net(
177-
r'Get-Counter -Counter '
178-
r'"\\NetworkInterface(*)\\Bytes Received/sec", '
179-
r'"\\NetworkInterface(*)\\Bytes Sent/sec" '
180-
r'-SampleInterval 1 -MaxSamples 2 | ConvertTo-Json',
174+
r'$s1 = @(Get-WmiObject Win32_PerfRawData_Tcpip_NetworkInterface | '
175+
r'Select-Object Name, BytesReceivedPersec, BytesSentPersec, Timestamp_Sys100NS); '
176+
r'Start-Sleep -Seconds 1; '
177+
r'$s2 = @(Get-WmiObject Win32_PerfRawData_Tcpip_NetworkInterface | '
178+
r'Select-Object Name, BytesReceivedPersec, BytesSentPersec, Timestamp_Sys100NS); '
179+
r'@($s1, $s2) | ConvertTo-Json -Depth 5',
181180
),
182181
sys('(Get-ComputerInfo).OsName'),
183182
cpu(
@@ -213,19 +212,19 @@ enum WindowsStatusCmdType implements ShellCmdType {
213212
),
214213
host(r'Write-Output $env:COMPUTERNAME'),
215214

216-
/// Get disk I/O statistics using Windows Performance Counters
215+
/// Get disk I/O statistics using WMI
217216
///
218-
/// Uses Get-Counter to collect disk I/O metrics from all physical disks:
217+
/// Uses WMI Win32_PerfRawData_PerfDisk_PhysicalDisk:
219218
/// - Monitors read and write bytes per second for all physical disks
220-
/// - Takes 2 samples with 1 second interval to calculate I/O rates
221-
/// - Physical disk counters provide hardware-level I/O statistics
222-
/// - Outputs results in JSON format for parsing
223-
/// - Counter names use wildcard (*) to capture all disk instances
219+
/// - Takes 2 samples with 1 second interval to calculate rates
220+
/// - DiskReadBytesPersec and DiskWriteBytesPersec are cumulative counters
224221
diskio(
225-
r'Get-Counter -Counter '
226-
r'"\\PhysicalDisk(*)\\Disk Read Bytes/sec", '
227-
r'"\\PhysicalDisk(*)\\Disk Write Bytes/sec" '
228-
r'-SampleInterval 1 -MaxSamples 2 | ConvertTo-Json',
222+
r'$s1 = @(Get-WmiObject Win32_PerfRawData_PerfDisk_PhysicalDisk | '
223+
r'Select-Object Name, DiskReadBytesPersec, DiskWriteBytesPersec, Timestamp_Sys100NS); '
224+
r'Start-Sleep -Seconds 1; '
225+
r'$s2 = @(Get-WmiObject Win32_PerfRawData_PerfDisk_PhysicalDisk | '
226+
r'Select-Object Name, DiskReadBytesPersec, DiskWriteBytesPersec, Timestamp_Sys100NS); '
227+
r'@($s1, $s2) | ConvertTo-Json -Depth 5',
229228
),
230229
battery(
231230
'Get-WmiObject -Class Win32_Battery | '

lib/data/model/server/server_status_update_req.dart

Lines changed: 54 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -550,38 +550,33 @@ List<NetSpeedPart> _parseWindowsNetwork(String raw, int currentTime) {
550550
final dynamic jsonData = json.decode(raw);
551551
final List<NetSpeedPart> netParts = [];
552552

553-
// PowerShell Get-Counter returns a structure with CounterSamples
554-
if (jsonData is Map && jsonData.containsKey('CounterSamples')) {
555-
final samples = jsonData['CounterSamples'] as List?;
556-
if (samples != null && samples.length >= 2) {
557-
// We need 2 samples to calculate speed (interval between them)
558-
final Map<String, double> interfaceRx = {};
559-
final Map<String, double> interfaceTx = {};
560-
561-
for (final sample in samples) {
562-
final path = sample['Path']?.toString() ?? '';
563-
final cookedValue = sample['CookedValue'] as num? ?? 0;
564-
565-
if (path.contains('Bytes Received/sec')) {
566-
final interfaceName = _extractInterfaceName(path);
567-
if (interfaceName.isNotEmpty) {
568-
interfaceRx[interfaceName] = cookedValue.toDouble();
569-
}
570-
} else if (path.contains('Bytes Sent/sec')) {
571-
final interfaceName = _extractInterfaceName(path);
572-
if (interfaceName.isNotEmpty) {
573-
interfaceTx[interfaceName] = cookedValue.toDouble();
574-
}
575-
}
576-
}
577-
578-
// Create NetSpeedPart for each interface
579-
for (final interfaceName in interfaceRx.keys) {
580-
final rx = interfaceRx[interfaceName] ?? 0;
581-
final tx = interfaceTx[interfaceName] ?? 0;
582-
553+
if (jsonData is List && jsonData.length >= 2) {
554+
var sample1 = jsonData[jsonData.length - 2];
555+
var sample2 = jsonData[jsonData.length - 1];
556+
if (sample1 is Map && sample1.containsKey('value')) {
557+
sample1 = sample1['value'];
558+
}
559+
if (sample2 is Map && sample2.containsKey('value')) {
560+
sample2 = sample2['value'];
561+
}
562+
if (sample1 is List && sample2 is List && sample1.length == sample2.length) {
563+
for (int i = 0; i < sample1.length; i++) {
564+
final s1 = sample1[i];
565+
final s2 = sample2[i];
566+
final name = s1['Name']?.toString() ?? '';
567+
if (name.isEmpty || name == '_Total') continue;
568+
final rx1 = (s1['BytesReceivedPersec'] as num?)?.toDouble() ?? 0;
569+
final rx2 = (s2['BytesReceivedPersec'] as num?)?.toDouble() ?? 0;
570+
final tx1 = (s1['BytesSentPersec'] as num?)?.toDouble() ?? 0;
571+
final tx2 = (s2['BytesSentPersec'] as num?)?.toDouble() ?? 0;
572+
final time1 = (s1['Timestamp_Sys100NS'] as num?)?.toDouble() ?? 0;
573+
final time2 = (s2['Timestamp_Sys100NS'] as num?)?.toDouble() ?? 0;
574+
final timeDelta = (time2 - time1) / 10000000;
575+
if (timeDelta <= 0) continue;
576+
final rxSpeed = ((rx2 - rx1) / timeDelta).abs();
577+
final txSpeed = ((tx2 - tx1) / timeDelta).abs();
583578
netParts.add(
584-
NetSpeedPart(interfaceName, BigInt.from(rx.toInt()), BigInt.from(tx.toInt()), currentTime),
579+
NetSpeedPart(name, BigInt.from(rxSpeed.toInt()), BigInt.from(txSpeed.toInt()), currentTime),
585580
);
586581
}
587582
}
@@ -593,53 +588,42 @@ List<NetSpeedPart> _parseWindowsNetwork(String raw, int currentTime) {
593588
}
594589
}
595590

596-
String _extractInterfaceName(String path) {
597-
// Extract interface name from path like
598-
// "\\Computer\\NetworkInterface(Interface Name)\\..."
599-
final match = RegExp(r'\\NetworkInterface\(([^)]+)\)\\').firstMatch(path);
600-
return match?.group(1) ?? '';
601-
}
602-
603591
List<DiskIOPiece> _parseWindowsDiskIO(String raw, int currentTime) {
604592
try {
605593
final dynamic jsonData = json.decode(raw);
606594
final List<DiskIOPiece> diskParts = [];
607595

608-
// PowerShell Get-Counter returns a structure with CounterSamples
609-
if (jsonData is Map && jsonData.containsKey('CounterSamples')) {
610-
final samples = jsonData['CounterSamples'] as List?;
611-
if (samples != null) {
612-
final Map<String, double> diskReads = {};
613-
final Map<String, double> diskWrites = {};
614-
615-
for (final sample in samples) {
616-
final path = sample['Path']?.toString() ?? '';
617-
final cookedValue = sample['CookedValue'] as num? ?? 0;
618-
619-
if (path.contains('Disk Read Bytes/sec')) {
620-
final diskName = _extractDiskName(path);
621-
if (diskName.isNotEmpty) {
622-
diskReads[diskName] = cookedValue.toDouble();
623-
}
624-
} else if (path.contains('Disk Write Bytes/sec')) {
625-
final diskName = _extractDiskName(path);
626-
if (diskName.isNotEmpty) {
627-
diskWrites[diskName] = cookedValue.toDouble();
628-
}
629-
}
630-
}
631-
632-
// Create DiskIOPiece for each disk - convert bytes to sectors
633-
// (assuming 512 bytes per sector)
634-
for (final diskName in diskReads.keys) {
635-
final readBytes = diskReads[diskName] ?? 0;
636-
final writeBytes = diskWrites[diskName] ?? 0;
637-
final sectorsRead = (readBytes / 512).round();
638-
final sectorsWrite = (writeBytes / 512).round();
596+
if (jsonData is List && jsonData.length >= 2) {
597+
var sample1 = jsonData[jsonData.length - 2];
598+
var sample2 = jsonData[jsonData.length - 1];
599+
if (sample1 is Map && sample1.containsKey('value')) {
600+
sample1 = sample1['value'];
601+
}
602+
if (sample2 is Map && sample2.containsKey('value')) {
603+
sample2 = sample2['value'];
604+
}
605+
if (sample1 is List && sample2 is List && sample1.length == sample2.length) {
606+
for (int i = 0; i < sample1.length; i++) {
607+
final s1 = sample1[i];
608+
final s2 = sample2[i];
609+
final name = s1['Name']?.toString() ?? '';
610+
if (name.isEmpty || name == '_Total') continue;
611+
final read1 = (s1['DiskReadBytesPersec'] as num?)?.toDouble() ?? 0;
612+
final read2 = (s2['DiskReadBytesPersec'] as num?)?.toDouble() ?? 0;
613+
final write1 = (s1['DiskWriteBytesPersec'] as num?)?.toDouble() ?? 0;
614+
final write2 = (s2['DiskWriteBytesPersec'] as num?)?.toDouble() ?? 0;
615+
final time1 = (s1['Timestamp_Sys100NS'] as num?)?.toDouble() ?? 0;
616+
final time2 = (s2['Timestamp_Sys100NS'] as num?)?.toDouble() ?? 0;
617+
final timeDelta = (time2 - time1) / 10000000;
618+
if (timeDelta <= 0) continue;
619+
final readSpeed = ((read2 - read1) / timeDelta).abs();
620+
final writeSpeed = ((write2 - write1) / timeDelta).abs();
621+
final sectorsRead = (readSpeed / 512).round();
622+
final sectorsWrite = (writeSpeed / 512).round();
639623

640624
diskParts.add(
641625
DiskIOPiece(
642-
dev: diskName,
626+
dev: name,
643627
sectorsRead: sectorsRead,
644628
sectorsWrite: sectorsWrite,
645629
time: currentTime,
@@ -655,13 +639,6 @@ List<DiskIOPiece> _parseWindowsDiskIO(String raw, int currentTime) {
655639
}
656640
}
657641

658-
String _extractDiskName(String path) {
659-
// Extract disk name from path like
660-
// "\\Computer\\PhysicalDisk(Disk Name)\\..."
661-
final match = RegExp(r'\\PhysicalDisk\(([^)]+)\)\\').firstMatch(path);
662-
return match?.group(1) ?? '';
663-
}
664-
665642
void _parseWindowsTemperatures(Temperatures temps, String raw) {
666643
try {
667644
// Handle error output

0 commit comments

Comments
 (0)