opt.: display total disk space on server tab

This commit is contained in:
lollipopkit
2024-03-06 15:31:54 +08:00
parent 4e6ea086e3
commit fc00b4b961
5 changed files with 46 additions and 58 deletions

View File

@@ -1,3 +1,4 @@
import 'package:toolbox/core/extension/listx.dart';
import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/core/extension/numx.dart';
import 'package:toolbox/data/model/server/time_seq.dart'; import 'package:toolbox/data/model/server/time_seq.dart';
@@ -20,12 +21,6 @@ class Disk {
required this.avail, required this.avail,
}); });
/// raw:
/// ```
/// Filesystem 1K-blocks Used Available Use% Mounted on
/// overlay 959122528 154470540 755857572 17% /
/// tmpfs 65536 0 65536 0% /dev
/// ```
static List<Disk> parse(String raw) { static List<Disk> parse(String raw) {
final list = <Disk>[]; final list = <Disk>[];
final items = raw.split('\n'); final items = raw.split('\n');
@@ -66,22 +61,16 @@ class DiskIO extends TimeSeq<DiskIOPiece> {
@override @override
void onUpdate() { void onUpdate() {
cachedAllSpeed = _getAllSpeed();
} }
(double?, double?) _getSpeed(String dev) { (double?, double?) _getSpeed(String dev) {
final pres = this.pre.where( final old = pre.firstWhereOrNull((e) => e.dev == '/dev/$dev');
(element) => element.dev == dev.replaceFirst('/dev/', ''), final new_ = now.firstWhereOrNull((e) => e.dev == '/dev/$dev');
); if (old == null || new_ == null) return (null, null);
final nows = this.now.where( final sectorsRead = new_.sectorsRead - old.sectorsRead;
(element) => element.dev == dev.replaceFirst('/dev/', ''), final sectorsWrite = new_.sectorsWrite - old.sectorsWrite;
); final time = new_.time - old.time;
if (pres.isEmpty || nows.isEmpty) return (null, null);
final pre = pres.first;
final now = nows.first;
final sectorsRead = now.sectorsRead - pre.sectorsRead;
final sectorsWrite = now.sectorsWrite - pre.sectorsWrite;
final time = now.time - pre.time;
final read = sectorsRead / time * 512; final read = sectorsRead / time * 512;
final write = sectorsWrite / time * 512; final write = sectorsWrite / time * 512;
return (read, write); return (read, write);
@@ -95,7 +84,8 @@ class DiskIO extends TimeSeq<DiskIOPiece> {
return (read, write); return (read, write);
} }
(String?, String?) getAllSpeed() { (String?, String?) cachedAllSpeed = (null, null);
(String?, String?) _getAllSpeed() {
if (pre.isEmpty || now.isEmpty) return (null, null); if (pre.isEmpty || now.isEmpty) return (null, null);
var (read, write) = (0.0, 0.0); var (read, write) = (0.0, 0.0);
for (var pre in pre) { for (var pre in pre) {
@@ -108,18 +98,6 @@ class DiskIO extends TimeSeq<DiskIOPiece> {
return (readStr, writeStr); return (readStr, writeStr);
} }
// Raw:
// 254 0 vda 584193 186416 40419294 845790 5024458 2028159 92899586 6997559 0 5728372 8143590 0 0 0 0 2006112 300240
// 254 1 vda1 584029 186416 40412734 845668 5024453 2028159 92899586 6997558 0 5728264 7843226 0 0 0 0 0 0
// 11 0 sr0 36 0 280 49 0 0 0 0 0 56 49 0 0 0 0 0 0
// 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
static List<DiskIOPiece> parse(String raw, int time) { static List<DiskIOPiece> parse(String raw, int time) {
final lines = raw.split('\n'); final lines = raw.split('\n');
if (lines.isEmpty) return []; if (lines.isEmpty) return [];
@@ -163,25 +141,29 @@ class DiskIOPiece extends TimeSeqIface<DiskIOPiece> {
bool same(DiskIOPiece other) => dev == other.dev; bool same(DiskIOPiece other) => dev == other.dev;
} }
/// Issue 88 class DiskUsage {
/// final BigInt used;
/// Due to performance issues, final BigInt size;
/// if there is no `Disk.loc == '/' || Disk.loc == '/sysroot'`,
/// return the first [Disk] of [disks]. DiskUsage({
/// required this.used,
/// If we find out the biggest [Disk] of [disks], required this.size,
/// the fps may lower than 60. });
Disk? findRootDisk(List<Disk> disks) {
if (disks.isEmpty) return null; double get usedPercent => used / size * 100;
final roots = disks.where((element) => element.mount == '/');
if (roots.isEmpty) { /// Find all devs, add their used and size
final sysRoots = disks.where((element) => element.mount == '/sysroot'); static DiskUsage parse(List<Disk> disks) {
if (sysRoots.isEmpty) { final devs = <String>{};
return disks.first; var used = BigInt.zero;
} else { var size = BigInt.zero;
return sysRoots.first; for (var disk in disks) {
if (!disk.dev.startsWith('/dev')) continue;
if (devs.contains(disk.dev)) continue;
devs.add(disk.dev);
used += disk.used;
size += disk.size;
} }
} else { return DiskUsage(used: used, size: size);
return roots.first;
} }
} }

View File

@@ -44,7 +44,7 @@ class NetSpeed extends TimeSeq<NetSpeedPart> {
/// Issue #295 /// Issue #295
/// Non-virtual network device prefix /// Non-virtual network device prefix
static const List<String> realIfacePrefixs = ['eth', 'wlan', 'en', 'ww', 'wl']; static const realIfacePrefixs = ['eth', 'wlan', 'en', 'ww', 'wl'];
/// Cached non-virtual network device prefix /// Cached non-virtual network device prefix
final realIfaces = <String>[]; final realIfaces = <String>[];
@@ -166,7 +166,8 @@ class NetSpeed extends TimeSeq<NetSpeedPart> {
for (final item in split.sublist(2)) { for (final item in split.sublist(2)) {
try { try {
final data = item.trim().split(':'); final data = item.trim().split(':');
final device = data.first; final device = data.firstOrNull;
if (device == null) continue;
final bytes = data.last.trim().split(' '); final bytes = data.last.trim().split(' ');
bytes.removeWhere((element) => element == ''); bytes.removeWhere((element) => element == '');
final bytesIn = BigInt.parse(bytes.first); final bytesIn = BigInt.parse(bytes.first);

View File

@@ -57,6 +57,7 @@ class ServerStatus {
final List<Battery> batteries = []; final List<Battery> batteries = [];
final Map<StatusCmdType, String> more = {}; final Map<StatusCmdType, String> more = {};
final List<SensorItem> sensors = []; final List<SensorItem> sensors = [];
DiskUsage? diskUsage;
ServerStatus({ ServerStatus({
required this.cpu, required this.cpu,
@@ -70,6 +71,7 @@ class ServerStatus {
required this.diskIO, required this.diskIO,
this.err, this.err,
this.nvidia, this.nvidia,
this.diskUsage,
}); });
} }

View File

@@ -93,6 +93,7 @@ Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
try { try {
req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments)); req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments));
req.ss.diskUsage = DiskUsage.parse(req.ss.disk);
} catch (e, s) { } catch (e, s) {
Loggers.parse.warning(e, s); Loggers.parse.warning(e, s);
} }

View File

@@ -19,7 +19,6 @@ import 'package:toolbox/data/res/store.dart';
import '../../../core/route.dart'; import '../../../core/route.dart';
import '../../../data/model/app/net_view.dart'; import '../../../data/model/app/net_view.dart';
import '../../../data/model/server/disk.dart';
import '../../../data/model/server/server.dart'; import '../../../data/model/server/server.dart';
import '../../../data/model/server/server_private_info.dart'; import '../../../data/model/server/server_private_info.dart';
import '../../../data/provider/server.dart'; import '../../../data/provider/server.dart';
@@ -430,11 +429,10 @@ class _ServerPageState extends State<ServerPage>
return ListenableBuilder( return ListenableBuilder(
listenable: cardNoti, listenable: cardNoti,
builder: (_, __) { builder: (_, __) {
final rootDisk = findRootDisk(ss.disk);
final isSpeed = cardNoti.value.diskIO ?? final isSpeed = cardNoti.value.diskIO ??
!Stores.setting.serverTabPreferDiskAmount.fetch(); !Stores.setting.serverTabPreferDiskAmount.fetch();
final (r, w) = ss.diskIO.getAllSpeed(); final (r, w) = ss.diskIO.cachedAllSpeed;
return AnimatedSwitcher( return AnimatedSwitcher(
duration: const Duration(milliseconds: 377), duration: const Duration(milliseconds: 377),
@@ -442,8 +440,12 @@ class _ServerPageState extends State<ServerPage>
return FadeTransition(opacity: animation, child: child); return FadeTransition(opacity: animation, child: child);
}, },
child: _buildIOData( child: _buildIOData(
isSpeed ? '${l10n.read}:\n$r' : 'Total:\n${rootDisk?.size.kb2Str}', isSpeed
isSpeed ? '${l10n.write}:\n$w' : 'Used:\n${rootDisk?.usedPercent}%', ? '${l10n.read}:\n$r'
: 'Total:\n${ss.diskUsage?.size.kb2Str}',
isSpeed
? '${l10n.write}:\n$w'
: 'Used:\n${ss.diskUsage?.used.kb2Str}',
onTap: () { onTap: () {
cardNoti.value = cardNoti.value.copyWith(diskIO: !isSpeed); cardNoti.value = cardNoti.value.copyWith(diskIO: !isSpeed);
}, },