make sftpworker upload/download action handle single file
This commit is contained in:
parent
33ade0479f
commit
075003f1ad
3 changed files with 77 additions and 89 deletions
|
@ -216,23 +216,17 @@ class _SftpExplorerState extends State<SftpExplorer> {
|
||||||
final files = await openFiles();
|
final files = await openFiles();
|
||||||
filePaths = files.map((file) => file.path).toList();
|
filePaths = files.map((file) => file.path).toList();
|
||||||
}
|
}
|
||||||
try {
|
for (final filePath in filePaths) {
|
||||||
bool start = true;
|
try {
|
||||||
await for (final progress in widget.sftpWorker.uploadFiles(path, filePaths)) {
|
await for (final progress in widget.sftpWorker.uploadFile(path, filePath)) {
|
||||||
if (start) {
|
setState(() => _uploadProgress = progress);
|
||||||
start = false;
|
|
||||||
_listDir();
|
|
||||||
}
|
|
||||||
setState(() => _uploadProgress = progress);
|
|
||||||
if (progress == 1) {
|
|
||||||
// TODO: fix: next file also starts to show
|
|
||||||
_listDir();
|
|
||||||
}
|
}
|
||||||
|
await _listDir();
|
||||||
}
|
}
|
||||||
}
|
catch (e) {
|
||||||
catch (e) {
|
if (context.mounted) {
|
||||||
if (context.mounted) {
|
ScaffoldMessenger.of(context).showSnackBar(buildErrorSnackBar(context, e.toString()));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(buildErrorSnackBar(context, e.toString()));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setState(() => _uploadProgress = null);
|
setState(() => _uploadProgress = null);
|
||||||
|
|
|
@ -15,11 +15,11 @@ class ListDir extends SftpCommand {
|
||||||
ListDir(this.path);
|
ListDir(this.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
class UploadFiles extends SftpCommand {
|
class UploadFile extends SftpCommand {
|
||||||
final String path;
|
final String path;
|
||||||
final List<String> filePaths;
|
final String filePath;
|
||||||
|
|
||||||
UploadFiles(this.path, this.filePaths);
|
UploadFile(this.path, this.filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MkDir extends SftpCommand {
|
class MkDir extends SftpCommand {
|
||||||
|
@ -42,12 +42,12 @@ class Rename extends SftpCommand {
|
||||||
Rename(this.oldpath, this.newpath);
|
Rename(this.oldpath, this.newpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadFiles extends SftpCommand {
|
class DownloadFile extends SftpCommand {
|
||||||
final List<SftpName> files;
|
final SftpName file;
|
||||||
final String path;
|
final String path;
|
||||||
final String downloadPath;
|
final String downloadPath;
|
||||||
|
|
||||||
DownloadFiles(this.files, this.path, this.downloadPath);
|
DownloadFile(this.file, this.path, this.downloadPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,33 +120,30 @@ class SftpWorker {
|
||||||
on SftpStatusError catch (e) {
|
on SftpStatusError catch (e) {
|
||||||
sendPort.send((id, RemoteError(e.message, '')));
|
sendPort.send((id, RemoteError(e.message, '')));
|
||||||
}
|
}
|
||||||
case UploadFiles(:final path, :final filePaths):
|
case UploadFile(:final path, :final filePath):
|
||||||
for (var filePath in filePaths) {
|
try {
|
||||||
try {
|
final file = File(filePath);
|
||||||
final file = File(filePath);
|
final fileSize = await file.length();
|
||||||
final fileSize = await file.length();
|
final remoteFile = await sftpClient.open(
|
||||||
final remoteFile = await sftpClient.open(
|
'$path${basename(filePath)}',
|
||||||
'$path${basename(filePath)}',
|
mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive
|
||||||
mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive
|
);
|
||||||
);
|
bool timeout = true;
|
||||||
bool timeout = true;
|
await remoteFile.write(
|
||||||
await remoteFile.write(
|
file.openRead().cast(),
|
||||||
file.openRead().cast(),
|
onProgress: (progress) {
|
||||||
onProgress: (progress) {
|
if (timeout) {
|
||||||
if (timeout) {
|
timeout = false;
|
||||||
timeout = false;
|
sendPort.send((id, progress/fileSize));
|
||||||
sendPort.send((id, progress/fileSize));
|
Future.delayed(Duration(seconds: 2), () => timeout = true);
|
||||||
Future.delayed(Duration(seconds: 2), () => timeout = true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
}
|
);
|
||||||
on SftpStatusError catch (e) {
|
|
||||||
sendPort.send((id, RemoteError(e.message, '')));
|
|
||||||
}
|
|
||||||
sendPort.send((id, 1.0));
|
|
||||||
}
|
}
|
||||||
sendPort.send((id, null));
|
on SftpStatusError catch (e) {
|
||||||
|
sendPort.send((id, RemoteError(e.message, '')));
|
||||||
|
}
|
||||||
|
sendPort.send((id, 1.0));
|
||||||
case MkDir(:final path):
|
case MkDir(:final path):
|
||||||
try {
|
try {
|
||||||
await sftpClient.mkdir(path);
|
await sftpClient.mkdir(path);
|
||||||
|
@ -190,42 +187,39 @@ class SftpWorker {
|
||||||
on SftpStatusError catch (e) {
|
on SftpStatusError catch (e) {
|
||||||
sendPort.send((id, RemoteError(e.message, '')));
|
sendPort.send((id, RemoteError(e.message, '')));
|
||||||
}
|
}
|
||||||
case DownloadFiles(:final files, :final path, :final downloadPath):
|
case DownloadFile(:final file, :final path, :final downloadPath):
|
||||||
for (final file in files) {
|
try {
|
||||||
try {
|
final localFile = File('$downloadPath/${file.filename}');
|
||||||
final localFile = File('$downloadPath/${file.filename}');
|
if (await localFile.exists()) {
|
||||||
if (await localFile.exists()) {
|
sendPort.send((id, RemoteError('File Already Exists', '')));
|
||||||
sendPort.send((id, RemoteError('File Already Exists', '')));
|
break;
|
||||||
continue;
|
}
|
||||||
}
|
final localFileWriter = await localFile.open(mode: FileMode.write);
|
||||||
final localFileWriter = await localFile.open(mode: FileMode.write);
|
final remoteFile = await sftpClient.open('$path${file.filename}');
|
||||||
final remoteFile = await sftpClient.open('$path${file.filename}');
|
final fileSize = file.attr.size!;
|
||||||
final fileSize = file.attr.size!;
|
bool timeout = true;
|
||||||
bool timeout = true;
|
await for (final bytes in remoteFile.read(
|
||||||
await for (final bytes in remoteFile.read(
|
onProgress: (progress) {
|
||||||
onProgress: (progress) {
|
if (timeout) {
|
||||||
if (timeout) {
|
timeout = false;
|
||||||
timeout = false;
|
sendPort.send((id, progress/fileSize));
|
||||||
sendPort.send((id, progress/fileSize));
|
Future.delayed(Duration(seconds: 2), () => timeout = true);
|
||||||
Future.delayed(Duration(seconds: 2), () => timeout = true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)) {
|
|
||||||
await localFileWriter.writeFrom(bytes);
|
|
||||||
}
|
}
|
||||||
|
)) {
|
||||||
|
await localFileWriter.writeFrom(bytes);
|
||||||
}
|
}
|
||||||
on SftpStatusError catch (e) {
|
|
||||||
sendPort.send((id, RemoteError(e.message, '')));
|
|
||||||
}
|
|
||||||
sendPort.send((id, 1.0));
|
|
||||||
}
|
}
|
||||||
sendPort.send((id, null));
|
on SftpStatusError catch (e) {
|
||||||
|
sendPort.send((id, RemoteError(e.message, '')));
|
||||||
|
}
|
||||||
|
sendPort.send((id, 1.0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sftpResponseHandler(dynamic message) {
|
void _sftpResponseHandler(dynamic message) {
|
||||||
final (int id, Object? response) = message;
|
final (int id, Object response) = message;
|
||||||
|
|
||||||
if (_activeRequests[id] is Completer) {
|
if (_activeRequests[id] is Completer) {
|
||||||
final completer = _activeRequests.remove(id)!;
|
final completer = _activeRequests.remove(id)!;
|
||||||
|
@ -243,13 +237,11 @@ class SftpWorker {
|
||||||
controller.addError(response);
|
controller.addError(response);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (response == null) {
|
controller.add(response);
|
||||||
|
if (response == 1) {
|
||||||
controller.close();
|
controller.close();
|
||||||
_activeRequests.remove(id);
|
_activeRequests.remove(id);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
controller.add(response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,11 +256,11 @@ class SftpWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Stream<double> uploadFiles(String path, List<String> filePaths) {
|
Stream<double> uploadFile(String path, String filePath) {
|
||||||
final controller = StreamController<double>();
|
final controller = StreamController<double>();
|
||||||
final id = _idCounter++;
|
final id = _idCounter++;
|
||||||
_activeRequests[id] = controller;
|
_activeRequests[id] = controller;
|
||||||
_commands.send((id, UploadFiles(path, filePaths)));
|
_commands.send((id, UploadFile(path, filePath)));
|
||||||
return controller.stream;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,11 +288,11 @@ class SftpWorker {
|
||||||
await completer.future;
|
await completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<double> downloadFiles(List<SftpName> files, String path, String downloadPath) {
|
Stream<double> downloadFile(SftpName file, String path, String downloadPath) {
|
||||||
final controller = StreamController<double>();
|
final controller = StreamController<double>();
|
||||||
final id = _idCounter++;
|
final id = _idCounter++;
|
||||||
_activeRequests[id] = controller;
|
_activeRequests[id] = controller;
|
||||||
_commands.send((id, DownloadFiles(files, path, downloadPath)));
|
_commands.send((id, DownloadFile(file, path, downloadPath)));
|
||||||
return controller.stream;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,17 +123,19 @@ class OperationButtons extends StatelessWidget {
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final downloadsDir = await getDownloadsDirectory();
|
final downloadsDir = await getDownloadsDirectory();
|
||||||
if (downloadsDir == null) return;
|
if (downloadsDir == null) return;
|
||||||
try {
|
for (final dirEntry in dirEntries) {
|
||||||
await for (final progress in sftpWorker.downloadFiles(dirEntries, path, downloadsDir.path)) {
|
try {
|
||||||
setDownloadProgress(progress);
|
await for (final progress in sftpWorker.downloadFile(dirEntry, path, downloadsDir.path)) {
|
||||||
|
setDownloadProgress(progress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setDownloadProgress(null);
|
catch (e) {
|
||||||
}
|
if (context.mounted) {
|
||||||
catch (e) {
|
ScaffoldMessenger.of(context).showSnackBar(buildErrorSnackBar(context, e.toString()));
|
||||||
if (context.mounted) {
|
}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(buildErrorSnackBar(context, e.toString()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setDownloadProgress(null);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.download)
|
icon: Icon(Icons.download)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue