opt.: sftp dl

This commit is contained in:
lollipopkit🏳️‍⚧️
2025-07-21 16:20:27 +08:00
parent 263d4eabb4
commit ec4bf3df24
8 changed files with 73 additions and 64 deletions

View File

@@ -58,7 +58,7 @@ Future<SSHClient> genClient(
Spi? jumpSpi,
/// Handle keyboard-interactive authentication
FutureOr<List<String>?> Function(SSHUserInfoRequest)? onKeyboardInteractive,
SSHUserInfoRequestHandler? onKeyboardInteractive,
}) async {
onStatus?.call(GenSSHClientStatus.socket);

View File

@@ -99,16 +99,21 @@ Future<void> _download(
mainSendPort.send(size);
mainSendPort.send(SftpWorkerStatus.loading);
// Read 2m each time
// Issue #161
// The download speed is about 2m/s may due to single core performance
const defaultChunkSize = 1024 * 1024 * 2;
final chunkSize = size > defaultChunkSize ? defaultChunkSize : size;
for (var i = 0; i < size; i += chunkSize) {
final fileData = file.read(length: chunkSize);
await for (var form in fileData) {
localFile.add(form);
mainSendPort.send((i + form.length) / size * 100);
// Due to single core performance, limit the chunk size
const defaultChunkSize = 1024 * 1024 * 5;
var totalRead = 0;
while (totalRead < size) {
final remaining = size - totalRead;
final chunkSize = remaining > defaultChunkSize ? defaultChunkSize : remaining;
dprint('Size: $size, Total Read: $totalRead, Chunk Size: $chunkSize');
final fileData = file.read(offset: totalRead, length: chunkSize);
await for (var chunk in fileData) {
localFile.add(chunk);
totalRead += chunk.length;
mainSendPort.send(totalRead / size * 100);
}
}

View File

@@ -4,10 +4,7 @@ extension _Init on SSHPageState {
void _initStoredCfg() {
final fontFamilly = Stores.setting.fontPath.fetch().getFileName();
final textSize = Stores.setting.termFontSize.fetch();
final textStyle = TextStyle(
fontFamily: fontFamilly,
fontSize: textSize,
);
final textStyle = TextStyle(fontFamily: fontFamilly, fontSize: textSize);
_terminalStyle = TerminalStyle.fromTextStyle(textStyle);
}
@@ -37,15 +34,12 @@ extension _Init on SSHPageState {
onStatus: (p0) {
_writeLn(p0.toString());
},
onKeyboardInteractive: _onKeyboardInteractive,
onKeyboardInteractive: (_) => KeybordInteractive.defaultHandle(widget.args.spi, ctx: context),
);
_writeLn('${libL10n.execute}: Shell');
final session = await _client?.shell(
pty: SSHPtyConfig(
width: _terminal.viewWidth,
height: _terminal.viewHeight,
),
pty: SSHPtyConfig(width: _terminal.viewWidth, height: _terminal.viewHeight),
environment: widget.args.spi.envs,
);
@@ -98,30 +92,30 @@ extension _Init on SSHPageState {
return;
}
stream.cast<List<int>>().transform(const Utf8Decoder()).listen(
_terminal.write,
onError: (Object error, StackTrace stack) {
// _terminal.write('Stream error: $error\n');
Loggers.root.warning('Error in SSH stream', error, stack);
},
cancelOnError: false,
);
stream
.cast<List<int>>()
.transform(const Utf8Decoder())
.listen(
_terminal.write,
onError: (Object error, StackTrace stack) {
// _terminal.write('Stream error: $error\n');
Loggers.root.warning('Error in SSH stream', error, stack);
},
cancelOnError: false,
);
}
void _setupDiscontinuityTimer() {
_discontinuityTimer = Timer.periodic(
const Duration(seconds: 5),
(_) async {
var throwTimeout = true;
Future.delayed(const Duration(seconds: 3), () {
if (throwTimeout) {
_catchTimeout();
}
});
await _client?.ping();
throwTimeout = false;
},
);
_discontinuityTimer = Timer.periodic(const Duration(seconds: 5), (_) async {
var throwTimeout = true;
Future.delayed(const Duration(seconds: 3), () {
if (throwTimeout) {
_catchTimeout();
}
});
await _client?.ping();
throwTimeout = false;
});
}
void _catchTimeout() {

View File

@@ -164,8 +164,4 @@ extension _VirtKey on SSHPageState {
}
}
}
FutureOr<List<String>?> _onKeyboardInteractive(SSHUserInfoRequest req) {
return KeybordInteractive.defaultHandle(widget.args.spi, ctx: context);
}
}

View File

@@ -73,11 +73,24 @@ class _LocalFilePageState extends State<LocalFilePage> with AutomaticKeepAliveCl
},
icon: const Icon(Icons.add),
),
if (!isMobile)
IconButton(
icon: const Icon(Icons.refresh),
tooltip: MaterialLocalizations.of(context).refreshIndicatorSemanticLabel,
onPressed: () => setState(() {}),
),
if (!isPickFile) _buildMissionBtn(),
_buildSortBtn(),
],
),
body: _sortType.listen(_buildBody),
body: isMobile
? RefreshIndicator(
onRefresh: () async {
setState(() {});
},
child: _sortType.listen(_buildBody),
)
: _sortType.listen(_buildBody),
);
}

View File

@@ -537,7 +537,7 @@ extension _Actions on _SftpPageState {
/// Local file dir + server id + remote path
String _getLocalPath(String remotePath) {
return Paths.file.joinPath(widget.args.spi.id).joinPath(remotePath);
return Paths.file.joinPath(widget.args.spi.oldId).joinPath(remotePath);
}
/// Only return true if the path is changed

View File

@@ -324,7 +324,7 @@ packages:
source: hosted
version: "0.3.4+2"
crypto:
dependency: transitive
dependency: "direct main"
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"

View File

@@ -12,29 +12,30 @@ dependencies:
sdk: flutter
flutter_localizations:
sdk: flutter
hive_ce_flutter: ^2.3.1
choice: ^2.3.2
crypto: ^3.0.6
dio: ^5.2.1
easy_isolate: ^1.3.0
intl: ^0.20.2
highlight: ^0.7.0
flutter_highlight: ^0.7.0
re_editor: ^0.7.0
shared_preferences: ^2.1.1
dynamic_color: ^1.6.6
xml: ^6.4.2 # for parsing nvidia-smi
flutter_displaymode: ^0.6.0
fl_chart: ^1.0.0
wakelock_plus: ^1.2.4
wake_on_lan: ^4.1.1+3
easy_isolate: ^1.3.0
extended_image: ^10.0.0
file_picker: ^10.1.9
json_annotation: ^4.9.0
choice: ^2.3.2
webdav_client_plus: ^1.0.2
freezed_annotation: ^3.0.0
flutter_riverpod: ^2.6.1
riverpod_annotation: ^2.6.1
flutter_highlight: ^0.7.0
flutter_displaymode: ^0.6.0
fl_chart: ^1.0.0
freezed_annotation: ^3.0.0
highlight: ^0.7.0
hive_ce_flutter: ^2.3.1
intl: ^0.20.2
json_annotation: ^4.9.0
responsive_framework: ^1.5.1
re_editor: ^0.7.0
riverpod_annotation: ^2.6.1
shared_preferences: ^2.1.1
wakelock_plus: ^1.2.4
wake_on_lan: ^4.1.1+3
webdav_client_plus: ^1.0.2
xml: ^6.4.2 # for parsing nvidia-smi
dartssh2:
git:
url: https://github.com/lollipopkit/dartssh2