#43 new: bsd base support

This commit is contained in:
lollipopkit
2023-08-22 21:07:17 +08:00
parent e3f2b211a9
commit 417cb4c89d
23 changed files with 499 additions and 234 deletions

View File

@@ -35,11 +35,19 @@ enum DockerMenuType {
rm,
logs,
terminal,
stats;
//stats,
;
static List<DockerMenuType> items(bool running) {
if (running) {
return [stop, restart, rm, logs, terminal, stats];
return [
stop,
restart,
rm,
logs,
terminal,
//stats,
];
} else {
return [start, rm, logs];
}
@@ -59,8 +67,8 @@ enum DockerMenuType {
return Icons.logo_dev;
case DockerMenuType.terminal:
return Icons.terminal;
case DockerMenuType.stats:
return Icons.bar_chart;
// case DockerMenuType.stats:
// return Icons.bar_chart;
}
}
@@ -78,8 +86,8 @@ enum DockerMenuType {
return s.log;
case DockerMenuType.terminal:
return s.terminal;
case DockerMenuType.stats:
return s.stats;
// case DockerMenuType.stats:
// return s.stats;
}
}

View File

@@ -1,7 +1,12 @@
import '../../res/build_data.dart';
import '../../res/server_cmd.dart';
import '../server/system.dart';
const _cmdDivider = '\necho $seperator\n';
const _serverBoxDir = r'$HOME/.config/server_box';
const _shellPath = '$_serverBoxDir/mobile_app.sh';
enum AppShellFuncType {
status,
docker;
@@ -15,7 +20,7 @@ enum AppShellFuncType {
}
}
String get exec => 'sh $shellPath -$flag';
String get exec => 'sh $_shellPath -$flag';
String get name {
switch (this) {
@@ -31,16 +36,20 @@ enum AppShellFuncType {
String get cmd {
switch (this) {
case AppShellFuncType.status:
return statusCmds.join(_cmdDivider);
return '''
result=\$(uname 2>&1 | grep "Linux")
if [ "\$result" != "" ]; then
${_statusCmds.join(_cmdDivider)}
else
${_bsdStatusCmd.join(_cmdDivider)}
fi''';
case AppShellFuncType.docker:
return '''
result=\$(docker version 2>&1)
deniedStr="permission denied"
containStr=\$(echo \$result | grep "\${deniedStr}")
if [[ \$containStr != "" ]]; then
${dockerCmds.join(_cmdDivider)}
result=\$(docker version 2>&1 | grep "permission denied")
if [ "\$result" != "" ]; then
${_dockerCmds.join(_cmdDivider)}
else
${dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
fi''';
}
}
@@ -83,6 +92,7 @@ extension EnumX on Enum {
}
enum StatusCmdType {
echo,
time,
net,
sys,
@@ -94,12 +104,81 @@ enum StatusCmdType {
tempType,
tempVal,
host,
sysRhel;
;
}
/// Cmds for linux server
const _statusCmds = [
'echo $linuxSign',
'date +%s',
'cat /proc/net/dev',
'cat /etc/*-release | grep PRETTY_NAME',
'cat /proc/stat | grep cpu',
'uptime',
'cat /proc/net/snmp',
'df -h',
'cat /proc/meminfo',
'cat /sys/class/thermal/thermal_zone*/type',
'cat /sys/class/thermal/thermal_zone*/temp',
'hostname',
];
enum DockerCmdType {
version,
ps,
stats,
images;
//stats,
images,
;
}
const _dockerCmds = [
'docker version',
'docker ps -a',
//'docker stats --no-stream',
'docker image ls',
];
enum BSDStatusCmdType {
echo,
time,
net,
sys,
cpu,
uptime,
disk,
mem,
//temp,
host,
;
}
/// Cmds for BSD server
const _bsdStatusCmd = [
'echo $bsdSign',
'date +%s',
'netstat -ibn',
'uname -or',
'top -l 1 | grep "CPU usage"',
'uptime',
'df -h',
'top -l 1 | grep PhysMem',
//'sysctl -a | grep temperature',
'hostname',
];
final _shellCmd = """
#!/bin/sh
#
# Script for ServerBox app v1.0.${BuildData.build}
#
# DO NOT delete this file while app is running
# DO NOT run multi ServerBox apps with different version at the same time
export LANG=en_US.UTF-8
${AppShellFuncType.shellScript}
""";
final installShellCmd = "mkdir -p $_serverBoxDir && "
"echo '$_shellCmd' > $_shellPath && "
"chmod +x $_shellPath";

View File

@@ -8,10 +8,10 @@ class DockerPsItem {
late String status;
late String ports;
late String name;
String? cpu;
String? mem;
String? net;
String? disk;
// String? cpu;
// String? mem;
// String? net;
// String? disk;
DockerPsItem(
this.containerId,
@@ -41,19 +41,19 @@ class DockerPsItem {
}
}
void parseStats(String rawString) {
if (rawString.isEmpty) {
return;
}
final parts = rawString.split(_seperator);
if (parts.length != 8) {
return;
}
cpu = parts[2];
mem = parts[3];
net = parts[5];
disk = parts[6];
}
// void parseStats(String rawString) {
// if (rawString.isEmpty) {
// return;
// }
// final parts = rawString.split(_seperator);
// if (parts.length != 8) {
// return;
// }
// cpu = parts[2];
// mem = parts[3];
// net = parts[5];
// disk = parts[6];
// }
bool get running => status.contains('Up ');

View File

@@ -1,3 +1,5 @@
import 'package:toolbox/data/res/status.dart';
import 'time_seq.dart';
class Cpus extends TimeSeq<OneTimeCpuStatus> {
@@ -95,3 +97,22 @@ List<OneTimeCpuStatus> parseCPU(String raw) {
}
return cpus;
}
final _bsdCpuPercentReg = RegExp(r'(\d+\.\d+)%');
/// TODO: Change this implementation to parse cpu status on BSD system
///
/// [raw]:
/// CPU usage: 14.70% user, 12.76% sys, 72.52% idle
Cpus parseBsdCpu(String raw) {
final percents = _bsdCpuPercentReg
.allMatches(raw)
.map((e) => double.parse(e.group(1) ?? '0') * 100)
.toList();
if (percents.length != 3) return initCpuStatus;
return initCpuStatus
..now = [
OneTimeCpuStatus('cpu', percents[0].toInt(), percents[1].toInt(), 0,
percents[2].toInt(), 0, 0, 0)
];
}

View File

@@ -115,3 +115,51 @@ List<NetSpeedPart> parseNetSpeed(String raw, int time) {
}
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

@@ -1,3 +1,4 @@
import 'package:toolbox/data/model/server/system.dart';
import 'package:toolbox/data/model/server/temp.dart';
import 'cpu.dart';
@@ -16,6 +17,7 @@ class ServerStatus {
Conn tcp;
NetSpeed netSpeed;
Temperatures temps;
SystemType system;
String? failedInfo;
ServerStatus({
@@ -28,6 +30,7 @@ class ServerStatus {
required this.netSpeed,
required this.swap,
required this.temps,
required this.system,
this.failedInfo,
});
}

View File

@@ -1,3 +1,5 @@
import 'package:toolbox/data/model/server/system.dart';
import '../app/shell_func.dart';
import 'cpu.dart';
import 'disk.dart';
@@ -9,11 +11,25 @@ import 'conn.dart';
class ServerStatusUpdateReq {
final ServerStatus ss;
final List<String> segments;
final SystemType system;
const ServerStatusUpdateReq(this.ss, this.segments);
const ServerStatusUpdateReq({
required this.system,
required this.ss,
required this.segments,
});
}
Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
switch (req.system) {
case SystemType.linux:
return _getLinuxStatus(req);
case SystemType.bsd:
return _getBsdStatus(req);
}
}
Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
final segments = req.segments;
final time = int.parse(StatusCmdType.time.find(segments));
@@ -24,7 +40,6 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
final sys = _parseSysVer(
StatusCmdType.sys.find(segments),
StatusCmdType.host.find(segments),
StatusCmdType.sysRhel.find(segments),
);
if (sys != null) {
req.ss.sysVer = sys;
@@ -56,6 +71,30 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
return req.ss;
}
Future<ServerStatus> _getBsdStatus(ServerStatusUpdateReq req) async {
final segments = req.segments;
final time = int.parse(BSDStatusCmdType.time.find(segments));
final net = parseBsdNetSpeed(BSDStatusCmdType.net.find(segments), time);
req.ss.netSpeed.update(net);
req.ss.sysVer = BSDStatusCmdType.sys.find(segments);
req.ss.cpu = parseBsdCpu(BSDStatusCmdType.cpu.find(segments));
//req.ss.mem = parseBsdMem(BSDStatusCmdType.mem.find(segments));
final uptime = _parseUpTime(BSDStatusCmdType.uptime.find(segments));
if (uptime != null) {
req.ss.uptime = uptime;
}
req.ss.disk = parseDisk(BSDStatusCmdType.disk.find(segments));
return req.ss;
}
// raw:
// 19:39:15 up 61 days, 18:16, 1 user, load average: 0.00, 0.00, 0.00
String? _parseUpTime(String raw) {
@@ -69,17 +108,14 @@ String? _parseUpTime(String raw) {
return null;
}
String? _parseSysVer(String raw, String hostname, String rawRhel) {
String? _parseSysVer(String raw, String hostname) {
try {
final s = raw.split('=');
if (s.length == 2) {
return s[1].replaceAll('"', '').replaceFirst('\n', '');
}
} catch (e) {
if (!rawRhel.contains('cat: /etc/redhat-release:')) {
return rawRhel;
}
if (hostname.isNotEmpty) return hostname;
} finally {
// ignore: control_flow_in_finally
return hostname.isEmpty ? null : hostname;
}
return null;
}

View File

@@ -0,0 +1,34 @@
import 'package:toolbox/data/model/app/shell_func.dart';
enum SystemType {
linux._(linuxSign),
bsd._(bsdSign),
;
final String value;
const SystemType._(this.value);
static SystemType? parse(String? value) {
if (value == null) return null;
switch (value) {
case linuxSign:
return SystemType.linux;
case bsdSign:
return SystemType.bsd;
}
return null;
}
bool isSegmentsLenMatch(int len) {
switch (this) {
case SystemType.linux:
return len == StatusCmdType.values.length;
case SystemType.bsd:
return len == BSDStatusCmdType.values.length;
}
}
}
const linuxSign = 'linux';
const bsdSign = 'bsd';

View File

@@ -1,5 +1,3 @@
// ignore_for_file: prefer_final_fields
abstract class TimeSeq<T extends TimeSeqIface> {
List<T> pre;
List<T> now;