mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix
- docker ps item parse - parse issue in fish (shell) - make.dart path
This commit is contained in:
@@ -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>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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')) {
|
final lines = raw.split('\n');
|
||||||
error = 'docker not found';
|
lines.removeAt(0);
|
||||||
notifyListeners();
|
lines.removeWhere((element) => element.isEmpty);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final lines = raw.split('\n');
|
items = lines.map((e) => DockerPsItem.fromRawString(e)).toList();
|
||||||
lines.removeAt(0);
|
|
||||||
lines.removeWhere((element) => element.isEmpty);
|
|
||||||
running = lines.map((e) => DockerPsItem.fromRawString(e)).toList();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e.toString();
|
error = e.toString();
|
||||||
|
rethrow;
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
|
if (si.client == null) return;
|
||||||
|
final raw = await si.client!.run("sh $shellPath").string;
|
||||||
|
final lines = raw.split('A====A').map((e) => e.trim()).toList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (si.client == null) return;
|
_getCPU(spi, lines[2], lines[7], lines[8]);
|
||||||
final raw = await si.client!
|
_getMem(spi, lines[6]);
|
||||||
.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();
|
|
||||||
_getCPU(spi, lines[2], lines[3]);
|
|
||||||
_getMem(spi, lines[7]);
|
|
||||||
_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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
14
make.dart
14
make.dart
@@ -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');
|
||||||
|
|||||||
Reference in New Issue
Block a user