- docker ps item parse
- parse issue in fish (shell)
- make.dart path
This commit is contained in:
Junyuan Feng
2022-04-29 11:59:27 +08:00
parent 9663e4174d
commit 9b7d33369a
6 changed files with 87 additions and 55 deletions

View File

@@ -11,8 +11,7 @@ class DockerPsItem {
this.status, this.ports, this.name); this.status, this.ports, this.name);
DockerPsItem.fromRawString(String rawString) { DockerPsItem.fromRawString(String rawString) {
List<String> parts = rawString.split(' '); List<String> parts = rawString.split(RegExp(' +'));
parts.removeWhere((element) => element.isEmpty);
parts = parts.map((e) => e.trim()).toList(); parts = parts.map((e) => e.trim()).toList();
containerId = parts[0]; containerId = parts[0];
@@ -20,7 +19,7 @@ class DockerPsItem {
command = parts[2].trim(); command = parts[2].trim();
created = parts[3]; created = parts[3];
status = parts[4]; status = parts[4];
if (running) { if (running && parts.length > 6) {
ports = parts[5]; ports = parts[5];
name = parts[6]; name = parts[6];
} else { } else {
@@ -30,4 +29,9 @@ class DockerPsItem {
} }
bool get running => status.contains('Up '); bool get running => status.contains('Up ');
@override
String toString() {
return 'DockerPsItem<$containerId@$name>';
}
} }

View File

@@ -3,9 +3,11 @@ import 'package:toolbox/core/extension/uint8list.dart';
import 'package:toolbox/core/provider_base.dart'; import 'package:toolbox/core/provider_base.dart';
import 'package:toolbox/data/model/docker/ps.dart'; import 'package:toolbox/data/model/docker/ps.dart';
final dockerNotFound = RegExp('(command not found | Unknown command)');
class DockerProvider extends BusyProvider { class DockerProvider extends BusyProvider {
SSHClient? client; SSHClient? client;
List<DockerPsItem>? running; List<DockerPsItem>? items;
String? version; String? version;
String? edition; String? edition;
String? error; String? error;
@@ -15,7 +17,7 @@ class DockerProvider extends BusyProvider {
void clear() { void clear() {
client = null; client = null;
error = null; error = null;
running = null; items = null;
version = null; version = null;
edition = null; edition = null;
} }
@@ -28,6 +30,11 @@ class DockerProvider extends BusyProvider {
} }
final verRaw = await client!.run('docker version').string; final verRaw = await client!.run('docker version').string;
if (verRaw.contains(dockerNotFound)) {
error = 'docker not found';
notifyListeners();
return;
}
final verSplit = verRaw.split('\n'); final verSplit = verRaw.split('\n');
if (verSplit.length < 3) { if (verSplit.length < 3) {
error = 'invalid version'; error = 'invalid version';
@@ -42,19 +49,15 @@ class DockerProvider extends BusyProvider {
} }
final raw = await client!.run('docker ps -a').string; final raw = await client!.run('docker ps -a').string;
if (raw.contains('command not found')) {
error = 'docker not found';
notifyListeners();
return;
}
try {
final lines = raw.split('\n'); final lines = raw.split('\n');
lines.removeAt(0); lines.removeAt(0);
lines.removeWhere((element) => element.isEmpty); lines.removeWhere((element) => element.isEmpty);
running = lines.map((e) => DockerPsItem.fromRawString(e)).toList();
try {
items = lines.map((e) => DockerPsItem.fromRawString(e)).toList();
} catch (e) { } catch (e) {
error = e.toString(); error = e.toString();
rethrow;
} finally { } finally {
notifyListeners(); notifyListeners();
} }

View File

@@ -29,6 +29,18 @@ List<SSHKeyPair> loadIndentity(String key) {
return SSHKeyPair.fromPem(key); return SSHKeyPair.fromPem(key);
} }
const shellCmd = "cat /proc/net/dev && date +%s \necho A====A \n "
"cat /etc/os-release | grep PRETTY_NAME \necho A====A \n"
"cat /proc/stat | grep cpu \necho A====A \n"
"uptime \necho A====A \n"
"cat /proc/net/snmp \necho A====A \n"
"df -h \necho A====A \n"
"free -m \necho A====A \n"
"cat /sys/class/thermal/thermal_zone*/type \necho A====A \n"
"cat /sys/class/thermal/thermal_zone*/temp";
const shellPath = '.serverbox.sh';
final cpuTempReg = RegExp('(x86_pkg_temp|cpu_thermal)');
class ServerProvider extends BusyProvider { class ServerProvider extends BusyProvider {
List<ServerInfo> _servers = []; List<ServerInfo> _servers = [];
List<ServerInfo> get servers => _servers; List<ServerInfo> get servers => _servers;
@@ -90,15 +102,9 @@ class ServerProvider extends BusyProvider {
_getData(spi); _getData(spi);
return; return;
} }
try {
await Future.wait(_servers.map((s) async { await Future.wait(_servers.map((s) async {
await _getData(s.info); await _getData(s.info);
})); }));
} catch (e) {
if (e is! RangeError) {
rethrow;
}
}
} }
Future<void> startAutoRefresh() async { Future<void> startAutoRefresh() async {
@@ -167,33 +173,37 @@ class ServerProvider extends BusyProvider {
logger.info( logger.info(
'Connected to [${spi.name}] in [${time2.difference(time1).toString()}].'); 'Connected to [${spi.name}] in [${time2.difference(time1).toString()}].');
_servers[idx].connectionState = ServerConnectionState.connected; _servers[idx].connectionState = ServerConnectionState.connected;
notifyListeners(); _servers[idx]
.client!
.run("echo '$shellCmd' > $shellPath && chmod +x $shellPath");
} catch (e) { } catch (e) {
_servers[idx].connectionState = ServerConnectionState.failed; _servers[idx].connectionState = ServerConnectionState.failed;
_servers[idx].status.failedInfo = e.toString() + ' ## '; _servers[idx].status.failedInfo = e.toString() + ' ## ';
notifyListeners();
logger.warning(e); logger.warning(e);
} finally {
notifyListeners();
} }
} }
// if client is null, return
final si = _servers[idx]; final si = _servers[idx];
try {
if (si.client == null) return; if (si.client == null) return;
final raw = await si.client! final raw = await si.client!.run("sh $shellPath").string;
.run(
r"cat /proc/net/dev && date +%s && echo 'A====A' && cat /etc/os-release | grep PRETTY_NAME && echo 'A====A' && cat /proc/stat | grep cpu && echo 'A====A' && paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | column -s $'\t' -t | sed 's/\(.\)..$/.\1°C/' && echo 'A====A' && uptime && echo 'A====A' && cat /proc/net/snmp && echo 'A====A' && df -h && echo 'A====A' && free -m")
.string;
final lines = raw.split('A====A').map((e) => e.trim()).toList(); final lines = raw.split('A====A').map((e) => e.trim()).toList();
_getCPU(spi, lines[2], lines[3]);
_getMem(spi, lines[7]); try {
_getCPU(spi, lines[2], lines[7], lines[8]);
_getMem(spi, lines[6]);
_getSysVer(spi, lines[1]); _getSysVer(spi, lines[1]);
_getUpTime(spi, lines[4]); _getUpTime(spi, lines[3]);
_getDisk(spi, lines[6]); _getDisk(spi, lines[5]);
_getTcp(spi, lines[5]); _getTcp(spi, lines[4]);
_getNetSpeed(spi, lines[0]); _getNetSpeed(spi, lines[0]);
} catch (e) { } catch (e) {
_servers[idx].connectionState = ServerConnectionState.failed; _servers[idx].connectionState = ServerConnectionState.failed;
servers[idx].status.failedInfo = e.toString(); servers[idx].status.failedInfo = e.toString();
logger.warning(e); logger.warning(e);
rethrow;
} finally { } finally {
notifyListeners(); notifyListeners();
} }
@@ -232,17 +242,30 @@ class ServerProvider extends BusyProvider {
} }
} }
String _getCPUTemp(String raw) { String _getCPUTemp(String type, String value) {
final split = raw.split('\n'); const noMatch = 'No such file or directory';
for (var item in split) { // Not support to get CPU temperature
if (item.contains('x86_pkg_temp') || item.contains('cpu_thermal')) { if (value.contains(noMatch) ||
return item.split(' ').last; type.contains(noMatch) ||
} value.isEmpty ||
} type.isEmpty) {
return ''; return '';
} }
final split = type.split('\n');
int idx = 0;
for (var item in split) {
if (item.contains(cpuTempReg)) {
break;
}
idx++;
}
return (int.parse(value.split('\n')[idx].trim()) / 1000)
.toStringAsFixed(1) +
'°C';
}
void _getCPU(ServerPrivateInfo spi, String raw, String temp) { void _getCPU(
ServerPrivateInfo spi, String raw, String tempType, String tempValue) {
final info = _servers.firstWhere((e) => e.info == spi); final info = _servers.firstWhere((e) => e.info == spi);
final List<CpuStatus> cpus = []; final List<CpuStatus> cpus = [];
@@ -262,7 +285,7 @@ class ServerProvider extends BusyProvider {
} }
if (cpus.isNotEmpty) { if (cpus.isNotEmpty) {
info.status.cpu2Status = info.status.cpu2Status =
info.status.cpu2Status.update(cpus, _getCPUTemp(temp)); info.status.cpu2Status.update(cpus, _getCPUTemp(tempType, tempValue));
} }
} }

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 113; static const int build = 114;
static const String engine = static const String engine =
"Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision c860cba910 (3 weeks ago) • 2022-03-25 00:23:12 -0500\nEngine • revision 57d3bac3dd\nTools • Dart 2.16.2 • DevTools 2.9.2\n"; "Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision c860cba910 (3 weeks ago) • 2022-03-25 00:23:12 -0500\nEngine • revision 57d3bac3dd\nTools • Dart 2.16.2 • DevTools 2.9.2\n";
static const String buildAt = "2022-04-15 19:46:15.224203"; static const String buildAt = "2022-04-15 20:20:29.860208";
static const int modifications = 2; static const int modifications = 1;
} }

View File

@@ -66,7 +66,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
Widget _buildMain() { Widget _buildMain() {
return Consumer<DockerProvider>(builder: (_, docker, __) { return Consumer<DockerProvider>(builder: (_, docker, __) {
final running = docker.running; final running = docker.items;
if (docker.error != null && running == null) { if (docker.error != null && running == null) {
return Center( return Center(
child: Column( child: Column(

View File

@@ -5,6 +5,9 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
const appName = 'ServerBox'; const appName = 'ServerBox';
const buildDataFilePath = 'lib/data/res/build_data.dart';
const xcarchivePath = 'build/ios/archive/Runner.xcarchive';
const skslFileSuffix = '.sksl.json'; const skslFileSuffix = '.sksl.json';
Future<int> getGitCommitCount() async { Future<int> getGitCommitCount() async {
@@ -64,8 +67,7 @@ Future<void> updateBuildData() async {
print('Updating BuildData...'); print('Updating BuildData...');
final data = await getBuildData(); final data = await getBuildData();
print(jsonEncodeWithIndent(data)); print(jsonEncodeWithIndent(data));
const path = 'lib/data/res/build_data.dart'; await writeStaicConfigFile(data, 'BuildData', buildDataFilePath);
await writeStaicConfigFile(data, 'BuildData', path);
} }
void dartFormat() { void dartFormat() {
@@ -120,8 +122,8 @@ Future<void> flutterBuild(String source, String target, bool isAndroid) async {
} }
Future<void> flutterBuildIOS() async { Future<void> flutterBuildIOS() async {
await flutterBuild('./build/ios/archive/Runner.xcarchive', await flutterBuild(
'./release/${appName}_build.xcarchive', false); xcarchivePath, './release/${appName}_build.xcarchive', false);
} }
Future<void> flutterBuildAndroid() async { Future<void> flutterBuildAndroid() async {
@@ -149,10 +151,10 @@ void main(List<String> args) async {
final platform = args[1]; final platform = args[1];
switch (platform) { switch (platform) {
case 'ios': case 'ios':
buildFunc.remove(flutterBuildIOS); buildFunc.remove(flutterBuildAndroid);
break; break;
case 'android': case 'android':
buildFunc.remove(flutterBuildAndroid); buildFunc.remove(flutterBuildIOS);
break; break;
default: default:
print('Unknown platform: $platform'); print('Unknown platform: $platform');