new & opt

new: `net` total in & out bytes
opt: i18n for `ssh`
opt: disk path ignore
This commit is contained in:
lollipopkit
2023-02-02 13:11:21 +08:00
parent 469b9fe8cd
commit c479d18714
10 changed files with 103 additions and 72 deletions

View File

@@ -1,3 +1,5 @@
import '../../res/misc.dart';
class DiskInfo { class DiskInfo {
/* /*
{ {
@@ -26,3 +28,24 @@ class DiskInfo {
this.avail, this.avail,
); );
} }
List<DiskInfo> parseDisk(String raw) {
final list = <DiskInfo>[];
final items = raw.split('\n');
items.removeAt(0);
for (var item in items) {
if (item.isEmpty) {
continue;
}
final vals = item.split(numReg);
list.add(DiskInfo(
vals[0],
vals[5],
int.parse(vals[4].replaceFirst('%', '')),
vals[2],
vals[1],
vals[3],
));
}
return list;
}

View File

@@ -36,6 +36,13 @@ class NetSpeed {
return buildStandardOutput(speedInBytesPerSecond); return buildStandardOutput(speedInBytesPerSecond);
} }
String totalIn({String? device}) {
if (_old[0].device == '' || _now[0].device == '') return '0kb';
final idx = deviceIdx(device);
final totalInBytes = _now[idx].bytesIn;
return totalInBytes.toInt().convertBytes;
}
String speedOut({String? device}) { String speedOut({String? device}) {
if (_old[0].device == '' || _now[0].device == '') return '0kb/s'; if (_old[0].device == '' || _now[0].device == '') return '0kb/s';
final idx = deviceIdx(device); final idx = deviceIdx(device);
@@ -44,6 +51,13 @@ class NetSpeed {
return buildStandardOutput(speedOutBytesPerSecond); return buildStandardOutput(speedOutBytesPerSecond);
} }
String totalOut({String? device}) {
if (_old[0].device == '' || _now[0].device == '') return '0kb';
final idx = deviceIdx(device);
final totalOutBytes = _now[idx].bytesOut;
return totalOutBytes.toInt().convertBytes;
}
int deviceIdx(String? device) { int deviceIdx(String? device) {
if (device != null) { if (device != null) {
for (var item in _now) { for (var item in _now) {
@@ -55,10 +69,15 @@ class NetSpeed {
return 0; return 0;
} }
String buildStandardOutput(double speed) => String buildStandardOutput(double speed) => '${speed.convertBytes}/s';
'${speed.convertBytes.toLowerCase()}/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
/// 1635752901
List<NetSpeedPart> parseNetSpeed(String raw) { List<NetSpeedPart> parseNetSpeed(String raw) {
final split = raw.split('\n'); final split = raw.split('\n');
if (split.length < 4) { if (split.length < 4) {

View File

@@ -1,4 +1,5 @@
import '../../../core/extension/stringx.dart'; import '../../../core/extension/stringx.dart';
import '../../res/misc.dart';
/// ///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/ /// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
@@ -42,8 +43,6 @@ class TcpStatus {
} }
} }
final numReg = RegExp(r'\s{1,}');
TcpStatus? parseTcp(String raw) { TcpStatus? parseTcp(String raw) {
final lines = raw.split('\n'); final lines = raw.split('\n');
final idx = lines.lastWhere((element) => element.startsWith('Tcp:'), final idx = lines.lastWhere((element) => element.startsWith('Tcp:'),

View File

@@ -186,12 +186,6 @@ class ServerProvider extends BusyProvider {
} }
} }
/// [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
/// 1635752901
Future<void> _getNetSpeed(ServerPrivateInfo spi, String raw) async { Future<void> _getNetSpeed(ServerPrivateInfo spi, String raw) async {
final info = _servers.firstWhere((e) => e.spi == spi); final info = _servers.firstWhere((e) => e.spi == spi);
info.status.netSpeed.update(await compute(parseNetSpeed, raw)); info.status.netSpeed.update(await compute(parseNetSpeed, raw));
@@ -211,8 +205,10 @@ class ServerProvider extends BusyProvider {
final cpus = await compute(parseCPU, raw); final cpus = await compute(parseCPU, raw);
if (cpus.isNotEmpty) { if (cpus.isNotEmpty) {
info.status.cpu info.status.cpu.update(
.update(cpus, await compute(parseCPUTemp, [tempType, tempValue])); cpus,
await compute(parseCPUTemp, [tempType, tempValue]),
);
} }
} }
@@ -229,25 +225,14 @@ class ServerProvider extends BusyProvider {
} }
} }
void _getDisk(ServerPrivateInfo spi, String raw) { Future<void> _getDisk(ServerPrivateInfo spi, String raw) async {
final info = _servers.firstWhere((e) => e.spi == spi); final info = _servers.firstWhere((e) => e.spi == spi);
final list = <DiskInfo>[]; info.status.disk = await compute(parseDisk, raw);
final items = raw.split('\n');
for (var item in items) {
if (items.indexOf(item) == 0 || item.isEmpty) {
continue;
}
final vals = item.split(numReg);
list.add(DiskInfo(vals[0], vals[5],
int.parse(vals[4].replaceFirst('%', '')), vals[2], vals[1], vals[3]));
}
info.status.disk = list;
} }
Future<void> _getMem(ServerPrivateInfo spi, String raw) async { Future<void> _getMem(ServerPrivateInfo spi, String raw) async {
final info = _servers.firstWhere((e) => e.spi == spi); final info = _servers.firstWhere((e) => e.spi == spi);
final mem = await compute(parseMem, raw); info.status.mem = await compute(parseMem, raw);
info.status.mem = mem;
} }
Future<String?> runSnippet(String id, Snippet snippet) async { Future<String?> runSnippet(String id, Snippet snippet) async {

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 210; static const int build = 211;
static const String engine = static const String engine =
"Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (9 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n"; "Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (9 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n";
static const String buildAt = "2023-02-01 23:36:32.789406"; static const String buildAt = "2023-02-02 12:40:53.962160";
static const int modifications = 0; static const int modifications = 5;
} }

View File

@@ -1 +1,3 @@
const serverMaxTryTimes = 7; const serverMaxTryTimes = 7;
final numReg = RegExp(r'\s{1,}');

View File

@@ -89,7 +89,7 @@ class MessageLookup extends MessageLookupByLibrary {
"cmd": MessageLookupByLibrary.simpleMessage("命令"), "cmd": MessageLookupByLibrary.simpleMessage("命令"),
"containerStatus": MessageLookupByLibrary.simpleMessage("容器状态"), "containerStatus": MessageLookupByLibrary.simpleMessage("容器状态"),
"convert": MessageLookupByLibrary.simpleMessage("转换"), "convert": MessageLookupByLibrary.simpleMessage("转换"),
"copy": MessageLookupByLibrary.simpleMessage("复制到剪切板"), "copy": MessageLookupByLibrary.simpleMessage("复制"),
"copyPath": MessageLookupByLibrary.simpleMessage("复制路径"), "copyPath": MessageLookupByLibrary.simpleMessage("复制路径"),
"createFile": MessageLookupByLibrary.simpleMessage("创建文件"), "createFile": MessageLookupByLibrary.simpleMessage("创建文件"),
"createFolder": MessageLookupByLibrary.simpleMessage("创建文件夹"), "createFolder": MessageLookupByLibrary.simpleMessage("创建文件夹"),

View File

@@ -20,7 +20,7 @@
"cmd": "命令", "cmd": "命令",
"containerStatus": "容器状态", "containerStatus": "容器状态",
"convert": "转换", "convert": "转换",
"copy": "复制到剪切板", "copy": "复制",
"copyPath": "复制路径", "copyPath": "复制路径",
"createFile": "创建文件", "createFile": "创建文件",
"createFolder": "创建文件夹", "createFolder": "创建文件夹",

View File

@@ -245,7 +245,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
Widget _buildDiskView(ServerStatus ss) { Widget _buildDiskView(ServerStatus ss) {
final clone = ss.disk.toList(); final clone = ss.disk.toList();
for (var item in ss.disk) { for (var item in ss.disk) {
if (ignorePath.any((ele) => item.loc.contains(ele))) { if (_ignorePath.any((ele) => item.path.startsWith(ele))) {
clone.remove(item); clone.remove(item);
} }
} }
@@ -316,10 +316,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [ children: const [
Icon( Icon(Icons.device_hub, size: 17),
Icons.device_hub,
size: 17,
),
Icon(Icons.arrow_downward, size: 17), Icon(Icons.arrow_downward, size: 17),
Icon(Icons.arrow_upward, size: 17), Icon(Icons.arrow_upward, size: 17),
], ],
@@ -328,39 +325,42 @@ class _ServerDetailPageState extends State<ServerDetailPage>
} }
Widget _buildNetSpeedItem(NetSpeed ns, String device) { Widget _buildNetSpeedItem(NetSpeed ns, String device) {
final width = (_media.size.width - 34 - 34) / 3;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 3), padding: const EdgeInsets.symmetric(vertical: 3),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
SizedBox( SizedBox(
width: _media.size.width / 4, width: width,
child: Text(device, style: textSize11, textScaleFactor: 1.0)), child: Text(
SizedBox( device,
width: _media.size.width / 4, style: textSize11,
child: Text(ns.speedIn(device: device), textScaleFactor: 1.0,
style: textSize11, ),
textAlign: TextAlign.center,
textScaleFactor: 1.0),
), ),
SizedBox( SizedBox(
width: _media.size.width / 4, width: width,
child: Text(ns.speedOut(device: device), child: Text(
style: textSize11, '${ns.speedIn(device: device)}\n${ns.totalIn(device: device)}',
textAlign: TextAlign.right, style: textSize11,
textScaleFactor: 1.0), textAlign: TextAlign.center,
textScaleFactor: 0.87,
),
),
SizedBox(
width: width,
child: Text(
'${ns.speedOut(device: device)}\n${ns.totalOut(device: device)}',
style: textSize11,
textAlign: TextAlign.right,
textScaleFactor: 0.87,
),
) )
], ],
), ),
); );
} }
static const ignorePath = [ static const _ignorePath = ['udev', 'tmpfs', 'devtmpfs'];
'/run',
'/sys',
'/dev/shm',
'/snap',
'/var/lib/docker',
'/dev/tty'
];
} }

View File

@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/generated/l10n.dart';
import 'package:xterm/xterm.dart'; import 'package:xterm/xterm.dart';
import '../../core/utils/ui.dart'; import '../../core/utils/ui.dart';
@@ -35,8 +36,9 @@ class _SSHPageState extends State<SSHPage> {
final TerminalController _terminalController = TerminalController(); final TerminalController _terminalController = TerminalController();
final ContextMenuController _menuController = ContextMenuController(); final ContextMenuController _menuController = ContextMenuController();
late TextStyle _menuTextStyle; late TextStyle _menuTextStyle;
late S _s;
var isDark = false; var _isDark = false;
@override @override
void initState() { void initState() {
@@ -47,9 +49,10 @@ class _SSHPageState extends State<SSHPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
isDark = isDarkMode(context); _isDark = isDarkMode(context);
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_menuTextStyle = TextStyle(color: contentColor.resolve(context)); _menuTextStyle = TextStyle(color: contentColor.resolve(context));
_s = S.of(context);
} }
@override @override
@@ -78,15 +81,8 @@ class _SSHPageState extends State<SSHPage> {
session.write(utf8.encode(data) as Uint8List); session.write(utf8.encode(data) as Uint8List);
}; };
session.stdout _listen(session.stdout);
.cast<List<int>>() _listen(session.stderr);
.transform(const Utf8Decoder())
.listen(_terminal.write);
session.stderr
.cast<List<int>>()
.transform(const Utf8Decoder())
.listen(_terminal.write);
await session.done; await session.done;
if (mounted) { if (mounted) {
@@ -94,9 +90,16 @@ class _SSHPageState extends State<SSHPage> {
} }
} }
void _listen(Stream<Uint8List> stream) {
stream
.cast<List<int>>()
.transform(const Utf8Decoder())
.listen(_terminal.write);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final termTheme = isDark ? termDarkTheme : termLightTheme; final termTheme = _isDark ? termDarkTheme : termLightTheme;
return Scaffold( return Scaffold(
backgroundColor: termTheme.background, backgroundColor: termTheme.background,
body: _buildBody(termTheme), body: _buildBody(termTheme),
@@ -118,7 +121,7 @@ class _SSHPageState extends State<SSHPage> {
deleteDetection: Platform.isIOS, deleteDetection: Platform.isIOS,
onTapUp: _onTapUp, onTapUp: _onTapUp,
autofocus: true, autofocus: true,
keyboardAppearance: isDark ? Brightness.dark : Brightness.light, keyboardAppearance: _isDark ? Brightness.dark : Brightness.light,
), ),
); );
} }
@@ -170,7 +173,7 @@ class _SSHPageState extends State<SSHPage> {
final child = item.icon != null final child = item.icon != null
? Icon( ? Icon(
item.icon, item.icon,
color: isDark ? Colors.white : Colors.black, color: _isDark ? Colors.white : Colors.black,
size: 17, size: 17,
) )
: Text( : Text(
@@ -296,7 +299,7 @@ class _SSHPageState extends State<SSHPage> {
children: [ children: [
TextButton( TextButton(
child: Text( child: Text(
'Copy', _s.copy,
style: _menuTextStyle, style: _menuTextStyle,
), ),
onPressed: () { onPressed: () {