diff --git a/lib/data/model/server/conn.dart b/lib/data/model/server/conn.dart index 132fb30a..81621717 100644 --- a/lib/data/model/server/conn.dart +++ b/lib/data/model/server/conn.dart @@ -12,20 +12,20 @@ class Conn { required this.passive, required this.fail, }); -} -Conn? parseConn(String raw) { - final lines = raw.split('\n'); - final idx = lines.lastWhere((element) => element.startsWith('Tcp:'), - orElse: () => ''); - if (idx != '') { - final vals = idx.split(Miscs.numReg); - return Conn( - maxConn: int.tryParse(vals[5]) ?? 0, - active: int.tryParse(vals[6]) ?? 0, - passive: int.tryParse(vals[7]) ?? 0, - fail: int.tryParse(vals[8]) ?? 0, - ); + static Conn? parse(String raw) { + final lines = raw.split('\n'); + final idx = lines.lastWhere((element) => element.startsWith('Tcp:'), + orElse: () => ''); + if (idx != '') { + final vals = idx.split(Miscs.numReg); + return Conn( + maxConn: int.tryParse(vals[5]) ?? 0, + active: int.tryParse(vals[6]) ?? 0, + passive: int.tryParse(vals[7]) ?? 0, + fail: int.tryParse(vals[8]) ?? 0, + ); + } + return null; } - return null; } diff --git a/lib/data/model/server/cpu.dart b/lib/data/model/server/cpu.dart index ff0a5013..2b09d2bb 100644 --- a/lib/data/model/server/cpu.dart +++ b/lib/data/model/server/cpu.dart @@ -73,9 +73,8 @@ class OneTimeCpuStatus extends TimeSeqIface { @override bool same(OneTimeCpuStatus other) => id == other.id; -} -List parseCPU(String raw) { + static List parse(String raw) { final List cpus = []; for (var item in raw.split('\n')) { @@ -97,6 +96,8 @@ List parseCPU(String raw) { } return cpus; } +} + final _bsdCpuPercentReg = RegExp(r'(\d+\.\d+)%'); diff --git a/lib/data/model/server/disk.dart b/lib/data/model/server/disk.dart index e3a2dab5..b9a3bb71 100644 --- a/lib/data/model/server/disk.dart +++ b/lib/data/model/server/disk.dart @@ -19,6 +19,40 @@ class Disk { required this.size, required this.avail, }); + + 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: vals[2], + size: vals[1], + avail: vals[3], + )); + } catch (e) { + continue; + } + } + return list; + } } class DiskIO extends TimeSeq { @@ -118,40 +152,6 @@ class DiskIOPiece extends TimeSeqIface { bool same(DiskIOPiece other) => dev == other.dev; } -List parseDisk(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: vals[2], - size: vals[1], - avail: vals[3], - )); - } catch (e) { - continue; - } - } - return list; -} - /// Issue 88 /// /// Due to performance issues, diff --git a/lib/data/model/server/memory.dart b/lib/data/model/server/memory.dart index 94d5ba58..fb144951 100644 --- a/lib/data/model/server/memory.dart +++ b/lib/data/model/server/memory.dart @@ -1,3 +1,5 @@ +import 'package:toolbox/core/extension/listx.dart'; + class Memory { final int total; final int free; @@ -17,51 +19,36 @@ class Memory { } double get usedPercent => 1 - availPercent; + + static Memory parse(String raw) { + final items = raw.split('\n').map((e) => memItemReg.firstMatch(e)).toList(); + + final total = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'MemTotal:') + ?.group(2) ?? + '1') ?? + 1; + final free = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'MemFree:') + ?.group(2) ?? + '0') ?? + 0; + final available = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'MemAvailable:') + ?.group(2) ?? + '0') ?? + 0; + + return Memory( + total: total, + free: free, + avail: available, + ); + } } final memItemReg = RegExp(r'([A-Z].+:)\s+([0-9]+) kB'); -Memory parseMem(String raw) { - final items = raw.split('\n').map((e) => memItemReg.firstMatch(e)).toList(); - - final total = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'MemTotal:', - orElse: () => null, - ) - ?.group(2) ?? - '1', - ) ?? - 1; - final free = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'MemFree:', - orElse: () => null, - ) - ?.group(2) ?? - '0', - ) ?? - 0; - final available = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'MemAvailable:', - orElse: () => null, - ) - ?.group(2) ?? - '0', - ) ?? - 0; - - return Memory( - total: total, - free: free, - avail: available, - ); -} - class Swap { final int total; final int free; @@ -81,45 +68,30 @@ class Swap { String toString() { return 'Swap{total: $total, free: $free, cached: $cached}'; } -} - -Swap parseSwap(String raw) { - final items = raw.split('\n').map((e) => memItemReg.firstMatch(e)).toList(); - - final total = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'SwapTotal:', - orElse: () => null, - ) - ?.group(2) ?? - '1', - ) ?? - 0; - final free = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'SwapFree:', - orElse: () => null, - ) - ?.group(2) ?? - '1', - ) ?? - 0; - final cached = int.tryParse( - items - .firstWhere( - (e) => e?.group(1) == 'SwapCached:', - orElse: () => null, - ) - ?.group(2) ?? - '0', - ) ?? - 0; - - return Swap( - total: total, - free: free, - cached: cached, - ); + + static Swap parse(String raw) { + final items = raw.split('\n').map((e) => memItemReg.firstMatch(e)).toList(); + + final total = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'SwapTotal:') + ?.group(2) ?? + '1') ?? + 0; + final free = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'SwapFree:') + ?.group(2) ?? + '1') ?? + 0; + final cached = int.tryParse(items + .firstWhereOrNull((e) => e?.group(1) == 'SwapCached:') + ?.group(2) ?? + '0') ?? + 0; + + return Swap( + total: total, + free: free, + cached: cached, + ); + } } diff --git a/lib/data/model/server/net_speed.dart b/lib/data/model/server/net_speed.dart index 7a12a46c..03e269c8 100644 --- a/lib/data/model/server/net_speed.dart +++ b/lib/data/model/server/net_speed.dart @@ -91,80 +91,80 @@ class NetSpeed extends TimeSeq { } String buildStandardOutput(double speed) => '${speed.convertBytes}/s'; -} -/// [raw] example: -/// Inter-| Receive | Transmit -/// face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed -/// lo: 45929941 269112 0 0 0 0 0 0 45929941 269112 0 0 0 0 0 0 -/// eth0: 48481023 505772 0 0 0 0 0 0 36002262 202307 0 0 0 0 0 0 -List parseNetSpeed(String raw, int time) { - final split = raw.split('\n'); - if (split.length < 4) { - return []; + /// [raw] example: + /// Inter-| Receive | Transmit + /// face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + /// lo: 45929941 269112 0 0 0 0 0 0 45929941 269112 0 0 0 0 0 0 + /// eth0: 48481023 505772 0 0 0 0 0 0 36002262 202307 0 0 0 0 0 0 + static List parse(String raw, int time) { + final split = raw.split('\n'); + if (split.length < 4) { + return []; + } + + final results = []; + for (final item in split.sublist(2)) { + try { + final data = item.trim().split(':'); + final device = data.first; + final bytes = data.last.trim().split(' '); + bytes.removeWhere((element) => element == ''); + final bytesIn = BigInt.parse(bytes.first); + final bytesOut = BigInt.parse(bytes[8]); + results.add(NetSpeedPart(device, bytesIn, bytesOut, time)); + } catch (_) { + continue; + } + } + return results; } - final results = []; - for (final item in split.sublist(2)) { - try { - final data = item.trim().split(':'); - final device = data.first; - final bytes = data.last.trim().split(' '); - bytes.removeWhere((element) => element == ''); - final bytesIn = BigInt.parse(bytes.first); - final bytesOut = BigInt.parse(bytes[8]); + /// [raw] example: + /// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll + /// lo0 16384 17296531 0 2524959720 17296531 0 2524959720 0 + /// lo0 16384 127 127.0.0.1 17296531 - 2524959720 17296531 - 2524959720 - + /// lo0 16384 ::1/128 ::1 17296531 - 2524959720 17296531 - 2524959720 - + /// lo0 16384 fe80::1%lo0 fe80:1::1 17296531 - 2524959720 17296531 - 2524959720 - + /// gif0* 1280 0 0 0 0 0 0 0 + /// stf0* 1280 0 0 0 0 0 0 0 + /// en0 1500 22:20:xx:xx:xx:e6 739447 0 693997876 535600 0 79008877 0 + /// en0 1500 fe80::f1:xx fe80:4::f1:xxxx:9 739447 - 693997876 535600 - 79008877 - + /// en0 1500 192.168.2 192.168.2.111 739447 - 693997876 535600 - 79008877 - + /// en0 1500 fd6b:xxxx:3 fd6b:xxxx:xxxx:0: 739447 - 693997876 535600 - 79008877 - + /// en1 1500 88:d8:xx:xx:xx:1d 0 0 0 0 0 0 0 + /// utun0 1380 0 0 0 3 0 280 0 + /// utun0 1380 fe80::xxxx: fe80:6::xxxx:xxxx 0 - 0 3 - 280 - + /// utun1 2000 0 0 0 3 0 280 0 + /// utun1 2000 fe80::xxxx: fe80:7::xxxx:xxxx 0 - 0 3 - 280 - + /// utun2 1000 0 0 0 3 0 280 0 + /// utun2 1000 fe80::xxxx: fe80:8::xxxx:xxx: 0 - 0 3 - 280 - + /// utun4 9000 746744 0 845373390 386111 0 424400998 0 + /// utun4 9000 198.18.0/16 198.18.0.1 746744 - 845373390 386111 - 424400998 - + /// en2* 1500 36:7c:xx:xx:xx:xx 0 0 0 0 0 0 0 + static List parseBsd(String raw, int time) { + final split = raw.split('\n'); + if (split.length < 2) { + return []; + } + + final results = []; + for (final item in split.sublist(1)) { + final data = item.trim().split(RegExp(r'\s+')); + final device = data[0]; + if (device.endsWith('*')) { + continue; + } + if (results.any((element) => element.device == device)) { + continue; + } + if (data.length != 11) { + continue; + } + final bytesIn = BigInt.parse(data[6]); + final bytesOut = BigInt.parse(data[9]); results.add(NetSpeedPart(device, bytesIn, bytesOut, time)); - } catch (_) { - continue; } + return results; } - return results; -} - -/// [raw] example: -/// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll -/// lo0 16384 17296531 0 2524959720 17296531 0 2524959720 0 -/// lo0 16384 127 127.0.0.1 17296531 - 2524959720 17296531 - 2524959720 - -/// lo0 16384 ::1/128 ::1 17296531 - 2524959720 17296531 - 2524959720 - -/// lo0 16384 fe80::1%lo0 fe80:1::1 17296531 - 2524959720 17296531 - 2524959720 - -/// gif0* 1280 0 0 0 0 0 0 0 -/// stf0* 1280 0 0 0 0 0 0 0 -/// en0 1500 22:20:xx:xx:xx:e6 739447 0 693997876 535600 0 79008877 0 -/// en0 1500 fe80::f1:xx fe80:4::f1:xxxx:9 739447 - 693997876 535600 - 79008877 - -/// en0 1500 192.168.2 192.168.2.111 739447 - 693997876 535600 - 79008877 - -/// en0 1500 fd6b:xxxx:3 fd6b:xxxx:xxxx:0: 739447 - 693997876 535600 - 79008877 - -/// en1 1500 88:d8:xx:xx:xx:1d 0 0 0 0 0 0 0 -/// utun0 1380 0 0 0 3 0 280 0 -/// utun0 1380 fe80::xxxx: fe80:6::xxxx:xxxx 0 - 0 3 - 280 - -/// utun1 2000 0 0 0 3 0 280 0 -/// utun1 2000 fe80::xxxx: fe80:7::xxxx:xxxx 0 - 0 3 - 280 - -/// utun2 1000 0 0 0 3 0 280 0 -/// utun2 1000 fe80::xxxx: fe80:8::xxxx:xxx: 0 - 0 3 - 280 - -/// utun4 9000 746744 0 845373390 386111 0 424400998 0 -/// utun4 9000 198.18.0/16 198.18.0.1 746744 - 845373390 386111 - 424400998 - -/// en2* 1500 36:7c:xx:xx:xx:xx 0 0 0 0 0 0 0 -List parseBsdNetSpeed(String raw, int time) { - final split = raw.split('\n'); - if (split.length < 2) { - return []; - } - - final results = []; - for (final item in split.sublist(1)) { - final data = item.trim().split(RegExp(r'\s+')); - final device = data[0]; - if (device.endsWith('*')) { - continue; - } - if (results.any((element) => element.device == device)) { - continue; - } - if (data.length != 11) { - continue; - } - final bytesIn = BigInt.parse(data[6]); - final bytesOut = BigInt.parse(data[9]); - results.add(NetSpeedPart(device, bytesIn, bytesOut, time)); - } - return results; } diff --git a/lib/data/model/server/server_status_update_req.dart b/lib/data/model/server/server_status_update_req.dart index f05f1e47..b69fa206 100644 --- a/lib/data/model/server/server_status_update_req.dart +++ b/lib/data/model/server/server_status_update_req.dart @@ -39,7 +39,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { DateTime.now().millisecondsSinceEpoch ~/ 1000; try { - final net = parseNetSpeed(StatusCmdType.net.find(segments), time); + final net = NetSpeed.parse(StatusCmdType.net.find(segments), time); req.ss.netSpeed.update(net); } catch (e, s) { Loggers.parse.warning(e, s); @@ -66,7 +66,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { } try { - final cpus = parseCPU(StatusCmdType.cpu.find(segments)); + final cpus = OneTimeCpuStatus.parse(StatusCmdType.cpu.find(segments)); req.ss.cpu.update(cpus); req.ss.temps.parse( StatusCmdType.tempType.find(segments), @@ -77,7 +77,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { } try { - final tcp = parseConn(StatusCmdType.conn.find(segments)); + final tcp = Conn.parse(StatusCmdType.conn.find(segments)); if (tcp != null) { req.ss.tcp = tcp; } @@ -86,13 +86,13 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { } try { - req.ss.disk = parseDisk(StatusCmdType.disk.find(segments)); + req.ss.disk = Disk.parse(StatusCmdType.disk.find(segments)); } catch (e, s) { Loggers.parse.warning(e, s); } try { - req.ss.mem = parseMem(StatusCmdType.mem.find(segments)); + req.ss.mem = Memory.parse(StatusCmdType.mem.find(segments)); } catch (e, s) { Loggers.parse.warning(e, s); } @@ -107,7 +107,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { } try { - req.ss.swap = parseSwap(StatusCmdType.mem.find(segments)); + req.ss.swap = Swap.parse(StatusCmdType.mem.find(segments)); } catch (e, s) { Loggers.parse.warning(e, s); } @@ -120,8 +120,7 @@ Future _getLinuxStatus(ServerStatusUpdateReq req) async { } try { - final nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments)); - req.ss.nvidia = nvidia; + req.ss.nvidia = NvidiaSmi.fromXml(StatusCmdType.nvidia.find(segments)); } catch (e, s) { Loggers.parse.warning(e, s); } @@ -148,7 +147,7 @@ Future _getBsdStatus(ServerStatusUpdateReq req) async { try { final time = int.parse(BSDStatusCmdType.time.find(segments)); - final net = parseBsdNetSpeed(BSDStatusCmdType.net.find(segments), time); + final net = NetSpeed.parseBsd(BSDStatusCmdType.net.find(segments), time); req.ss.netSpeed.update(net); } catch (e, s) { Loggers.parse.warning(e, s); @@ -182,7 +181,7 @@ Future _getBsdStatus(ServerStatusUpdateReq req) async { } try { - req.ss.disk = parseDisk(BSDStatusCmdType.disk.find(segments)); + req.ss.disk = Disk.parse(BSDStatusCmdType.disk.find(segments)); } catch (e, s) { Loggers.parse.warning(e, s); } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 040b4d75..5e135886 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:dartssh2/dartssh2.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:toolbox/core/utils/platform/path.dart'; @@ -294,13 +295,18 @@ class ServerProvider extends ChangeNotifier { if (writeResult == null || writeResult.isNotEmpty) { throw Exception('$writeResult'); } + } on SSHAuthAbortError catch (e) { + TryLimiter.inc(sid); + s.status.err = e.toString(); + _setServerState(s, ServerState.failed); + return; } catch (e) { Loggers.app.warning('Write script to ${spi.name} by shell', e); - // by sftp + + /// by sftp final localPath = joinPath(await Paths.doc, 'install.sh'); final file = File(localPath); try { - Loggers.app.info('Using SFTP to write script to ${spi.name}'); file.writeAsString(ShellFunc.allScript); final completer = Completer(); final homePath = (await s.client?.run('echo \$HOME').string)?.trim(); diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index 67de5d01..4dd69563 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -69,7 +69,8 @@ class _ServerDetailPageState extends State @override void initState() { super.initState(); - _cardsOrder.addAll(Stores.setting.detailCardOrder.fetch()); + //_cardsOrder.addAll(Stores.setting.detailCardOrder.fetch()); + _cardsOrder.addAll(_cardBuildMap.keys); } @override @@ -313,7 +314,7 @@ class _ServerDetailPageState extends State Widget _buildGpuView(ServerStatus ss) { if (ss.nvidia == null) return UIs.placeholder; - final children = ss.nvidia!.map((e) => _buildGpuItem(e)).toList(); + final children = ss.nvidia?.map((e) => _buildGpuItem(e)).toList() ?? []; return CardX( child: ExpandTile( title: const Text('GPU'), @@ -333,8 +334,25 @@ class _ServerDetailPageState extends State } return ListTile( title: Text(item.name, style: UIs.text13), + leading: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${item.percent}%', + style: UIs.text12Grey, + textScaler: _textFactor, + ), + const Divider(), + Text( + '${item.temp} °C', + style: UIs.text12Grey, + textScaler: _textFactor, + ), + ], + ), subtitle: Text( - '${item.power} - ${item.temp} °C\n${mem.used} / ${mem.total} ${mem.unit} - ${item.fanSpeed} RPM', + '${item.power} - ${item.fanSpeed} RPM\n${mem.used} / ${mem.total} ${mem.unit}', style: UIs.text12Grey, textScaler: _textFactor, ), @@ -343,11 +361,6 @@ class _ServerDetailPageState extends State mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - Text( - '${item.percent}%', - style: UIs.text12Grey, - textScaler: _textFactor, - ), IconButton( onPressed: () { final height = () { diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index 020c6b83..163f7a9a 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -18,7 +18,6 @@ import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; -import 'package:toolbox/view/widget/expand_tile.dart'; import '../../../core/persistant_store.dart'; import '../../../core/route.dart'; @@ -991,25 +990,26 @@ class _SettingPageState extends State { } Widget _buildSequence() { - return ExpandTile( - title: Text(l10n.sequence), - subtitle: Text( - '${l10n.serverOrder} / ${l10n.serverDetailOrder} ...', - style: UIs.textGrey, - ), - children: [ - ListTile( - title: Text(l10n.serverOrder), - trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.serverOrder().go(context), - ), - ListTile( - title: Text(l10n.serverDetailOrder), - trailing: const Icon(Icons.keyboard_arrow_right), - onTap: () => AppRoute.serverDetailOrder().go(context), - ), - ], + return ListTile( + title: Text(l10n.serverOrder), + trailing: const Icon(Icons.keyboard_arrow_right), + onTap: () => AppRoute.serverOrder().go(context), ); + // return ExpandTile( + // title: Text(l10n.sequence), + // subtitle: Text( + // '${l10n.serverOrder} / ${l10n.serverDetailOrder} ...', + // style: UIs.textGrey, + // ), + // children: [ + // , + // ListTile( + // title: Text(l10n.serverDetailOrder), + // trailing: const Icon(Icons.keyboard_arrow_right), + // onTap: () => AppRoute.serverDetailOrder().go(context), + // ), + // ], + // ); } Widget _buildEditorFontSize() {