opt. & rm: server detail cards seq

This commit is contained in:
lollipopkit
2023-12-25 14:02:46 +08:00
parent 527e161264
commit 3a3ba4de37
9 changed files with 232 additions and 241 deletions

View File

@@ -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;
}

View File

@@ -73,9 +73,8 @@ class OneTimeCpuStatus extends TimeSeqIface<OneTimeCpuStatus> {
@override
bool same(OneTimeCpuStatus other) => id == other.id;
}
List<OneTimeCpuStatus> parseCPU(String raw) {
static List<OneTimeCpuStatus> parse(String raw) {
final List<OneTimeCpuStatus> cpus = [];
for (var item in raw.split('\n')) {
@@ -97,6 +96,8 @@ List<OneTimeCpuStatus> parseCPU(String raw) {
}
return cpus;
}
}
final _bsdCpuPercentReg = RegExp(r'(\d+\.\d+)%');

View File

@@ -19,6 +19,40 @@ class Disk {
required this.size,
required this.avail,
});
static List<Disk> parse(String raw) {
final list = <Disk>[];
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<DiskIOPiece> {
@@ -118,40 +152,6 @@ class DiskIOPiece extends TimeSeqIface<DiskIOPiece> {
bool same(DiskIOPiece other) => dev == other.dev;
}
List<Disk> parseDisk(String raw) {
final list = <Disk>[];
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,

View File

@@ -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,
);
}
}

View File

@@ -91,80 +91,80 @@ class NetSpeed extends TimeSeq<NetSpeedPart> {
}
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<NetSpeedPart> 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<NetSpeedPart> parse(String raw, int time) {
final split = raw.split('\n');
if (split.length < 4) {
return [];
}
final results = <NetSpeedPart>[];
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 = <NetSpeedPart>[];
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 <Link#1> 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 <Link#2> 0 0 0 0 0 0 0
/// stf0* 1280 <Link#3> 0 0 0 0 0 0 0
/// en0 1500 <Link#4> 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 <Link#5> 88:d8:xx:xx:xx:1d 0 0 0 0 0 0 0
/// utun0 1380 <Link#6> 0 0 0 3 0 280 0
/// utun0 1380 fe80::xxxx: fe80:6::xxxx:xxxx 0 - 0 3 - 280 -
/// utun1 2000 <Link#7> 0 0 0 3 0 280 0
/// utun1 2000 fe80::xxxx: fe80:7::xxxx:xxxx 0 - 0 3 - 280 -
/// utun2 1000 <Link#8> 0 0 0 3 0 280 0
/// utun2 1000 fe80::xxxx: fe80:8::xxxx:xxx: 0 - 0 3 - 280 -
/// utun4 9000 <Link#10> 746744 0 845373390 386111 0 424400998 0
/// utun4 9000 198.18.0/16 198.18.0.1 746744 - 845373390 386111 - 424400998 -
/// en2* 1500 <Link#11> 36:7c:xx:xx:xx:xx 0 0 0 0 0 0 0
static List<NetSpeedPart> parseBsd(String raw, int time) {
final split = raw.split('\n');
if (split.length < 2) {
return [];
}
final results = <NetSpeedPart>[];
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 <Link#1> 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 <Link#2> 0 0 0 0 0 0 0
/// stf0* 1280 <Link#3> 0 0 0 0 0 0 0
/// en0 1500 <Link#4> 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 <Link#5> 88:d8:xx:xx:xx:1d 0 0 0 0 0 0 0
/// utun0 1380 <Link#6> 0 0 0 3 0 280 0
/// utun0 1380 fe80::xxxx: fe80:6::xxxx:xxxx 0 - 0 3 - 280 -
/// utun1 2000 <Link#7> 0 0 0 3 0 280 0
/// utun1 2000 fe80::xxxx: fe80:7::xxxx:xxxx 0 - 0 3 - 280 -
/// utun2 1000 <Link#8> 0 0 0 3 0 280 0
/// utun2 1000 fe80::xxxx: fe80:8::xxxx:xxx: 0 - 0 3 - 280 -
/// utun4 9000 <Link#10> 746744 0 845373390 386111 0 424400998 0
/// utun4 9000 198.18.0/16 198.18.0.1 746744 - 845373390 386111 - 424400998 -
/// en2* 1500 <Link#11> 36:7c:xx:xx:xx:xx 0 0 0 0 0 0 0
List<NetSpeedPart> parseBsdNetSpeed(String raw, int time) {
final split = raw.split('\n');
if (split.length < 2) {
return [];
}
final results = <NetSpeedPart>[];
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;
}

View File

@@ -39,7 +39,7 @@ Future<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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<ServerStatus> _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);
}

View File

@@ -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();

View File

@@ -69,7 +69,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
@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<ServerDetailPage>
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<ServerDetailPage>
}
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<ServerDetailPage>
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${item.percent}%',
style: UIs.text12Grey,
textScaler: _textFactor,
),
IconButton(
onPressed: () {
final height = () {

View File

@@ -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<SettingPage> {
}
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() {