mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
feat: disk smart info (#773)
This commit is contained in:
@@ -11,13 +11,13 @@ enum ServerDetailCards {
|
||||
swap(Icons.swap_horiz),
|
||||
gpu(Bootstrap.gpu_card),
|
||||
disk(Bootstrap.device_hdd_fill),
|
||||
smart(Icons.health_and_safety, sinceBuild: 1174),
|
||||
net(ZondIcons.network),
|
||||
sensor(MingCute.dashboard_4_line),
|
||||
temp(FontAwesome.temperature_empty_solid),
|
||||
battery(Icons.battery_full),
|
||||
pve(BoxIcons.bxs_dashboard, sinceBuild: 818),
|
||||
custom(Icons.code, sinceBuild: 825),
|
||||
;
|
||||
custom(Icons.code, sinceBuild: 825);
|
||||
|
||||
final int? sinceBuild;
|
||||
|
||||
@@ -31,19 +31,20 @@ enum ServerDetailCards {
|
||||
static final names = values.map((e) => e.name).toList();
|
||||
|
||||
String get toStr => switch (this) {
|
||||
about => libL10n.about,
|
||||
cpu => 'CPU',
|
||||
mem => 'RAM',
|
||||
swap => 'Swap',
|
||||
gpu => 'GPU',
|
||||
disk => l10n.disk,
|
||||
net => l10n.net,
|
||||
sensor => l10n.sensors,
|
||||
temp => l10n.temperature,
|
||||
battery => l10n.battery,
|
||||
pve => 'PVE',
|
||||
custom => l10n.cmd,
|
||||
};
|
||||
about => libL10n.about,
|
||||
cpu => 'CPU',
|
||||
mem => 'RAM',
|
||||
swap => 'Swap',
|
||||
gpu => 'GPU',
|
||||
disk => l10n.disk,
|
||||
smart => l10n.diskHealth,
|
||||
net => l10n.net,
|
||||
sensor => l10n.sensors,
|
||||
temp => l10n.temperature,
|
||||
battery => l10n.battery,
|
||||
pve => 'PVE',
|
||||
custom => l10n.cmd,
|
||||
};
|
||||
|
||||
/// If:
|
||||
/// Version 1 => user set [about], default is [about, cpu]
|
||||
|
||||
@@ -9,8 +9,7 @@ enum ShellFunc {
|
||||
process,
|
||||
shutdown,
|
||||
reboot,
|
||||
suspend,
|
||||
;
|
||||
suspend;
|
||||
|
||||
static const seperator = 'SrvBoxSep';
|
||||
|
||||
@@ -29,7 +28,9 @@ enum ShellFunc {
|
||||
/// Default is [scriptDirTmp]/[scriptFile], if this path is not accessible,
|
||||
/// it will be changed to [scriptDirHome]/[scriptFile].
|
||||
static String getScriptDir(String id) {
|
||||
final customScriptDir = ServerProvider.pick(id: id)?.value.spi.custom?.scriptDir;
|
||||
final customScriptDir = ServerProvider.pick(
|
||||
id: id,
|
||||
)?.value.spi.custom?.scriptDir;
|
||||
if (customScriptDir != null) return customScriptDir;
|
||||
return _scriptDirMap.putIfAbsent(id, () {
|
||||
return scriptDirTmp;
|
||||
@@ -37,10 +38,10 @@ enum ShellFunc {
|
||||
}
|
||||
|
||||
static void switchScriptDir(String id) => switch (_scriptDirMap[id]) {
|
||||
scriptDirTmp => _scriptDirMap[id] = scriptDirHome,
|
||||
scriptDirHome => _scriptDirMap[id] = scriptDirTmp,
|
||||
_ => _scriptDirMap[id] = scriptDirHome,
|
||||
};
|
||||
scriptDirTmp => _scriptDirMap[id] = scriptDirHome,
|
||||
scriptDirHome => _scriptDirMap[id] = scriptDirTmp,
|
||||
_ => _scriptDirMap[id] = scriptDirHome,
|
||||
};
|
||||
|
||||
static String getScriptPath(String id) {
|
||||
return '${getScriptDir(id)}/$scriptFile';
|
||||
@@ -57,13 +58,13 @@ chmod 755 $scriptPath
|
||||
}
|
||||
|
||||
String get flag => switch (this) {
|
||||
ShellFunc.process => 'p',
|
||||
ShellFunc.shutdown => 'sd',
|
||||
ShellFunc.reboot => 'r',
|
||||
ShellFunc.suspend => 'sp',
|
||||
ShellFunc.status => 's',
|
||||
// ShellFunc.docker=> 'd',
|
||||
};
|
||||
ShellFunc.process => 'p',
|
||||
ShellFunc.shutdown => 'sd',
|
||||
ShellFunc.reboot => 'r',
|
||||
ShellFunc.suspend => 'sp',
|
||||
ShellFunc.status => 's',
|
||||
// ShellFunc.docker=> 'd',
|
||||
};
|
||||
|
||||
String exec(String id) => 'sh ${getScriptPath(id)} -$flag';
|
||||
|
||||
@@ -94,14 +95,14 @@ if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
||||
else
|
||||
\t${BSDStatusCmdType.values.map((e) => e.cmd).join(cmdDivider)}
|
||||
fi''';
|
||||
// case ShellFunc.docker:
|
||||
// return '''
|
||||
// result=\$(docker version 2>&1 | grep "permission denied")
|
||||
// if [ "\$result" != "" ]; then
|
||||
// \t${_dockerCmds.join(_cmdDivider)}
|
||||
// else
|
||||
// \t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
||||
// fi''';
|
||||
// case ShellFunc.docker:
|
||||
// return '''
|
||||
// result=\$(docker version 2>&1 | grep "permission denied")
|
||||
// if [ "\$result" != "" ]; then
|
||||
// \t${_dockerCmds.join(_cmdDivider)}
|
||||
// else
|
||||
// \t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
||||
// fi''';
|
||||
case ShellFunc.process:
|
||||
return '''
|
||||
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
||||
@@ -162,7 +163,9 @@ exec 2>/dev/null
|
||||
// Write each func
|
||||
for (final func in values) {
|
||||
final customCmdsStr = () {
|
||||
if (func == ShellFunc.status && customCmds != null && customCmds.isNotEmpty) {
|
||||
if (func == ShellFunc.status &&
|
||||
customCmds != null &&
|
||||
customCmds.isNotEmpty) {
|
||||
return '$cmdDivider\n\t${customCmds.values.join(cmdDivider)}';
|
||||
}
|
||||
return '';
|
||||
@@ -209,17 +212,21 @@ enum StatusCmdType {
|
||||
cpu._('cat /proc/stat | grep cpu'),
|
||||
uptime._('uptime'),
|
||||
conn._('cat /proc/net/snmp'),
|
||||
disk._('lsblk --bytes --json --output FSTYPE,PATH,NAME,KNAME,MOUNTPOINT,FSSIZE,FSUSED,FSAVAIL,FSUSE%,UUID'),
|
||||
disk._(
|
||||
'lsblk --bytes --json --output FSTYPE,PATH,NAME,KNAME,MOUNTPOINT,FSSIZE,FSUSED,FSAVAIL,FSUSE%,UUID',
|
||||
),
|
||||
mem._("cat /proc/meminfo | grep -E 'Mem|Swap'"),
|
||||
tempType._('cat /sys/class/thermal/thermal_zone*/type'),
|
||||
tempVal._('cat /sys/class/thermal/thermal_zone*/temp'),
|
||||
host._('cat /etc/hostname'),
|
||||
diskio._('cat /proc/diskstats'),
|
||||
battery._('for f in /sys/class/power_supply/*/uevent; do cat "\$f"; echo; done'),
|
||||
battery._(
|
||||
'for f in /sys/class/power_supply/*/uevent; do cat "\$f"; echo; done',
|
||||
),
|
||||
nvidia._('nvidia-smi -q -x'),
|
||||
sensors._('sensors'),
|
||||
cpuBrand._('cat /proc/cpuinfo | grep "model name"'),
|
||||
;
|
||||
diskSmart._('for d in \$(lsblk -dn -o KNAME); do smartctl -j /dev/\$d; echo; done'),
|
||||
cpuBrand._('cat /proc/cpuinfo | grep "model name"');
|
||||
|
||||
final String cmd;
|
||||
|
||||
@@ -238,8 +245,7 @@ enum BSDStatusCmdType {
|
||||
mem._('top -l 1 | grep PhysMem'),
|
||||
//temp,
|
||||
host._('hostname'),
|
||||
cpuBrand._('sysctl -n machdep.cpu.brand_string'),
|
||||
;
|
||||
cpuBrand._('sysctl -n machdep.cpu.brand_string');
|
||||
|
||||
final String cmd;
|
||||
|
||||
@@ -248,10 +254,10 @@ enum BSDStatusCmdType {
|
||||
|
||||
extension StatusCmdTypeX on StatusCmdType {
|
||||
String get i18n => switch (this) {
|
||||
StatusCmdType.sys => l10n.system,
|
||||
StatusCmdType.host => l10n.host,
|
||||
StatusCmdType.uptime => l10n.uptime,
|
||||
StatusCmdType.battery => l10n.battery,
|
||||
final val => val.name,
|
||||
};
|
||||
StatusCmdType.sys => l10n.system,
|
||||
StatusCmdType.host => l10n.host,
|
||||
StatusCmdType.uptime => l10n.uptime,
|
||||
StatusCmdType.battery => l10n.battery,
|
||||
final val => val.name,
|
||||
};
|
||||
}
|
||||
|
||||
204
lib/data/model/server/disk_smart.dart
Normal file
204
lib/data/model/server/disk_smart.dart
Normal file
@@ -0,0 +1,204 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fl_lib/fl_lib.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'disk_smart.freezed.dart';
|
||||
part 'disk_smart.g.dart';
|
||||
|
||||
@freezed
|
||||
class DiskSmart with _$DiskSmart {
|
||||
const DiskSmart._();
|
||||
|
||||
const factory DiskSmart({
|
||||
required String device,
|
||||
bool? healthy,
|
||||
double? temperature,
|
||||
String? model,
|
||||
String? serial,
|
||||
int? powerOnHours,
|
||||
int? powerCycleCount,
|
||||
required Map<String, dynamic> rawData,
|
||||
required Map<String, SmartAttribute> smartAttributes,
|
||||
}) = _DiskSmart;
|
||||
|
||||
factory DiskSmart.fromJson(Map<String, dynamic> json) => _$DiskSmartFromJson(json);
|
||||
|
||||
static List<DiskSmart> parse(String raw) {
|
||||
final results = <DiskSmart>[];
|
||||
|
||||
final jsonBlocks = raw.split('\n\n').where((s) => s.trim().isNotEmpty);
|
||||
|
||||
for (final jsonStr in jsonBlocks) {
|
||||
try {
|
||||
final data = json.decode(jsonStr.trim()) as Map<String, dynamic>;
|
||||
|
||||
// Basic
|
||||
final device = data['device']?['name']?.toString() ?? '';
|
||||
final healthy = data['smart_status']?['passed'] as bool?;
|
||||
|
||||
// Model and Serial
|
||||
final model =
|
||||
data['model_name']?.toString() ??
|
||||
data['model_family']?.toString() ??
|
||||
data['device']?['model_name']?.toString();
|
||||
final serial = data['serial_number']?.toString() ?? data['device']?['serial_number']?.toString();
|
||||
|
||||
// SMART Attrs
|
||||
final smartAttributes = _parseSmartAttributes(data);
|
||||
final temperature = _extractTemperature(data, smartAttributes);
|
||||
final powerOnHours =
|
||||
data['power_on_time']?['hours'] as int? ?? smartAttributes['Power_On_Hours']?.rawValue as int?;
|
||||
final powerCycleCount =
|
||||
data['power_cycle_count'] as int? ?? smartAttributes['Power_Cycle_Count']?.rawValue as int?;
|
||||
|
||||
results.add(
|
||||
DiskSmart(
|
||||
device: device,
|
||||
healthy: healthy,
|
||||
temperature: temperature,
|
||||
model: model,
|
||||
serial: serial,
|
||||
powerOnHours: powerOnHours,
|
||||
powerCycleCount: powerCycleCount,
|
||||
rawData: data,
|
||||
smartAttributes: smartAttributes,
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Loggers.app.warning('DiskSmart parse', e, s);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static Map<String, SmartAttribute> _parseSmartAttributes(Map<String, dynamic> data) {
|
||||
final attributes = <String, SmartAttribute>{};
|
||||
|
||||
final attrTable = data['ata_smart_attributes']?['table'] as List?;
|
||||
if (attrTable == null) return attributes;
|
||||
|
||||
for (final attr in attrTable) {
|
||||
if (attr is Map<String, dynamic>) {
|
||||
final name = attr['name']?.toString();
|
||||
if (name != null) {
|
||||
attributes[name] = SmartAttribute(
|
||||
id: attr['id'] as int?,
|
||||
name: name,
|
||||
value: attr['value'] as int?,
|
||||
worst: attr['worst'] as int?,
|
||||
thresh: attr['thresh'] as int?,
|
||||
whenFailed: attr['when_failed']?.toString(),
|
||||
rawValue: attr['raw']?['value'],
|
||||
rawString: attr['raw']?['string']?.toString(),
|
||||
flags: SmartAttributeFlags.fromMap(attr['flags'] as Map<String, dynamic>? ?? {}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
static final _tempReg = RegExp(r'^(\d+(?:\.\d+)?)');
|
||||
|
||||
/// Extract temperature from the data
|
||||
static double? _extractTemperature(Map<String, dynamic> data, Map<String, SmartAttribute> attrs) {
|
||||
// Directly
|
||||
final directTemp = data['temperature']?['current'];
|
||||
if (directTemp is num) return directTemp.toDouble();
|
||||
|
||||
// SMART attribute
|
||||
final tempAttr = attrs['Temperature_Celsius'];
|
||||
if (tempAttr != null) {
|
||||
// "35 (Min/Max 14/61)"
|
||||
final rawString = tempAttr.rawString;
|
||||
if (rawString != null) {
|
||||
final match = _tempReg.firstMatch(rawString);
|
||||
if (match != null) {
|
||||
return double.tryParse(match.group(1)!);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple numeric value
|
||||
if (tempAttr.rawValue is num && tempAttr.rawValue! < 150) {
|
||||
return tempAttr.rawValue!.toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get the specific SMART attribute by name
|
||||
SmartAttribute? getAttribute(String name) => smartAttributes[name];
|
||||
|
||||
int? get ssdLifeLeft => smartAttributes['SSD_Life_Left']?.rawValue as int?;
|
||||
int? get lifetimeWritesGiB => smartAttributes['Lifetime_Writes_GiB']?.rawValue as int?;
|
||||
int? get lifetimeReadsGiB => smartAttributes['Lifetime_Reads_GiB']?.rawValue as int?;
|
||||
int? get unsafeShutdownCount => smartAttributes['Unsafe_Shutdown_Count']?.rawValue as int?;
|
||||
int? get averageEraseCount => smartAttributes['Average_Erase_Count']?.rawValue as int?;
|
||||
int? get maxEraseCount => smartAttributes['Max_Erase_Count']?.rawValue as int?;
|
||||
|
||||
@override
|
||||
String toString() => 'DiskSmart($device)';
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SmartAttribute with _$SmartAttribute {
|
||||
const SmartAttribute._();
|
||||
|
||||
const factory SmartAttribute({
|
||||
int? id,
|
||||
required String name,
|
||||
int? value,
|
||||
int? worst,
|
||||
int? thresh,
|
||||
String? whenFailed,
|
||||
dynamic rawValue,
|
||||
String? rawString,
|
||||
required SmartAttributeFlags flags,
|
||||
}) = _SmartAttribute;
|
||||
|
||||
factory SmartAttribute.fromJson(Map<String, dynamic> json) => _$SmartAttributeFromJson(json);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SmartAttribute(id: $id, name: $name)';
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SmartAttributeFlags with _$SmartAttributeFlags {
|
||||
const SmartAttributeFlags._();
|
||||
|
||||
const factory SmartAttributeFlags({
|
||||
int? value,
|
||||
String? string,
|
||||
@Default(false) bool prefailure,
|
||||
@Default(false) bool updatedOnline,
|
||||
@Default(false) bool performance,
|
||||
@Default(false) bool errorRate,
|
||||
@Default(false) bool eventCount,
|
||||
@Default(false) bool autoKeep,
|
||||
}) = _SmartAttributeFlags;
|
||||
|
||||
factory SmartAttributeFlags.fromJson(Map<String, dynamic> json) => _$SmartAttributeFlagsFromJson(json);
|
||||
|
||||
factory SmartAttributeFlags.fromMap(Map<String, dynamic> map) {
|
||||
return SmartAttributeFlags(
|
||||
value: map['value'] as int?,
|
||||
string: map['string']?.toString(),
|
||||
prefailure: map['prefailure'] == true,
|
||||
updatedOnline: map['updated_online'] == true,
|
||||
performance: map['performance'] == true,
|
||||
errorRate: map['error_rate'] == true,
|
||||
eventCount: map['event_count'] == true,
|
||||
autoKeep: map['auto_keep'] == true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SmartAttributeFlags(value: $value, string: $string)';
|
||||
}
|
||||
}
|
||||
1038
lib/data/model/server/disk_smart.freezed.dart
Normal file
1038
lib/data/model/server/disk_smart.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
91
lib/data/model/server/disk_smart.g.dart
Normal file
91
lib/data/model/server/disk_smart.g.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'disk_smart.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$DiskSmartImpl _$$DiskSmartImplFromJson(Map<String, dynamic> json) =>
|
||||
_$DiskSmartImpl(
|
||||
device: json['device'] as String,
|
||||
healthy: json['healthy'] as bool?,
|
||||
temperature: (json['temperature'] as num?)?.toDouble(),
|
||||
model: json['model'] as String?,
|
||||
serial: json['serial'] as String?,
|
||||
powerOnHours: (json['powerOnHours'] as num?)?.toInt(),
|
||||
powerCycleCount: (json['powerCycleCount'] as num?)?.toInt(),
|
||||
rawData: json['rawData'] as Map<String, dynamic>,
|
||||
smartAttributes: (json['smartAttributes'] as Map<String, dynamic>).map(
|
||||
(k, e) =>
|
||||
MapEntry(k, SmartAttribute.fromJson(e as Map<String, dynamic>)),
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$DiskSmartImplToJson(_$DiskSmartImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'device': instance.device,
|
||||
'healthy': instance.healthy,
|
||||
'temperature': instance.temperature,
|
||||
'model': instance.model,
|
||||
'serial': instance.serial,
|
||||
'powerOnHours': instance.powerOnHours,
|
||||
'powerCycleCount': instance.powerCycleCount,
|
||||
'rawData': instance.rawData,
|
||||
'smartAttributes': instance.smartAttributes,
|
||||
};
|
||||
|
||||
_$SmartAttributeImpl _$$SmartAttributeImplFromJson(Map<String, dynamic> json) =>
|
||||
_$SmartAttributeImpl(
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
name: json['name'] as String,
|
||||
value: (json['value'] as num?)?.toInt(),
|
||||
worst: (json['worst'] as num?)?.toInt(),
|
||||
thresh: (json['thresh'] as num?)?.toInt(),
|
||||
whenFailed: json['whenFailed'] as String?,
|
||||
rawValue: json['rawValue'],
|
||||
rawString: json['rawString'] as String?,
|
||||
flags: SmartAttributeFlags.fromJson(
|
||||
json['flags'] as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SmartAttributeImplToJson(
|
||||
_$SmartAttributeImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'name': instance.name,
|
||||
'value': instance.value,
|
||||
'worst': instance.worst,
|
||||
'thresh': instance.thresh,
|
||||
'whenFailed': instance.whenFailed,
|
||||
'rawValue': instance.rawValue,
|
||||
'rawString': instance.rawString,
|
||||
'flags': instance.flags,
|
||||
};
|
||||
|
||||
_$SmartAttributeFlagsImpl _$$SmartAttributeFlagsImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$SmartAttributeFlagsImpl(
|
||||
value: (json['value'] as num?)?.toInt(),
|
||||
string: json['string'] as String?,
|
||||
prefailure: json['prefailure'] as bool? ?? false,
|
||||
updatedOnline: json['updatedOnline'] as bool? ?? false,
|
||||
performance: json['performance'] as bool? ?? false,
|
||||
errorRate: json['errorRate'] as bool? ?? false,
|
||||
eventCount: json['eventCount'] as bool? ?? false,
|
||||
autoKeep: json['autoKeep'] as bool? ?? false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SmartAttributeFlagsImplToJson(
|
||||
_$SmartAttributeFlagsImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'value': instance.value,
|
||||
'string': instance.string,
|
||||
'prefailure': instance.prefailure,
|
||||
'updatedOnline': instance.updatedOnline,
|
||||
'performance': instance.performance,
|
||||
'errorRate': instance.errorRate,
|
||||
'eventCount': instance.eventCount,
|
||||
'autoKeep': instance.autoKeep,
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import 'package:server_box/data/model/server/battery.dart';
|
||||
import 'package:server_box/data/model/server/conn.dart';
|
||||
import 'package:server_box/data/model/server/cpu.dart';
|
||||
import 'package:server_box/data/model/server/disk.dart';
|
||||
import 'package:server_box/data/model/server/disk_smart.dart';
|
||||
import 'package:server_box/data/model/server/memory.dart';
|
||||
import 'package:server_box/data/model/server/net_speed.dart';
|
||||
import 'package:server_box/data/model/server/nvdia.dart';
|
||||
@@ -19,12 +20,7 @@ class Server {
|
||||
SSHClient? client;
|
||||
ServerConn conn;
|
||||
|
||||
Server(
|
||||
this.spi,
|
||||
this.status,
|
||||
this.conn, {
|
||||
this.client,
|
||||
});
|
||||
Server(this.spi, this.status, this.conn, {this.client});
|
||||
|
||||
bool get needGenClient => conn < ServerConn.connecting;
|
||||
|
||||
@@ -44,6 +40,7 @@ class ServerStatus {
|
||||
SystemType system;
|
||||
Err? err;
|
||||
DiskIO diskIO;
|
||||
List<DiskSmart> diskSmart;
|
||||
List<NvidiaSmiItem>? nvidia;
|
||||
final List<Battery> batteries = [];
|
||||
final Map<StatusCmdType, String> more = {};
|
||||
@@ -61,6 +58,7 @@ class ServerStatus {
|
||||
required this.temps,
|
||||
required this.system,
|
||||
required this.diskIO,
|
||||
this.diskSmart = const [],
|
||||
this.err,
|
||||
this.nvidia,
|
||||
this.diskUsage,
|
||||
|
||||
@@ -85,7 +85,9 @@ extension Spix on Spi {
|
||||
VNode<Server>? get jumpServer => ServerProvider.pick(id: jumpId);
|
||||
|
||||
bool shouldReconnect(Spi old) {
|
||||
return id != old.id ||
|
||||
return user != old.user ||
|
||||
ip != old.ip ||
|
||||
port != old.port ||
|
||||
pwd != old.pwd ||
|
||||
keyId != old.keyId ||
|
||||
alterUrl != old.alterUrl ||
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:server_box/data/model/server/battery.dart';
|
||||
import 'package:server_box/data/model/server/conn.dart';
|
||||
import 'package:server_box/data/model/server/cpu.dart';
|
||||
import 'package:server_box/data/model/server/disk.dart';
|
||||
import 'package:server_box/data/model/server/disk_smart.dart';
|
||||
import 'package:server_box/data/model/server/memory.dart';
|
||||
import 'package:server_box/data/model/server/net_speed.dart';
|
||||
import 'package:server_box/data/model/server/nvdia.dart';
|
||||
@@ -37,7 +38,8 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
|
||||
Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
||||
final segments = req.segments;
|
||||
|
||||
final time = int.tryParse(StatusCmdType.time.find(segments)) ??
|
||||
final time =
|
||||
int.tryParse(StatusCmdType.time.find(segments)) ??
|
||||
DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
|
||||
try {
|
||||
@@ -48,9 +50,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
||||
}
|
||||
|
||||
try {
|
||||
final sys = _parseSysVer(
|
||||
StatusCmdType.sys.find(segments),
|
||||
);
|
||||
final sys = _parseSysVer(StatusCmdType.sys.find(segments));
|
||||
if (sys != null) {
|
||||
req.ss.more[StatusCmdType.sys] = sys;
|
||||
}
|
||||
@@ -130,6 +130,13 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
|
||||
Loggers.app.warning(e, s);
|
||||
}
|
||||
|
||||
try {
|
||||
final smarts = DiskSmart.parse(StatusCmdType.diskSmart.find(segments));
|
||||
req.ss.diskSmart = smarts;
|
||||
} catch (e, s) {
|
||||
Loggers.app.warning(e, s);
|
||||
}
|
||||
|
||||
try {
|
||||
req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments));
|
||||
} catch (e, s) {
|
||||
|
||||
Reference in New Issue
Block a user