mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix: sftp dl
This commit is contained in:
@@ -570,7 +570,7 @@ abstract class S {
|
|||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'request failed, status code: {code}'**
|
/// **'request failed, status code: {code}'**
|
||||||
String httpFailedWithCode(Object code, Object kode);
|
String httpFailedWithCode(Object code);
|
||||||
|
|
||||||
/// No description provided for @image.
|
/// No description provided for @image.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ class SDe extends S {
|
|||||||
String get host => 'Host';
|
String get host => 'Host';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String httpFailedWithCode(Object code, Object kode) {
|
String httpFailedWithCode(Object code) {
|
||||||
return 'Anfrage fehlgeschlagen, Statuscode: $code';
|
return 'Anfrage fehlgeschlagen, Statuscode: $code';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ class SEn extends S {
|
|||||||
String get host => 'Host';
|
String get host => 'Host';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String httpFailedWithCode(Object code, Object kode) {
|
String httpFailedWithCode(Object code) {
|
||||||
return 'request failed, status code: $code';
|
return 'request failed, status code: $code';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,8 +255,8 @@ class SId extends S {
|
|||||||
String get host => 'Host';
|
String get host => 'Host';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String httpFailedWithCode(Object code, Object kode) {
|
String httpFailedWithCode(Object code) {
|
||||||
return 'Permintaan gagal, kode status: $kode';
|
return 'Permintaan gagal, kode status: $code';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ class SZh extends S {
|
|||||||
String get host => '主机';
|
String get host => '主机';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String httpFailedWithCode(Object code, Object kode) {
|
String httpFailedWithCode(Object code) {
|
||||||
return '请求失败, 状态码: $code';
|
return '请求失败, 状态码: $code';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,7 +931,7 @@ class SZhTw extends SZh {
|
|||||||
String get host => '主機';
|
String get host => '主機';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String httpFailedWithCode(Object code, Object kode) {
|
String httpFailedWithCode(Object code) {
|
||||||
return '請求失敗, 狀態碼: $code';
|
return '請求失敗, 狀態碼: $code';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Especially thanks to <a href="https://github.com/TerminalStudio/dartssh2">dartss
|
|||||||
- [x] `Status` charts
|
- [x] `Status` charts
|
||||||
- [x] `Code editor`
|
- [x] `Code editor`
|
||||||
- [x] `Ping` and etc.
|
- [x] `Ping` and etc.
|
||||||
- [x] Localization ( English, 简体中文, Deutsch, 繁體中文. [How to contribute?](#l10n-guide))
|
- [x] Localization ( English, 简体中文, Deutsch, 繁體中文, Indonesian. [How to contribute?](#l10n-guide))
|
||||||
- [x] Desktop support
|
- [x] Desktop support
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
- [x] 状态图表
|
- [x] 状态图表
|
||||||
- [x] 代码编辑器
|
- [x] 代码编辑器
|
||||||
- [x] `Ping` 和 更多
|
- [x] `Ping` 和 更多
|
||||||
- [x] 本地化 ( English, 简体中文, Deutsch, 繁體中文。 [如何贡献?](#l10n-guide))
|
- [x] 本地化 ( English, 简体中文, Deutsch, 繁體中文, Indonesian。 [如何贡献?](#l10n-guide))
|
||||||
- [x] 桌面端支持
|
- [x] 桌面端支持
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -470,7 +470,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -478,7 +478,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -602,7 +602,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -610,7 +610,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -628,7 +628,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||||
@@ -636,7 +636,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -657,7 +657,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -670,7 +670,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
@@ -696,7 +696,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -709,7 +709,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -732,7 +732,7 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -745,7 +745,7 @@
|
|||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ class PersistentStore<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StoreProperty<T> property<T>(String key, {T? defaultValue}) {
|
StoreProperty<T> property<T>(String key, {T? defaultValue}) {
|
||||||
|
|
||||||
return StoreProperty<T>(box, key, defaultValue);
|
return StoreProperty<T>(box, key, defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,21 @@ enum GenSSHClientStatus {
|
|||||||
pwd,
|
pwd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getPrivateKey(String id) {
|
||||||
|
final key = locator<PrivateKeyStore>().get(id);
|
||||||
|
if (key == null) {
|
||||||
|
throw SSHErr(
|
||||||
|
type: SSHErrType.noPrivateKey,
|
||||||
|
message: 'key [$id] not found',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return key.privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
Future<SSHClient> genClient(
|
Future<SSHClient> genClient(
|
||||||
ServerPrivateInfo spi, {
|
ServerPrivateInfo spi, {
|
||||||
void Function(GenSSHClientStatus)? onStatus,
|
void Function(GenSSHClientStatus)? onStatus,
|
||||||
|
String? privateKey,
|
||||||
}) async {
|
}) async {
|
||||||
onStatus?.call(GenSSHClientStatus.socket);
|
onStatus?.call(GenSSHClientStatus.socket);
|
||||||
late SSHSocket socket;
|
late SSHSocket socket;
|
||||||
@@ -66,17 +78,12 @@ Future<SSHClient> genClient(
|
|||||||
onPasswordRequest: () => spi.pwd,
|
onPasswordRequest: () => spi.pwd,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final key = locator<PrivateKeyStore>().get(spi.pubKeyId!);
|
privateKey ??= getPrivateKey(spi.pubKeyId!);
|
||||||
if (key == null) {
|
|
||||||
throw SSHErr(
|
|
||||||
type: SSHErrType.noPrivateKey,
|
|
||||||
message: 'key [${spi.pubKeyId}] not found',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
onStatus?.call(GenSSHClientStatus.key);
|
onStatus?.call(GenSSHClientStatus.key);
|
||||||
return SSHClient(
|
return SSHClient(
|
||||||
socket,
|
socket,
|
||||||
username: spi.user,
|
username: spi.user,
|
||||||
identities: await compute(loadIndentity, key.privateKey),
|
identities: await compute(loadIndentity, privateKey),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,38 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import '../../../core/utils/server.dart';
|
||||||
import '../server/server_private_info.dart';
|
import '../server/server_private_info.dart';
|
||||||
import 'worker.dart';
|
import 'worker.dart';
|
||||||
|
|
||||||
class SftpReqItem {
|
class SftpReq {
|
||||||
final ServerPrivateInfo spi;
|
final ServerPrivateInfo spi;
|
||||||
final String remotePath;
|
final String remotePath;
|
||||||
final String localPath;
|
final String localPath;
|
||||||
|
final SftpReqType type;
|
||||||
|
String? privateKey;
|
||||||
|
|
||||||
SftpReqItem(this.spi, this.remotePath, this.localPath);
|
SftpReq(
|
||||||
|
this.spi,
|
||||||
|
this.remotePath,
|
||||||
|
this.localPath,
|
||||||
|
this.type,
|
||||||
|
) {
|
||||||
|
if (spi.pubKeyId != null) {
|
||||||
|
privateKey = getPrivateKey(spi.pubKeyId!);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SftpReqType { download, upload }
|
enum SftpReqType { download, upload }
|
||||||
|
|
||||||
class SftpReq {
|
|
||||||
final SftpReqItem item;
|
|
||||||
final String? privateKey;
|
|
||||||
final SftpReqType type;
|
|
||||||
|
|
||||||
SftpReq({required this.item, this.privateKey, required this.type});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SftpReqStatus {
|
class SftpReqStatus {
|
||||||
final int id;
|
final int id;
|
||||||
final SftpReqItem item;
|
final SftpReq req;
|
||||||
final void Function() notifyListeners;
|
final void Function() notifyListeners;
|
||||||
late SftpWorker worker;
|
late SftpWorker worker;
|
||||||
final Completer? completer;
|
final Completer? completer;
|
||||||
|
|
||||||
String get fileName => item.localPath.split('/').last;
|
String get fileName => req.localPath.split('/').last;
|
||||||
|
|
||||||
// status of the download
|
// status of the download
|
||||||
double? progress;
|
double? progress;
|
||||||
@@ -38,17 +42,14 @@ class SftpReqStatus {
|
|||||||
Duration? spentTime;
|
Duration? spentTime;
|
||||||
|
|
||||||
SftpReqStatus({
|
SftpReqStatus({
|
||||||
required this.item,
|
required this.req,
|
||||||
required this.notifyListeners,
|
required this.notifyListeners,
|
||||||
required SftpReqType type,
|
|
||||||
this.completer,
|
this.completer,
|
||||||
}) : id = DateTime.now().microsecondsSinceEpoch {
|
}) : id = DateTime.now().microsecondsSinceEpoch {
|
||||||
worker = SftpWorker(
|
worker = SftpWorker(
|
||||||
onNotify: onNotify,
|
onNotify: onNotify,
|
||||||
item: item,
|
req: req,
|
||||||
type: type,
|
)..init();
|
||||||
);
|
|
||||||
worker.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -79,6 +80,7 @@ class SftpReqStatus {
|
|||||||
spentTime = event;
|
spentTime = event;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
error = Exception('unknown event: $event');
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,20 +6,19 @@ import 'dart:typed_data';
|
|||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:easy_isolate/easy_isolate.dart';
|
import 'package:easy_isolate/easy_isolate.dart';
|
||||||
import 'package:toolbox/core/utils/misc.dart';
|
import 'package:toolbox/core/utils/misc.dart';
|
||||||
|
import 'package:toolbox/core/utils/server.dart';
|
||||||
|
|
||||||
import 'req.dart';
|
import 'req.dart';
|
||||||
|
|
||||||
class SftpWorker {
|
class SftpWorker {
|
||||||
final Function(Object event) onNotify;
|
final Function(Object event) onNotify;
|
||||||
final SftpReqItem item;
|
final SftpReq req;
|
||||||
final SftpReqType type;
|
|
||||||
|
|
||||||
final worker = Worker();
|
final worker = Worker();
|
||||||
|
|
||||||
SftpWorker({
|
SftpWorker({
|
||||||
required this.onNotify,
|
required this.onNotify,
|
||||||
required this.item,
|
required this.req,
|
||||||
required this.type,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@@ -35,7 +34,7 @@ class SftpWorker {
|
|||||||
isolateMessageHandler,
|
isolateMessageHandler,
|
||||||
errorHandler: print,
|
errorHandler: print,
|
||||||
);
|
);
|
||||||
worker.sendMessage(SftpReq(item: item, type: type));
|
worker.sendMessage(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle the messages coming from the isolate
|
/// Handle the messages coming from the isolate
|
||||||
@@ -69,29 +68,19 @@ Future<void> isolateMessageHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _download(
|
Future<void> _download(
|
||||||
SftpReq data,
|
SftpReq req,
|
||||||
SendPort mainSendPort,
|
SendPort mainSendPort,
|
||||||
SendErrorFunction sendError,
|
SendErrorFunction sendError,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
mainSendPort.send(SftpWorkerStatus.preparing);
|
mainSendPort.send(SftpWorkerStatus.preparing);
|
||||||
final watch = Stopwatch()..start();
|
final watch = Stopwatch()..start();
|
||||||
final item = data.item;
|
final client = await genClient(req.spi, privateKey: req.privateKey);
|
||||||
final spi = item.spi;
|
|
||||||
final socket = await SSHSocket.connect(spi.ip, spi.port);
|
|
||||||
SSHClient client;
|
|
||||||
if (spi.pubKeyId == null) {
|
|
||||||
client = SSHClient(socket,
|
|
||||||
username: spi.user, onPasswordRequest: () => spi.pwd);
|
|
||||||
} else {
|
|
||||||
client = SSHClient(socket,
|
|
||||||
username: spi.user, identities: SSHKeyPair.fromPem(data.privateKey!));
|
|
||||||
}
|
|
||||||
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
||||||
|
|
||||||
final remotePath = item.remotePath;
|
final remotePath = req.remotePath;
|
||||||
final localPath = item.localPath;
|
final localPath = req.localPath;
|
||||||
await Directory(localPath.substring(0, item.localPath.lastIndexOf('/')))
|
await Directory(localPath.substring(0, req.localPath.lastIndexOf('/')))
|
||||||
.create(recursive: true);
|
.create(recursive: true);
|
||||||
final local = File(localPath);
|
final local = File(localPath);
|
||||||
if (await local.exists()) {
|
if (await local.exists()) {
|
||||||
@@ -104,7 +93,8 @@ Future<void> _download(
|
|||||||
mainSendPort.send(Exception('can not get file size'));
|
mainSendPort.send(Exception('can not get file size'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const defaultChunkSize = 1024 * 1024;
|
// Read 10m each time
|
||||||
|
const defaultChunkSize = 1024 * 1024 * 10;
|
||||||
final chunkSize = size > defaultChunkSize ? defaultChunkSize : size;
|
final chunkSize = size > defaultChunkSize ? defaultChunkSize : size;
|
||||||
mainSendPort.send(size);
|
mainSendPort.send(size);
|
||||||
mainSendPort.send(SftpWorkerStatus.downloading);
|
mainSendPort.send(SftpWorkerStatus.downloading);
|
||||||
@@ -125,29 +115,19 @@ Future<void> _download(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _upload(
|
Future<void> _upload(
|
||||||
SftpReq data,
|
SftpReq req,
|
||||||
SendPort mainSendPort,
|
SendPort mainSendPort,
|
||||||
SendErrorFunction sendError,
|
SendErrorFunction sendError,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
mainSendPort.send(SftpWorkerStatus.preparing);
|
mainSendPort.send(SftpWorkerStatus.preparing);
|
||||||
final watch = Stopwatch()..start();
|
final watch = Stopwatch()..start();
|
||||||
final item = data.item;
|
final client = await genClient(req.spi, privateKey: req.privateKey);
|
||||||
final spi = item.spi;
|
|
||||||
final socket = await SSHSocket.connect(spi.ip, spi.port);
|
|
||||||
SSHClient client;
|
|
||||||
if (spi.pubKeyId == null) {
|
|
||||||
client = SSHClient(socket,
|
|
||||||
username: spi.user, onPasswordRequest: () => spi.pwd);
|
|
||||||
} else {
|
|
||||||
client = SSHClient(socket,
|
|
||||||
username: spi.user, identities: SSHKeyPair.fromPem(data.privateKey!));
|
|
||||||
}
|
|
||||||
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
mainSendPort.send(SftpWorkerStatus.sshConnectted);
|
||||||
|
|
||||||
final localPath = item.localPath;
|
final localPath = req.localPath;
|
||||||
final remotePath =
|
final remotePath =
|
||||||
item.remotePath + (getFileName(localPath) ?? 'srvbox_sftp_upload');
|
req.remotePath + (getFileName(localPath) ?? 'srvbox_sftp_upload');
|
||||||
final local = File(localPath);
|
final local = File(localPath);
|
||||||
if (!await local.exists()) {
|
if (!await local.exists()) {
|
||||||
mainSendPort.send(Exception('local file not exists'));
|
mainSendPort.send(Exception('local file not exists'));
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class SftpProvider extends ProviderBase {
|
|||||||
found = _status.where((e) => e.id == id);
|
found = _status.where((e) => e.id == id);
|
||||||
}
|
}
|
||||||
if (fileName != null) {
|
if (fileName != null) {
|
||||||
found = found.where((e) => e.item.localPath.split('/').last == fileName);
|
found = found.where((e) => e.req.localPath.split('/').last == fileName);
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,11 @@ class SftpProvider extends ProviderBase {
|
|||||||
return found.first;
|
return found.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(SftpReqItem item, SftpReqType type, {Completer? completer}) {
|
void add(SftpReq req, {Completer? completer}) {
|
||||||
_status.add(SftpReqStatus(
|
_status.add(SftpReqStatus(
|
||||||
item: item,
|
|
||||||
notifyListeners: notifyListeners,
|
notifyListeners: notifyListeners,
|
||||||
type: type,
|
|
||||||
completer: completer,
|
completer: completer,
|
||||||
|
req: req,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
class BuildData {
|
class BuildData {
|
||||||
static const String name = "ServerBox";
|
static const String name = "ServerBox";
|
||||||
static const int build = 389;
|
static const int build = 395;
|
||||||
static const String engine = "3.10.6";
|
static const String engine = "3.10.6";
|
||||||
static const String buildAt = "2023-07-28 13:50:35.251988";
|
static const String buildAt = "2023-07-28 17:28:52.039761";
|
||||||
static const int modifications = 17;
|
static const int modifications = 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,5 +44,3 @@ const centerSizedLoading = SizedBox(
|
|||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadingIcon = IconButton(onPressed: null, icon: centerLoading);
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const myGithub = 'https://github.com/lollipopkit';
|
|||||||
const appHelpUrl = '$myGithub/flutter_server_box#-help';
|
const appHelpUrl = '$myGithub/flutter_server_box#-help';
|
||||||
|
|
||||||
// Thanks
|
// Thanks
|
||||||
|
// If you want to change the url, please open an issue.
|
||||||
const thanksMap = {
|
const thanksMap = {
|
||||||
'its-tom': 'https://github.com/its-tom',
|
'its-tom': 'https://github.com/its-tom',
|
||||||
'RainSunMe': 'https://github.com/RainSunMe',
|
'RainSunMe': 'https://github.com/RainSunMe',
|
||||||
@@ -15,4 +16,5 @@ const thanksMap = {
|
|||||||
'Aeorq': 'https://github.com/Aeorq',
|
'Aeorq': 'https://github.com/Aeorq',
|
||||||
'jaychoubaby': 'https://github.com/jaychoubaby',
|
'jaychoubaby': 'https://github.com/jaychoubaby',
|
||||||
'allonmymind': 'https://github.com/allonmymind',
|
'allonmymind': 'https://github.com/allonmymind',
|
||||||
|
'azkadev': 'https://github.com/azkadev'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
"goto": "Pergi ke",
|
"goto": "Pergi ke",
|
||||||
"homeWidgetUrlConfig": "Konfigurasi URL Widget Rumah",
|
"homeWidgetUrlConfig": "Konfigurasi URL Widget Rumah",
|
||||||
"host": "Host",
|
"host": "Host",
|
||||||
"httpFailedWithCode": "Permintaan gagal, kode status: {kode}",
|
"httpFailedWithCode": "Permintaan gagal, kode status: {code}",
|
||||||
"image": "Gambar",
|
"image": "Gambar",
|
||||||
"imagesList": "Daftar gambar",
|
"imagesList": "Daftar gambar",
|
||||||
"import": "Impor",
|
"import": "Impor",
|
||||||
|
|||||||
@@ -103,7 +103,9 @@ class _EditorPageState extends State<EditorPage> with AfterLayoutMixin {
|
|||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: CodeTheme(
|
child: CodeTheme(
|
||||||
data: CodeThemeData(styles: _codeTheme ?? (isDarkMode(context) ? monokaiTheme : a11yLightTheme)),
|
data: CodeThemeData(
|
||||||
|
styles: _codeTheme ??
|
||||||
|
(isDarkMode(context) ? monokaiTheme : a11yLightTheme)),
|
||||||
child: CodeField(
|
child: CodeField(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
|||||||
@@ -280,10 +280,12 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
|||||||
showSnackBar(context, Text(_s.fieldMustNotEmpty));
|
showSnackBar(context, Text(_s.fieldMustNotEmpty));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
locator<SftpProvider>().add(
|
locator<SftpProvider>().add(SftpReq(
|
||||||
SftpReqItem(spi, remotePath, file.absolute.path),
|
spi,
|
||||||
|
remotePath,
|
||||||
|
file.absolute.path,
|
||||||
SftpReqType.upload,
|
SftpReqType.upload,
|
||||||
);
|
));
|
||||||
showSnackBar(context, Text(_s.added2List));
|
showSnackBar(context, Text(_s.added2List));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -79,7 +79,11 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
|
|
||||||
Widget _buildItem(SftpReqStatus status) {
|
Widget _buildItem(SftpReqStatus status) {
|
||||||
if (status.error != null) {
|
if (status.error != null) {
|
||||||
showSnackBar(context, Text(status.error.toString()));
|
final err = status.error.toString();
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 377),
|
||||||
|
() => showSnackBar(context, Text(err)),
|
||||||
|
);
|
||||||
status.error = null;
|
status.error = null;
|
||||||
}
|
}
|
||||||
switch (status.status) {
|
switch (status.status) {
|
||||||
@@ -92,7 +96,7 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
status,
|
status,
|
||||||
str,
|
str,
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () => shareFiles(context, [status.item.localPath]),
|
onPressed: () => shareFiles(context, [status.req.localPath]),
|
||||||
icon: const Icon(Icons.open_in_new),
|
icon: const Icon(Icons.open_in_new),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -103,18 +107,35 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
return _wrapInCard(
|
return _wrapInCard(
|
||||||
status,
|
status,
|
||||||
_s.downloadStatus(percentStr, size),
|
_s.downloadStatus(percentStr, size),
|
||||||
trailing: CircularProgressIndicator(value: percent),
|
trailing: SizedBox(
|
||||||
|
height: 27,
|
||||||
|
width: 27,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
value: percent,
|
||||||
|
),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
case SftpWorkerStatus.preparing:
|
case SftpWorkerStatus.preparing:
|
||||||
return _wrapInCard(status, _s.sftpDlPrepare, trailing: loadingIcon);
|
return _wrapInCard(
|
||||||
|
status,
|
||||||
|
_s.sftpDlPrepare,
|
||||||
|
trailing: _loading,
|
||||||
|
);
|
||||||
case SftpWorkerStatus.sshConnectted:
|
case SftpWorkerStatus.sshConnectted:
|
||||||
return _wrapInCard(status, _s.sftpSSHConnected, trailing: loadingIcon);
|
return _wrapInCard(
|
||||||
|
status,
|
||||||
|
_s.sftpSSHConnected,
|
||||||
|
trailing: _loading,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return _wrapInCard(
|
return _wrapInCard(
|
||||||
status,
|
status,
|
||||||
_s.unknown,
|
_s.unknown,
|
||||||
trailing: const Icon(Icons.error, size: 40),
|
trailing: const Icon(Icons.error),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _loading =
|
||||||
|
SizedBox(height: 27, width: 27, child: CircularProgressIndicator());
|
||||||
|
|||||||
@@ -174,8 +174,12 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_sftp.add(
|
_sftp.add(
|
||||||
SftpReqItem(widget.spi, remotePath, path),
|
SftpReq(
|
||||||
|
widget.spi,
|
||||||
|
remotePath,
|
||||||
|
path,
|
||||||
SftpReqType.upload,
|
SftpReqType.upload,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.upload_file));
|
icon: const Icon(Icons.upload_file));
|
||||||
@@ -350,8 +354,13 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
final remotePath = _getRemotePath(name);
|
final remotePath = _getRemotePath(name);
|
||||||
final localPath = await _getLocalPath(remotePath);
|
final localPath = await _getLocalPath(remotePath);
|
||||||
final completer = Completer();
|
final completer = Completer();
|
||||||
final req = SftpReqItem(widget.spi, remotePath, localPath);
|
final req = SftpReq(
|
||||||
_sftp.add(req, SftpReqType.download, completer: completer);
|
widget.spi,
|
||||||
|
remotePath,
|
||||||
|
localPath,
|
||||||
|
SftpReqType.download,
|
||||||
|
);
|
||||||
|
_sftp.add(req, completer: completer);
|
||||||
showRoundDialog(context: context, child: centerSizedLoading);
|
showRoundDialog(context: context, child: centerSizedLoading);
|
||||||
await completer.future;
|
await completer.future;
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -361,7 +370,7 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
'SFTP edit',
|
'SFTP edit',
|
||||||
).go<String>(context);
|
).go<String>(context);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
_sftp.add(req, SftpReqType.upload);
|
_sftp.add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,12 +390,12 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
final remotePath = _getRemotePath(name);
|
final remotePath = _getRemotePath(name);
|
||||||
|
|
||||||
_sftp.add(
|
_sftp.add(
|
||||||
SftpReqItem(
|
SftpReq(
|
||||||
widget.spi,
|
widget.spi,
|
||||||
remotePath,
|
remotePath,
|
||||||
await _getLocalPath(remotePath),
|
await _getLocalPath(remotePath),
|
||||||
),
|
|
||||||
SftpReqType.download,
|
SftpReqType.download,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
context.pop();
|
context.pop();
|
||||||
|
|||||||
@@ -475,9 +475,9 @@
|
|||||||
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
|
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -490,9 +490,9 @@
|
|||||||
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
|
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -505,9 +505,9 @@
|
|||||||
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
|
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 389;
|
CURRENT_PROJECT_VERSION = 395;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0.389;
|
MARKETING_VERSION = 1.0.395;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|||||||
Reference in New Issue
Block a user