From ec4bf3df240828fc3468b92ef72ca4ef0da6ceca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lollipopkit=F0=9F=8F=B3=EF=B8=8F=E2=80=8D=E2=9A=A7?= =?UTF-8?q?=EF=B8=8F?= <10864310+lollipopkit@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:20:27 +0800 Subject: [PATCH] opt.: sftp dl --- lib/core/utils/server.dart | 2 +- lib/data/model/sftp/worker.dart | 23 +++++++----- lib/view/page/ssh/page/init.dart | 54 +++++++++++++--------------- lib/view/page/ssh/page/virt_key.dart | 4 --- lib/view/page/storage/local.dart | 15 +++++++- lib/view/page/storage/sftp.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 35 +++++++++--------- 8 files changed, 73 insertions(+), 64 deletions(-) diff --git a/lib/core/utils/server.dart b/lib/core/utils/server.dart index 9f7aea44..16fa124b 100644 --- a/lib/core/utils/server.dart +++ b/lib/core/utils/server.dart @@ -58,7 +58,7 @@ Future genClient( Spi? jumpSpi, /// Handle keyboard-interactive authentication - FutureOr?> Function(SSHUserInfoRequest)? onKeyboardInteractive, + SSHUserInfoRequestHandler? onKeyboardInteractive, }) async { onStatus?.call(GenSSHClientStatus.socket); diff --git a/lib/data/model/sftp/worker.dart b/lib/data/model/sftp/worker.dart index c28c8eb0..ff14f0d8 100644 --- a/lib/data/model/sftp/worker.dart +++ b/lib/data/model/sftp/worker.dart @@ -99,16 +99,21 @@ Future _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); } } diff --git a/lib/view/page/ssh/page/init.dart b/lib/view/page/ssh/page/init.dart index 1b94af07..9a533dba 100644 --- a/lib/view/page/ssh/page/init.dart +++ b/lib/view/page/ssh/page/init.dart @@ -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>().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>() + .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() { diff --git a/lib/view/page/ssh/page/virt_key.dart b/lib/view/page/ssh/page/virt_key.dart index b5710523..140e2556 100644 --- a/lib/view/page/ssh/page/virt_key.dart +++ b/lib/view/page/ssh/page/virt_key.dart @@ -164,8 +164,4 @@ extension _VirtKey on SSHPageState { } } } - - FutureOr?> _onKeyboardInteractive(SSHUserInfoRequest req) { - return KeybordInteractive.defaultHandle(widget.args.spi, ctx: context); - } } diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index 2c0ce4cb..d9b8fd9f 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -73,11 +73,24 @@ class _LocalFilePageState extends State 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), ); } diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index c347e0c0..2c394f0e 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -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 diff --git a/pubspec.lock b/pubspec.lock index 966b7191..9977a45f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -324,7 +324,7 @@ packages: source: hosted version: "0.3.4+2" crypto: - dependency: transitive + dependency: "direct main" description: name: crypto sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" diff --git a/pubspec.yaml b/pubspec.yaml index bb68cae0..52fd46d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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