import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/data/model/server/time_seq.dart'; import '../../res/misc.dart'; class Disk { final String dev; final String mount; final int usedPercent; final BigInt used; final BigInt size; final BigInt avail; const Disk({ required this.dev, required this.mount, required this.usedPercent, required this.used, required this.size, 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 parse(String raw) { final list = []; final items = raw.split('\n'); items.removeAt(0); var pathCache = ''; for (var item in items) { if (item.isEmpty) { continue; } final vals = item.split(Miscs.numReg); if (vals.length == 1) { pathCache = vals[0]; continue; } if (pathCache != '') { vals[0] = pathCache; pathCache = ''; } try { list.add(Disk( dev: vals[0], mount: vals[5], usedPercent: int.parse(vals[4].replaceFirst('%', '')), used: BigInt.tryParse(vals[2]) ?? BigInt.zero, size: BigInt.tryParse(vals[1]) ?? BigInt.one, avail: BigInt.tryParse(vals[3]) ?? BigInt.one, )); } catch (e) { continue; } } return list; } } class DiskIO extends TimeSeq { DiskIO(super.pre, super.now); @override void onUpdate() { } (double?, double?) _getSpeed(String dev) { final pres = this.pre.where( (element) => element.dev == dev.replaceFirst('/dev/', ''), ); final nows = this.now.where( (element) => element.dev == dev.replaceFirst('/dev/', ''), ); 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 write = sectorsWrite / time * 512; return (read, write); } (String?, String?) getSpeed(String dev) { final (read_, write_) = _getSpeed(dev); if (read_ == null || write_ == null) return (null, null); final read = '${read_.bytes2Str}/s'; final write = '${write_.bytes2Str}/s'; return (read, write); } (String?, String?) getAllSpeed() { if (pre.isEmpty || now.isEmpty) return (null, null); var (read, write) = (0.0, 0.0); for (var pre in pre) { final (read_, write_) = _getSpeed(pre.dev); read += read_ ?? 0; write += write_ ?? 0; } final readStr = '${read.bytes2Str}/s'; final writeStr = '${write.bytes2Str}/s'; 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 parse(String raw, int time) { final lines = raw.split('\n'); if (lines.isEmpty) return []; final items = []; for (var item in lines) { item = item.trim(); if (item.isEmpty) continue; final vals = item.split(Miscs.blankReg); if (vals.length < 10) continue; try { final dev = vals[2]; if (dev.startsWith('loop')) continue; items.add(DiskIOPiece( dev: dev, sectorsRead: int.parse(vals[5]), sectorsWrite: int.parse(vals[9]), time: time, )); } catch (e) { continue; } } return items; } } class DiskIOPiece extends TimeSeqIface { final String dev; final int sectorsRead; final int sectorsWrite; final int time; DiskIOPiece({ required this.dev, required this.sectorsRead, required this.sectorsWrite, required this.time, }); @override bool same(DiskIOPiece other) => dev == other.dev; } /// Issue 88 /// /// Due to performance issues, /// if there is no `Disk.loc == '/' || Disk.loc == '/sysroot'`, /// return the first [Disk] of [disks]. /// /// If we find out the biggest [Disk] of [disks], /// the fps may lower than 60. Disk? findRootDisk(List disks) { if (disks.isEmpty) return null; final roots = disks.where((element) => element.mount == '/'); if (roots.isEmpty) { final sysRoots = disks.where((element) => element.mount == '/sysroot'); if (sysRoots.isEmpty) { return disks.first; } else { return sysRoots.first; } } else { return roots.first; } }