mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix #168
This commit is contained in:
@@ -10,9 +10,9 @@ const _serverBoxDir = r'$HOME/.config/server_box';
|
|||||||
/// Issue #159
|
/// Issue #159
|
||||||
/// Use script commit count as version of shell script.
|
/// Use script commit count as version of shell script.
|
||||||
/// So different version of app can run at the same time.
|
/// So different version of app can run at the same time.
|
||||||
const _shellPath = '$_serverBoxDir/mobile_v${BuildData.script}.sh';
|
const installShellPath = '$_serverBoxDir/mobile_v${BuildData.script}.sh';
|
||||||
|
|
||||||
enum AppShellFuncType {
|
enum ShellFunc {
|
||||||
status,
|
status,
|
||||||
docker,
|
docker,
|
||||||
process,
|
process,
|
||||||
@@ -22,48 +22,48 @@ enum AppShellFuncType {
|
|||||||
|
|
||||||
String get flag {
|
String get flag {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AppShellFuncType.status:
|
case ShellFunc.status:
|
||||||
return 's';
|
return 's';
|
||||||
case AppShellFuncType.docker:
|
case ShellFunc.docker:
|
||||||
return 'd';
|
return 'd';
|
||||||
case AppShellFuncType.process:
|
case ShellFunc.process:
|
||||||
return 'p';
|
return 'p';
|
||||||
case AppShellFuncType.shutdown:
|
case ShellFunc.shutdown:
|
||||||
return 'sd';
|
return 'sd';
|
||||||
case AppShellFuncType.reboot:
|
case ShellFunc.reboot:
|
||||||
return 'r';
|
return 'r';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get exec => 'sh $_shellPath -$flag';
|
String get exec => 'sh $installShellPath -$flag';
|
||||||
|
|
||||||
String get name {
|
String get name {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AppShellFuncType.status:
|
case ShellFunc.status:
|
||||||
return 'status';
|
return 'status';
|
||||||
case AppShellFuncType.docker:
|
case ShellFunc.docker:
|
||||||
// `dockeR` -> avoid conflict with `docker` command
|
// `dockeR` -> avoid conflict with `docker` command
|
||||||
// 以防止循环递归
|
// 以防止循环递归
|
||||||
return 'dockeR';
|
return 'dockeR';
|
||||||
case AppShellFuncType.process:
|
case ShellFunc.process:
|
||||||
return 'process';
|
return 'process';
|
||||||
case AppShellFuncType.shutdown:
|
case ShellFunc.shutdown:
|
||||||
return 'ShutDown';
|
return 'ShutDown';
|
||||||
case AppShellFuncType.reboot:
|
case ShellFunc.reboot:
|
||||||
return 'Reboot';
|
return 'Reboot';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get cmd {
|
String get cmd {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AppShellFuncType.status:
|
case ShellFunc.status:
|
||||||
return '''
|
return '''
|
||||||
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
||||||
\t${_statusCmds.join(_cmdDivider)}
|
\t${_statusCmds.join(_cmdDivider)}
|
||||||
else
|
else
|
||||||
\t${_bsdStatusCmd.join(_cmdDivider)}
|
\t${_bsdStatusCmd.join(_cmdDivider)}
|
||||||
fi''';
|
fi''';
|
||||||
case AppShellFuncType.docker:
|
case ShellFunc.docker:
|
||||||
return '''
|
return '''
|
||||||
result=\$(docker version 2>&1 | grep "permission denied")
|
result=\$(docker version 2>&1 | grep "permission denied")
|
||||||
if [ "\$result" != "" ]; then
|
if [ "\$result" != "" ]; then
|
||||||
@@ -71,7 +71,7 @@ if [ "\$result" != "" ]; then
|
|||||||
else
|
else
|
||||||
\t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
\t${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
|
||||||
fi''';
|
fi''';
|
||||||
case AppShellFuncType.process:
|
case ShellFunc.process:
|
||||||
return '''
|
return '''
|
||||||
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
if [ "\$macSign" = "" ] && [ "\$bsdSign" = "" ]; then
|
||||||
\tif [ "\$isBusybox" != "" ]; then
|
\tif [ "\$isBusybox" != "" ]; then
|
||||||
@@ -83,14 +83,14 @@ else
|
|||||||
\tps -ax
|
\tps -ax
|
||||||
fi
|
fi
|
||||||
''';
|
''';
|
||||||
case AppShellFuncType.shutdown:
|
case ShellFunc.shutdown:
|
||||||
return '''
|
return '''
|
||||||
if [ "\$userId" = "0" ]; then
|
if [ "\$userId" = "0" ]; then
|
||||||
\tshutdown -h now
|
\tshutdown -h now
|
||||||
else
|
else
|
||||||
\tsudo -S shutdown -h now
|
\tsudo -S shutdown -h now
|
||||||
fi''';
|
fi''';
|
||||||
case AppShellFuncType.reboot:
|
case ShellFunc.reboot:
|
||||||
return '''
|
return '''
|
||||||
if [ "\$userId" = "0" ]; then
|
if [ "\$userId" = "0" ]; then
|
||||||
\treboot
|
\treboot
|
||||||
@@ -100,8 +100,25 @@ fi''';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String shellScript = () {
|
static final String allScript = () {
|
||||||
final sb = StringBuffer();
|
final sb = StringBuffer();
|
||||||
|
sb.write('''
|
||||||
|
#!/bin/sh
|
||||||
|
# Script for ServerBox app v1.0.${BuildData.build}
|
||||||
|
# DO NOT delete this file while app is running
|
||||||
|
|
||||||
|
export LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
# If macSign & bsdSign are both empty, then it's linux
|
||||||
|
macSign=\$(uname 2>&1 | grep "Darwin")
|
||||||
|
bsdSign=\$(uname 2>&1 | grep "BSD")
|
||||||
|
|
||||||
|
# Link /bin/sh to busybox?
|
||||||
|
isBusybox=\$(ls -l /bin/sh | grep "busybox")
|
||||||
|
|
||||||
|
userId=\$(id -u)
|
||||||
|
|
||||||
|
''');
|
||||||
// Write each func
|
// Write each func
|
||||||
for (final func in values) {
|
for (final func in values) {
|
||||||
sb.write('''
|
sb.write('''
|
||||||
@@ -212,31 +229,12 @@ const _bsdStatusCmd = [
|
|||||||
'hostname',
|
'hostname',
|
||||||
];
|
];
|
||||||
|
|
||||||
final _shellCmd = """
|
|
||||||
#!/bin/sh
|
|
||||||
# Script for ServerBox app v1.0.${BuildData.build}
|
|
||||||
# DO NOT delete this file while app is running
|
|
||||||
|
|
||||||
export LANG=en_US.UTF-8
|
|
||||||
|
|
||||||
# If macSign & bsdSign are both empty, then it's linux
|
|
||||||
macSign=\$(uname 2>&1 | grep "Darwin")
|
|
||||||
bsdSign=\$(uname 2>&1 | grep "BSD")
|
|
||||||
|
|
||||||
# Link /bin/sh to busybox?
|
|
||||||
isBusybox=\$(ls -l /bin/sh | grep "busybox")
|
|
||||||
|
|
||||||
userId=\$(id -u)
|
|
||||||
|
|
||||||
${AppShellFuncType.shellScript}
|
|
||||||
""";
|
|
||||||
|
|
||||||
/// Issue #168
|
/// Issue #168
|
||||||
/// Use `sh` for compatibility
|
/// Use `sh` for compatibility
|
||||||
final installShellCmd = """
|
final installShellCmd = """
|
||||||
mkdir -p $_serverBoxDir
|
mkdir -p $_serverBoxDir
|
||||||
sh -c cat << 'EOF' > $_shellPath
|
cat << 'EOF' > $installShellPath
|
||||||
$_shellCmd
|
${ShellFunc.allScript}
|
||||||
EOF
|
EOF
|
||||||
chmod +x $_shellPath
|
chmod +x $installShellPath
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class ServerPrivateInfo {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Server? get findServer => Providers.server.servers[id];
|
Server? get server => Providers.server.pick(spi: this);
|
||||||
|
|
||||||
bool shouldReconnect(ServerPrivateInfo old) {
|
bool shouldReconnect(ServerPrivateInfo old) {
|
||||||
return id != old.id ||
|
return id != old.id ||
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:toolbox/core/utils/platform/path.dart';
|
||||||
import 'package:toolbox/data/model/app/shell_func.dart';
|
import 'package:toolbox/data/model/app/shell_func.dart';
|
||||||
import 'package:toolbox/data/model/server/system.dart';
|
import 'package:toolbox/data/model/server/system.dart';
|
||||||
|
import 'package:toolbox/data/model/sftp/req.dart';
|
||||||
import 'package:toolbox/data/res/logger.dart';
|
import 'package:toolbox/data/res/logger.dart';
|
||||||
|
import 'package:toolbox/data/res/path.dart';
|
||||||
|
import 'package:toolbox/data/res/provider.dart';
|
||||||
import 'package:toolbox/data/res/store.dart';
|
import 'package:toolbox/data/res/store.dart';
|
||||||
|
|
||||||
import '../../core/extension/order.dart';
|
import '../../core/extension/order.dart';
|
||||||
@@ -20,7 +25,7 @@ typedef ServersMap = Map<String, Server>;
|
|||||||
|
|
||||||
class ServerProvider extends ChangeNotifier {
|
class ServerProvider extends ChangeNotifier {
|
||||||
final ServersMap _servers = {};
|
final ServersMap _servers = {};
|
||||||
ServersMap get servers => _servers;
|
Iterable<Server> get servers => _servers.values;
|
||||||
final Order<String> _serverOrder = [];
|
final Order<String> _serverOrder = [];
|
||||||
Order<String> get serverOrder => _serverOrder;
|
Order<String> get serverOrder => _serverOrder;
|
||||||
final List<String> _tags = [];
|
final List<String> _tags = [];
|
||||||
@@ -58,6 +63,19 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a [Server] by [spi] or [id].
|
||||||
|
///
|
||||||
|
/// Priority: [spi] > [id]
|
||||||
|
Server? pick({ServerPrivateInfo? spi, String? id}) {
|
||||||
|
if (spi != null) {
|
||||||
|
return _servers[spi.id];
|
||||||
|
}
|
||||||
|
if (id != null) {
|
||||||
|
return _servers[id];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void _updateTags() {
|
void _updateTags() {
|
||||||
_tags.clear();
|
_tags.clear();
|
||||||
for (final s in _servers.values) {
|
for (final s in _servers.values) {
|
||||||
@@ -264,12 +282,27 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
final writeResult = await s.client?.run(installShellCmd).string;
|
final writeResult = await s.client?.run(installShellCmd).string;
|
||||||
if (writeResult == null || writeResult.isNotEmpty) {
|
if (writeResult == null || writeResult.isNotEmpty) {
|
||||||
_limiter.inc(sid);
|
throw Exception('$writeResult');
|
||||||
s.status.failedInfo = writeResult;
|
|
||||||
_setServerState(s, ServerState.failed);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
var sftpFailed = false;
|
||||||
|
try {
|
||||||
|
Loggers.app.warning('Using SFTP to write script to ${spi.name}');
|
||||||
|
final localPath = joinPath(await Paths.doc, 'install.sh');
|
||||||
|
final file = File(localPath);
|
||||||
|
file.writeAsString(ShellFunc.allScript);
|
||||||
|
final sftp = Providers.sftp;
|
||||||
|
final completer = Completer();
|
||||||
|
sftp.add(
|
||||||
|
SftpReq(spi, installShellPath, localPath, SftpReqType.upload),
|
||||||
|
completer: completer,
|
||||||
|
);
|
||||||
|
await completer.future;
|
||||||
|
await file.delete();
|
||||||
|
} catch (_) {
|
||||||
|
sftpFailed = true;
|
||||||
|
}
|
||||||
|
if (sftpFailed) {
|
||||||
_limiter.inc(sid);
|
_limiter.inc(sid);
|
||||||
s.status.failedInfo = e.toString();
|
s.status.failedInfo = e.toString();
|
||||||
_setServerState(s, ServerState.failed);
|
_setServerState(s, ServerState.failed);
|
||||||
@@ -277,14 +310,15 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s.client == null) return;
|
/// Keep [finished] state, or the UI will be refreshed to [loading] state
|
||||||
|
/// instead of the 'Temp & Uptime'.
|
||||||
if (s.state != ServerState.finished) {
|
if (s.state != ServerState.finished) {
|
||||||
_setServerState(s, ServerState.loading);
|
_setServerState(s, ServerState.loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
final raw = await s.client?.run(AppShellFuncType.status.exec).string;
|
final raw = await s.client?.run(ShellFunc.status.exec).string;
|
||||||
final segments = raw?.split(seperator).map((e) => e.trim()).toList();
|
final segments = raw?.split(seperator).map((e) => e.trim()).toList();
|
||||||
if (raw == null || raw.isEmpty || segments == null || segments.isEmpty) {
|
if (raw == null || raw.isEmpty || segments == null || segments.isEmpty) {
|
||||||
_limiter.inc(sid);
|
_limiter.inc(sid);
|
||||||
|
|||||||
Reference in New Issue
Block a user