mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix (#195) & opt.
- fix: debug provider color - fix: can't write script through SFTP (#195) - opt.: go next refresh only after current refresh task is done
This commit is contained in:
@@ -49,6 +49,7 @@ Future<SSHClient> genClient(
|
|||||||
|
|
||||||
/// [ServerPrivateInfo] of the jump server
|
/// [ServerPrivateInfo] of the jump server
|
||||||
ServerPrivateInfo? jumpSpi,
|
ServerPrivateInfo? jumpSpi,
|
||||||
|
String? jumpPrivateKey,
|
||||||
}) async {
|
}) async {
|
||||||
onStatus?.call(GenSSHClientStatus.socket);
|
onStatus?.call(GenSSHClientStatus.socket);
|
||||||
SSHSocket? socket;
|
SSHSocket? socket;
|
||||||
@@ -76,14 +77,13 @@ Future<SSHClient> genClient(
|
|||||||
if (jumpSpi != null) {
|
if (jumpSpi != null) {
|
||||||
final jumpClient = await genClient(
|
final jumpClient = await genClient(
|
||||||
jumpSpi,
|
jumpSpi,
|
||||||
privateKey: privateKey,
|
privateKey: jumpPrivateKey,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
);
|
);
|
||||||
// Use `0.0.0.0` as localhost to use all interfaces.
|
// Use `0.0.0.0` as localhost to use all interfaces.
|
||||||
return await jumpClient.forwardLocal(
|
return await jumpClient.forwardLocal(
|
||||||
spi.ip,
|
spi.ip,
|
||||||
spi.port,
|
spi.port,
|
||||||
localHost: '0.0.0.0',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|||||||
@@ -5,13 +5,7 @@ const seperator = 'SrvBoxSep';
|
|||||||
|
|
||||||
/// The suffix `\t` is for formatting
|
/// The suffix `\t` is for formatting
|
||||||
const _cmdDivider = '\necho $seperator\n\t';
|
const _cmdDivider = '\necho $seperator\n\t';
|
||||||
|
const _homeVar = '\$HOME';
|
||||||
const _serverBoxDir = r'$HOME/.config/server_box';
|
|
||||||
|
|
||||||
/// Issue #159
|
|
||||||
/// Use script commit count as version of shell script.
|
|
||||||
/// So different version of app can run at the same time.
|
|
||||||
const installShellPath = '$_serverBoxDir/mobile_v${BuildData.script}.sh';
|
|
||||||
|
|
||||||
enum ShellFunc {
|
enum ShellFunc {
|
||||||
status,
|
status,
|
||||||
@@ -22,6 +16,31 @@ enum ShellFunc {
|
|||||||
suspend,
|
suspend,
|
||||||
;
|
;
|
||||||
|
|
||||||
|
static const _serverBoxDir = '.config/server_box';
|
||||||
|
static const _scriptFileName = 'mobile_v${BuildData.script}.sh';
|
||||||
|
|
||||||
|
/// Issue #159
|
||||||
|
///
|
||||||
|
/// Use script commit count as version of shell script.
|
||||||
|
///
|
||||||
|
/// So different version of app can run at the same time.
|
||||||
|
///
|
||||||
|
/// **Can't** use it in SFTP, because SFTP can't recognize `$HOME`
|
||||||
|
static String getShellPath(String home) =>
|
||||||
|
'$home/$_serverBoxDir/$_scriptFileName';
|
||||||
|
|
||||||
|
static final _installShellPath = getShellPath(_homeVar);
|
||||||
|
|
||||||
|
/// Issue #168
|
||||||
|
/// Use `sh` for compatibility
|
||||||
|
static final installShellCmd = """
|
||||||
|
mkdir -p $_homeVar/$_serverBoxDir
|
||||||
|
cat << 'EOF' > $_installShellPath
|
||||||
|
${ShellFunc.allScript}
|
||||||
|
EOF
|
||||||
|
chmod +x $_installShellPath
|
||||||
|
""";
|
||||||
|
|
||||||
String get flag {
|
String get flag {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case ShellFunc.status:
|
case ShellFunc.status:
|
||||||
@@ -39,7 +58,7 @@ enum ShellFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get exec => 'sh $installShellPath -$flag';
|
String get exec => 'sh $_installShellPath -$flag';
|
||||||
|
|
||||||
String get name {
|
String get name {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
@@ -241,13 +260,3 @@ const _bsdStatusCmd = [
|
|||||||
//'sysctl -a | grep temperature',
|
//'sysctl -a | grep temperature',
|
||||||
'hostname',
|
'hostname',
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Issue #168
|
|
||||||
/// Use `sh` for compatibility
|
|
||||||
final installShellCmd = """
|
|
||||||
mkdir -p $_serverBoxDir
|
|
||||||
cat << 'EOF' > $installShellPath
|
|
||||||
${ShellFunc.allScript}
|
|
||||||
EOF
|
|
||||||
chmod +x $installShellPath
|
|
||||||
""";
|
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ class Server implements TagPickable {
|
|||||||
SSHClient? client;
|
SSHClient? client;
|
||||||
ServerState state;
|
ServerState state;
|
||||||
|
|
||||||
/// Whether is generating client.
|
/// Whether is connectting, parsing and etc.
|
||||||
/// Use this to avoid reconnecting if last connect try not finished.
|
bool isBusy = false;
|
||||||
bool isGenerating = false;
|
|
||||||
|
|
||||||
Server(this.spi, this.status, this.client, this.state);
|
Server(this.spi, this.status, this.client, this.state);
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import 'package:toolbox/data/res/ui.dart';
|
|||||||
import '../../data/res/misc.dart';
|
import '../../data/res/misc.dart';
|
||||||
|
|
||||||
const _level2Color = {
|
const _level2Color = {
|
||||||
'[INFO]': Colors.blue,
|
'INFO': Colors.blue,
|
||||||
'[WARNING]': Colors.yellow,
|
'WARNING': Colors.yellow,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebugProvider extends ChangeNotifier {
|
class DebugProvider extends ChangeNotifier {
|
||||||
|
|||||||
@@ -246,6 +246,15 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
void _setServerState(Server s, ServerState ss) {
|
void _setServerState(Server s, ServerState ss) {
|
||||||
s.state = ss;
|
s.state = ss;
|
||||||
|
|
||||||
|
/// Only set [Sever.isBusy] to false when err occurs or finished.
|
||||||
|
switch (ss) {
|
||||||
|
case ServerState.failed || ServerState.finished:
|
||||||
|
s.isBusy = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,19 +271,23 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If busy, it may be because of network reasons that the last request
|
||||||
|
/// has not been completed, and the request should not be made again at this time.
|
||||||
|
if (s.isBusy) return;
|
||||||
|
s.isBusy = true;
|
||||||
|
|
||||||
if (s.state.shouldConnect || (s.client?.isClosed ?? true)) {
|
if (s.state.shouldConnect || (s.client?.isClosed ?? true)) {
|
||||||
_setServerState(s, ServerState.connecting);
|
_setServerState(s, ServerState.connecting);
|
||||||
|
|
||||||
final time1 = DateTime.now();
|
final time1 = DateTime.now();
|
||||||
|
final jumpSpi =
|
||||||
|
spi.jumpId == null ? null : Stores.server.box.get(spi.jumpId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (s.isGenerating) return;
|
|
||||||
s.isGenerating = true;
|
|
||||||
s.client = await genClient(
|
s.client = await genClient(
|
||||||
spi,
|
spi,
|
||||||
timeout: Stores.setting.timeoutD,
|
timeout: Stores.setting.timeoutD,
|
||||||
jumpSpi:
|
jumpSpi: jumpSpi,
|
||||||
spi.jumpId == null ? null : Stores.server.box.get(spi.jumpId),
|
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_limiter.inc(sid);
|
_limiter.inc(sid);
|
||||||
@@ -284,33 +297,43 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
/// In order to keep privacy, print [spi.name] instead of [spi.id]
|
/// In order to keep privacy, print [spi.name] instead of [spi.id]
|
||||||
Loggers.app.warning('Connect to ${spi.name} failed', e);
|
Loggers.app.warning('Connect to ${spi.name} failed', e);
|
||||||
return;
|
return;
|
||||||
} finally {
|
|
||||||
s.isGenerating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final time2 = DateTime.now();
|
final time2 = DateTime.now();
|
||||||
final spentTime = time2.difference(time1).inMilliseconds;
|
final spentTime = time2.difference(time1).inMilliseconds;
|
||||||
|
if (spi.jumpId == null) {
|
||||||
Loggers.app.info('Connected to ${spi.name} in $spentTime ms.');
|
Loggers.app.info('Connected to ${spi.name} in $spentTime ms.');
|
||||||
|
} else {
|
||||||
|
Loggers.app.info(
|
||||||
|
'Connected to ${spi.name} via ${jumpSpi?.name} in $spentTime ms.');
|
||||||
|
}
|
||||||
|
|
||||||
_setServerState(s, ServerState.connected);
|
_setServerState(s, ServerState.connected);
|
||||||
|
|
||||||
// Write script to server
|
// Write script to server
|
||||||
// by ssh
|
// by ssh
|
||||||
try {
|
try {
|
||||||
final writeResult = await s.client?.run(installShellCmd).string;
|
final writeResult =
|
||||||
|
await s.client?.run(ShellFunc.installShellCmd).string;
|
||||||
if (writeResult == null || writeResult.isNotEmpty) {
|
if (writeResult == null || writeResult.isNotEmpty) {
|
||||||
throw Exception('$writeResult');
|
throw Exception('$writeResult');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Loggers.app.warning('Write script to ${spi.name} by shell', e);
|
||||||
// by sftp
|
// by sftp
|
||||||
final localPath = joinPath(await Paths.doc, 'install.sh');
|
final localPath = joinPath(await Paths.doc, 'install.sh');
|
||||||
final file = File(localPath);
|
final file = File(localPath);
|
||||||
try {
|
try {
|
||||||
Loggers.app.warning('Using SFTP to write script to ${spi.name}');
|
Loggers.app.info('Using SFTP to write script to ${spi.name}');
|
||||||
file.writeAsString(ShellFunc.allScript);
|
file.writeAsString(ShellFunc.allScript);
|
||||||
final completer = Completer();
|
final completer = Completer();
|
||||||
|
final homePath = (await s.client?.run('echo \$HOME').string)?.trim();
|
||||||
|
if (homePath == null || homePath.isEmpty) {
|
||||||
|
throw Exception('Got home path: $homePath');
|
||||||
|
}
|
||||||
|
final remotePath = ShellFunc.getShellPath(homePath);
|
||||||
final reqId = Pros.sftp.add(
|
final reqId = Pros.sftp.add(
|
||||||
SftpReq(spi, installShellPath, localPath, SftpReqType.upload),
|
SftpReq(spi, remotePath, localPath, SftpReqType.upload),
|
||||||
completer: completer,
|
completer: completer,
|
||||||
);
|
);
|
||||||
await completer.future;
|
await completer.future;
|
||||||
@@ -322,7 +345,7 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
_limiter.inc(sid);
|
_limiter.inc(sid);
|
||||||
s.status.failedInfo = e.toString();
|
s.status.failedInfo = e.toString();
|
||||||
_setServerState(s, ServerState.failed);
|
_setServerState(s, ServerState.failed);
|
||||||
Loggers.app.warning('Write script to ${spi.name} failed', e);
|
Loggers.app.warning('Write script to ${spi.name} by sftp', e);
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
if (await file.exists()) await file.delete();
|
if (await file.exists()) await file.delete();
|
||||||
@@ -382,11 +405,8 @@ class ServerProvider extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.state != ServerState.finished) {
|
/// Call this every time for setting [Server.isBusy] to false
|
||||||
_setServerState(s, ServerState.finished);
|
_setServerState(s, ServerState.finished);
|
||||||
} else {
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
// reset try times only after prepared successfully
|
// reset try times only after prepared successfully
|
||||||
_limiter.reset(sid);
|
_limiter.reset(sid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -110,8 +112,8 @@ void _setupLogger() {
|
|||||||
Logger.root.level = Level.ALL;
|
Logger.root.level = Level.ALL;
|
||||||
Logger.root.onRecord.listen((record) {
|
Logger.root.onRecord.listen((record) {
|
||||||
Pros.debug.addLog(record);
|
Pros.debug.addLog(record);
|
||||||
// ignore: avoid_print
|
|
||||||
print(record);
|
print(record);
|
||||||
|
if (record.stackTrace != null) print(record.stackTrace);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user