opt.: refactor AppShellFunc

This commit is contained in:
lollipopkit
2023-08-05 15:19:37 +08:00
parent 432e3b1824
commit c406d92b82
6 changed files with 98 additions and 80 deletions

View File

@@ -1,22 +1,46 @@
import '../../res/server_cmd.dart'; import '../../res/server_cmd.dart';
class AppShellFunc { const _cmdDivider = '\necho $seperator\n';
final String name;
final String cmd;
final String flag;
const AppShellFunc(this.name, this.cmd, this.flag); enum AppShellFuncType {
status,
docker;
String get exec => 'sh $shellPath -$flag'; String get flag {
switch (this) {
case AppShellFuncType.status:
return 's';
case AppShellFuncType.docker:
return 'd';
}
} }
typedef AppShellFuncs = List<AppShellFunc>; String get exec => 'sh $shellPath -$flag';
extension AppShellFuncsExt on AppShellFuncs { String get name {
String get generate { switch (this) {
case AppShellFuncType.status:
return 'status';
case AppShellFuncType.docker:
/// `dockeR` -> avoid conflict with `docker` command
/// 以防止循环递归
return 'dockeR';
}
}
String get cmd {
switch (this) {
case AppShellFuncType.status:
return statusCmds.join(_cmdDivider);
case AppShellFuncType.docker:
return dockerCmds.join(_cmdDivider);
}
}
static String get shellScript {
final sb = StringBuffer(); final sb = StringBuffer();
// Write each func // Write each func
for (final func in this) { for (final func in values) {
sb.write(''' sb.write('''
${func.name}() { ${func.name}() {
${func.cmd} ${func.cmd}
@@ -27,7 +51,7 @@ ${func.cmd}
// Write switch case // Write switch case
sb.write('case \$1 in\n'); sb.write('case \$1 in\n');
for (final func in this) { for (final func in values) {
sb.write(''' sb.write('''
'-${func.flag}') '-${func.flag}')
${func.name} ${func.name}
@@ -38,13 +62,43 @@ ${func.cmd}
*) *)
echo "Invalid argument \$1" echo "Invalid argument \$1"
;; ;;
esac esac''');
''');
return sb.toString(); return sb.toString();
} }
} }
// enum AppShellFuncType { abstract class _CmdType {
// status, /// Find out the required segment from [segments]
// docker; String find(List<String> segments);
// } }
enum StatusCmdType implements _CmdType {
net,
sys,
cpu,
uptime,
conn,
disk,
mem,
tempType,
tempVal,
host,
sysRhel;
@override
String find(List<String> segments) {
return segments[index];
}
}
enum DockerCmdType implements _CmdType {
version,
ps,
stats,
images;
@override
String find(List<String> segments) {
return segments[index];
}
}

View File

@@ -1,4 +1,4 @@
import '../../res/server_cmd.dart'; import '../app/shell_func.dart';
import 'cpu.dart'; import 'cpu.dart';
import 'disk.dart'; import 'disk.dart';
import 'memory.dart'; import 'memory.dart';
@@ -13,50 +13,43 @@ class ServerStatusUpdateReq {
const ServerStatusUpdateReq(this.ss, this.segments); const ServerStatusUpdateReq(this.ss, this.segments);
} }
extension _SegmentsExt on List<String> {
String at(CmdType t) {
final index = t.index;
if (index >= length) return '';
return this[index];
}
}
Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async { Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
final net = parseNetSpeed(req.segments.at(CmdType.net)); final segments = req.segments;
final net = parseNetSpeed(StatusCmdType.net.find(segments));
req.ss.netSpeed.update(net); req.ss.netSpeed.update(net);
final sys = _parseSysVer( final sys = _parseSysVer(
req.segments.at(CmdType.sys), StatusCmdType.sys.find(segments),
req.segments.at(CmdType.host), StatusCmdType.host.find(segments),
req.segments.at(CmdType.sysRhel), StatusCmdType.sysRhel.find(segments),
); );
if (sys != null) { if (sys != null) {
req.ss.sysVer = sys; req.ss.sysVer = sys;
} }
final cpus = parseCPU(req.segments.at(CmdType.cpu)); final cpus = parseCPU(StatusCmdType.cpu.find(segments));
req.ss.cpu.update(cpus); req.ss.cpu.update(cpus);
req.ss.temps.parse( req.ss.temps.parse(
req.segments.at(CmdType.tempType), StatusCmdType.tempType.find(segments),
req.segments.at(CmdType.tempVal), StatusCmdType.tempVal.find(segments),
); );
final tcp = parseConn(req.segments.at(CmdType.conn)); final tcp = parseConn(StatusCmdType.conn.find(segments));
if (tcp != null) { if (tcp != null) {
req.ss.tcp = tcp; req.ss.tcp = tcp;
} }
req.ss.disk = parseDisk(req.segments.at(CmdType.disk)); req.ss.disk = parseDisk(StatusCmdType.disk.find(segments));
req.ss.mem = parseMem(req.segments.at(CmdType.mem)); req.ss.mem = parseMem(StatusCmdType.mem.find(segments));
final uptime = _parseUpTime(req.segments.at(CmdType.uptime)); final uptime = _parseUpTime(StatusCmdType.uptime.find(segments));
if (uptime != null) { if (uptime != null) {
req.ss.uptime = uptime; req.ss.uptime = uptime;
} }
req.ss.swap = parseSwap(req.segments.at(CmdType.mem)); req.ss.swap = parseSwap(StatusCmdType.mem.find(segments));
return req.ss; return req.ss;
} }

View File

@@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/extension/ssh_client.dart';
import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/extension/stringx.dart';
import 'package:toolbox/core/provider_base.dart'; import 'package:toolbox/core/provider_base.dart';
import 'package:toolbox/data/model/app/shell_func.dart';
import 'package:toolbox/data/model/docker/image.dart'; import 'package:toolbox/data/model/docker/image.dart';
import 'package:toolbox/data/model/docker/ps.dart'; import 'package:toolbox/data/model/docker/ps.dart';
import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/error.dart';
@@ -55,7 +56,7 @@ class DockerProvider extends BusyProvider {
var raw = ''; var raw = '';
await client!.exec( await client!.exec(
shellFuncDocker.exec, AppShellFuncType.docker.exec,
onStderr: _onPwd, onStderr: _onPwd,
onStdout: (data, _) => raw = '$raw$data', onStdout: (data, _) => raw = '$raw$data',
); );
@@ -75,7 +76,7 @@ class DockerProvider extends BusyProvider {
} }
// Parse docker version // Parse docker version
final verRaw = segments[0]; final verRaw = DockerCmdType.version.find(segments);
try { try {
version = _versionReg.firstMatch(verRaw)?.group(2); version = _versionReg.firstMatch(verRaw)?.group(2);
edition = _editionReg.firstMatch(verRaw)?.group(2); edition = _editionReg.firstMatch(verRaw)?.group(2);
@@ -88,7 +89,7 @@ class DockerProvider extends BusyProvider {
} }
// Parse docker ps // Parse docker ps
final psRaw = segments[1]; final psRaw = DockerCmdType.ps.find(segments);
try { try {
final lines = psRaw.split('\n'); final lines = psRaw.split('\n');
lines.removeWhere((element) => element.isEmpty); lines.removeWhere((element) => element.isEmpty);
@@ -105,7 +106,7 @@ class DockerProvider extends BusyProvider {
} }
// Parse docker images // Parse docker images
final imageRaw = segments[3]; final imageRaw = DockerCmdType.images.find(segments);
try { try {
final imageLines = imageRaw.split('\n'); final imageLines = imageRaw.split('\n');
imageLines.removeWhere((element) => element.isEmpty); imageLines.removeWhere((element) => element.isEmpty);
@@ -122,7 +123,7 @@ class DockerProvider extends BusyProvider {
} }
// Parse docker stats // Parse docker stats
final statsRaw = segments[2]; final statsRaw = DockerCmdType.stats.find(segments);
try { try {
final statsLines = statsRaw.split('\n'); final statsLines = statsRaw.split('\n');
statsLines.removeWhere((element) => element.isEmpty); statsLines.removeWhere((element) => element.isEmpty);

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:toolbox/data/model/app/shell_func.dart';
import '../../core/extension/order.dart'; import '../../core/extension/order.dart';
import '../../core/extension/uint8list.dart'; import '../../core/extension/uint8list.dart';
@@ -245,9 +246,9 @@ class ServerProvider extends BusyProvider {
if (s.client == null) return; if (s.client == null) return;
// run script to get server status // run script to get server status
raw = await s.client!.run(shellFuncStatus.exec).string; raw = await s.client!.run(AppShellFuncType.status.exec).string;
segments = raw.split(seperator).map((e) => e.trim()).toList(); segments = raw.split(seperator).map((e) => e.trim()).toList();
if (raw.isEmpty || segments.length != CmdType.values.length) { if (raw.isEmpty || segments.length != StatusCmdType.values.length) {
s.state = ServerState.failed; s.state = ServerState.failed;
if (s.status.failedInfo?.isEmpty ?? true) { if (s.status.failedInfo?.isEmpty ?? true) {
s.status.failedInfo = 'Seperate segments failed, raw:\n$raw'; s.status.failedInfo = 'Seperate segments failed, raw:\n$raw';

View File

@@ -7,21 +7,7 @@ const shellPath = '$serverBoxDir/mobile_app.sh';
const echoPWD = 'echo \$PWD'; const echoPWD = 'echo \$PWD';
enum CmdType { const statusCmds = [
net,
sys,
cpu,
uptime,
conn,
disk,
mem,
tempType,
tempVal,
host,
sysRhel,
}
const _cmdList = [
'cat /proc/net/dev && date +%s', 'cat /proc/net/dev && date +%s',
'cat /etc/os-release | grep PRETTY_NAME', 'cat /etc/os-release | grep PRETTY_NAME',
'cat /proc/stat | grep cpu', 'cat /proc/stat | grep cpu',
@@ -35,12 +21,6 @@ const _cmdList = [
'cat /etc/redhat-release', 'cat /etc/redhat-release',
]; ];
final shellFuncStatus = AppShellFunc(
'status',
_cmdList.join('\necho $seperator\n'),
's',
);
const dockerCmds = [ const dockerCmds = [
'docker version', 'docker version',
'docker ps -a', 'docker ps -a',
@@ -48,26 +28,13 @@ const dockerCmds = [
'docker image ls', 'docker image ls',
]; ];
final shellFuncDocker = AppShellFunc(
// `dockeR` -> avoid conflict with `docker` command
// 以防止循环递归
'dockeR',
dockerCmds.join('\necho $seperator\n'),
'd',
);
final _generated = [
shellFuncStatus,
shellFuncDocker,
].generate;
final shellCmd = """ final shellCmd = """
# Script for app `${BuildData.name} v1.0.${BuildData.build}` # Script for app `${BuildData.name} v1.0.${BuildData.build}`
# Delete this file while app is running will cause app crash # Delete this file while app is running will cause app crash
export LANG=en_US.utf-8 export LANG=en_US.utf-8
$_generated ${AppShellFuncType.shellScript}
"""; """;
final installShellCmd = "mkdir -p $serverBoxDir && " final installShellCmd = "mkdir -p $serverBoxDir && "

View File

@@ -456,6 +456,8 @@ class _DockerManagePageState extends State<DockerManagePage> {
subtitle: Text(_buildSubtitle(_docker.items!), style: grey), subtitle: Text(_buildSubtitle(_docker.items!), style: grey),
), ),
); );
// Bottom padding
items.add(height13);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: items, children: items,