Merge branch 'main' of github.com:lollipopkit/flutter_server_box

This commit is contained in:
lollipopkit
2024-02-18 10:33:55 +08:00
23 changed files with 257 additions and 48 deletions

View File

@@ -9,26 +9,31 @@ import 'package:toolbox/core/extension/uint8list.dart';
import '../../data/res/misc.dart';
typedef _OnStdout = void Function(String data, StreamSink<Uint8List> sink);
typedef _OnStdin = void Function(StreamSink<Uint8List> sink);
typedef _OnStdout = void Function(String data, SSHSession session);
typedef _OnStdin = void Function(SSHSession session);
typedef PwdRequestFunc = Future<String?> Function(String? user);
extension SSHClientX on SSHClient {
Future<int?> exec(
Future<SSHSession> exec(
String cmd, {
_OnStdout? onStderr,
_OnStdout? onStdout,
_OnStdin? stdin,
bool redirectToBash = false, // not working yet. do not use
}) async {
final session = await execute(cmd);
final session = await execute(redirectToBash ? "head -1 | bash" : cmd);
if (redirectToBash) {
session.stdin.add("$cmd\n".uint8List);
}
final stdoutDone = Completer<void>();
final stderrDone = Completer<void>();
if (onStdout != null) {
session.stdout.listen(
(e) => onStdout(e.string, session.stdin),
(e) => onStdout(e.string, session),
onDone: stdoutDone.complete,
);
} else {
@@ -37,7 +42,7 @@ extension SSHClientX on SSHClient {
if (onStderr != null) {
session.stderr.listen(
(e) => onStderr(e.string, session.stdin),
(e) => onStderr(e.string, session),
onDone: stderrDone.complete,
);
} else {
@@ -45,14 +50,14 @@ extension SSHClientX on SSHClient {
}
if (stdin != null) {
stdin(session.stdin);
stdin(session);
}
await stdoutDone.future;
await stderrDone.future;
session.close();
return session.exitCode;
return session;
}
Future<int?> execWithPwd(
@@ -61,38 +66,48 @@ extension SSHClientX on SSHClient {
_OnStdout? onStdout,
_OnStdout? onStderr,
_OnStdin? stdin,
bool redirectToBash = false, // not working yet. do not use
}) async {
var isRequestingPwd = false;
return await exec(
final session = await exec(
cmd,
onStderr: (data, sink) async {
onStderr?.call(data, sink);
redirectToBash: redirectToBash,
onStderr: (data, session) async {
debugPrint(
" --- execWithPwd stderr (reqPwd = $isRequestingPwd) --- $data");
onStderr?.call(data, session);
if (isRequestingPwd) return;
isRequestingPwd = true;
if (data.contains('[sudo] password for ')) {
isRequestingPwd = true;
final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1);
if (context == null) return;
final pwd = await context.showPwdDialog(user);
if (pwd == null || pwd.isEmpty) {
// Add ctrl + c to exit.
sink.add('\x03'.uint8List);
debugPrint("Empty pwd. Exiting");
session.kill(SSHSignal.INT);
} else {
sink.add('$pwd\n'.uint8List);
session.stdin.add('$pwd\n'.uint8List);
}
isRequestingPwd = false;
}
},
onStdout: onStdout,
onStdout: (data, sink) async {
onStdout?.call(data, sink);
debugPrint(" --- execWithPwd stdout --- $data");
},
stdin: stdin,
);
return session.exitCode;
}
Future<Uint8List> runWithSessionAction(
Future<Uint8List> runForOutput(
String command, {
bool runInPty = false,
bool stdout = true,
bool stderr = true,
Map<String, String>? environment,
Future<void> Function(SSHSession)? action,
Future<void> Function(SSHSession)? action,
}) async {
final session = await execute(
command,

View File

@@ -0,0 +1,83 @@
class ChainComparator<T> {
final ChainComparator<T>? _parent;
final Comparator<T> _comparator;
ChainComparator._create(this._parent, this._comparator);
ChainComparator.empty() : this._create(null, (a, b) => 0);
ChainComparator.create() : this._create(null, (a, b) => 0);
static ChainComparator<T> comparing<T, F extends Comparable<F>>(
F Function(T) extractor) {
return ChainComparator._create(
null, (a, b) => extractor(a).compareTo(extractor(b)));
}
int compare(T a, T b) {
final parent = _parent;
if (parent != null) {
final int result = parent.compare(a, b);
if (result != 0) return result;
}
return _comparator(a, b);
}
int call(T a, T b) {
return compare(a, b);
}
ChainComparator<T> thenCompareBy<F extends Comparable<F>>(
F Function(T) extractor,
{bool reversed = false}) {
return ChainComparator._create(
this,
reversed
? (a, b) => extractor(b).compareTo(extractor(a))
: (a, b) => extractor(a).compareTo(extractor(b)),
);
}
ChainComparator<T> thenWithComparator(Comparator<T> comparator,
{bool reversed = false}) {
return ChainComparator._create(
this,
!reversed ? comparator : (a, b) => comparator(b, a),
);
}
ChainComparator<T> thenCompareByReversed<F extends Comparable<F>>(
F Function(T) extractor) {
return ChainComparator._create(
this, (a, b) => -extractor(a).compareTo(extractor(b)));
}
ChainComparator<T> thenTrueFirst(bool Function(T) f) {
return ChainComparator._create(this, (a, b) {
final fa = f(a), fb = f(b);
return fa == fb ? 0 : (fa ? -1 : 1);
});
}
ChainComparator<T> reversed() {
return ChainComparator._create(null, (a, b) => this.compare(b, a));
}
}
class Comparators {
static Comparator<String> compareStringCaseInsensitive(
{bool uppercaseFirst = false}) {
return (String a, String b) {
final r = a.toLowerCase().compareTo(b.toLowerCase());
if (r != 0) return r;
return uppercaseFirst ? a.compareTo(b) : b.compareTo(a);
};
}
}
/*
Comparator.comparing<Type1, Type2>(Type1::getType2)
.thenCompare<Type3>(Type1::getType3)
.thenCompare<Type4>(Type1::getType4)
.thenCompareReversed<Type5>(Type1::getType5)
*/

View File

@@ -61,3 +61,4 @@ final isWeb = OS.type == OS.web;
final isMobile = OS.type == OS.ios || OS.type == OS.android;
final isDesktop =
OS.type == OS.linux || OS.type == OS.macos || OS.type == OS.windows;
const isDebuggingMobileLayoutOnDesktop = kDebugMode;