214 lines
5.8 KiB
Dart
214 lines
5.8 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:archive/archive_io.dart';
|
|
import 'package:cloud_archiver/config.dart';
|
|
import 'package:cloud_archiver/state.dart';
|
|
import 'package:filesize/filesize.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:path/path.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:webdav_client/webdav_client.dart' as dav;
|
|
|
|
late dav.Client _client;
|
|
|
|
String totalSize() {
|
|
if (cloudArchives.value.isEmpty) return '0 MB';
|
|
return filesize(
|
|
cloudArchives.value.values
|
|
.map((archives) => archives.map((archive) => archive.size ?? 0).reduce((total, size) => total + size))
|
|
.reduce((total, size) => total + size),
|
|
1,
|
|
);
|
|
}
|
|
|
|
Future<bool> connect(String server, String user, String auth) async {
|
|
var client = dav.newClient(
|
|
server,
|
|
debug: true,
|
|
user: user,
|
|
password: auth,
|
|
);
|
|
client.setHeaders({'accept-charset': 'utf-8'});
|
|
|
|
client.setConnectTimeout(5 * 1000);
|
|
|
|
// Set send data timeout time in milliseconds.
|
|
client.setSendTimeout(60 * 1000);
|
|
|
|
// Set transfer data time in milliseconds.
|
|
client.setReceiveTimeout(60 * 1000);
|
|
|
|
try {
|
|
davStatus.value = DavStatus.loading;
|
|
await client.ping();
|
|
davStatus.value = DavStatus.connected;
|
|
_client = client;
|
|
return true;
|
|
} catch (e) {
|
|
print('$e');
|
|
davStatus.value = DavStatus.notConnected;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void loadLocalStatus() {
|
|
if (appConfig?.syncItems.isNotEmpty != true) return;
|
|
var result = <SyncItemConfig, DateTime?>{};
|
|
for (var syncItem in appConfig!.syncItems) {
|
|
var file = File(syncItem.path);
|
|
var stat = file.statSync();
|
|
switch (stat.type) {
|
|
case FileSystemEntityType.file:
|
|
result[syncItem] = stat.modified;
|
|
case FileSystemEntityType.directory:
|
|
result[syncItem] = dirModifiedTime(syncItem.path);
|
|
default:
|
|
result[syncItem] = null;
|
|
}
|
|
}
|
|
|
|
localSyncItems.value = {
|
|
...localSyncItems.value,
|
|
...result,
|
|
};
|
|
}
|
|
|
|
DateTime dirModifiedTime(String dir) {
|
|
var directory = Directory(dir);
|
|
var modified = directory.statSync().modified;
|
|
for (var entry in Directory(dir).listSync(recursive: true)) {
|
|
var stat = entry.statSync();
|
|
if (stat.type == FileSystemEntityType.file) {
|
|
if (stat.modified.isAfter(modified)) {
|
|
modified = stat.modified;
|
|
}
|
|
}
|
|
}
|
|
return modified;
|
|
}
|
|
|
|
void loadCloudArchives() async {
|
|
if (davStatus.value != DavStatus.connected) return;
|
|
davStatus.value = DavStatus.loading;
|
|
List<dav.File> list = [];
|
|
try {
|
|
list = await _client.readDir('/');
|
|
} catch (e) {
|
|
print(e);
|
|
davStatus.value = DavStatus.notConnected;
|
|
return;
|
|
}
|
|
var result = <String, List<dav.File>>{};
|
|
for (var item in list) {
|
|
if (item.isDir == true && item.path?.isNotEmpty == true) {
|
|
var files = await _client.readDir(item.path!);
|
|
result[basename(item.path!)] = files;
|
|
}
|
|
}
|
|
|
|
cloudArchives.value = result;
|
|
davStatus.value = DavStatus.connected;
|
|
}
|
|
|
|
Future<void> upload(BuildContext context, SyncItemConfig item, bool needCreateDir) async {
|
|
if (needCreateDir) {
|
|
await _client.mkdir(item.name);
|
|
}
|
|
var file = File(item.path);
|
|
|
|
var cacheDir = await getApplicationCacheDirectory();
|
|
|
|
var zipFileEncoder = ZipFileEncoder();
|
|
var zipFileName = '${appConfig?.client ?? 'DEBUG'}-${DateTime.now().strFileName}.zip';
|
|
var zipTempFilePath = join(cacheDir.path, zipFileName);
|
|
zipFileEncoder.create(zipTempFilePath);
|
|
if (file.statSync().type == FileSystemEntityType.directory) {
|
|
var directory = Directory(item.path);
|
|
for (var file in directory.listSync()) {
|
|
print('Add file: ${file.path}');
|
|
}
|
|
await zipFileEncoder.addDirectory(
|
|
directory,
|
|
onProgress: (progress) {
|
|
print('Zip progress: $progress');
|
|
},
|
|
);
|
|
} else {
|
|
await zipFileEncoder.addFile(file);
|
|
}
|
|
|
|
await zipFileEncoder.close();
|
|
await _client.writeFromFile(zipTempFilePath, join(item.name, zipFileName));
|
|
|
|
File(zipTempFilePath).delete();
|
|
if (context.mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('上传完成'),
|
|
),
|
|
);
|
|
}
|
|
loadCloudArchives();
|
|
}
|
|
|
|
Future<void> download(BuildContext context, SyncItemConfig item, dav.File cloudArchive) async {
|
|
print('Start download: ${cloudArchive.path}');
|
|
var cacheDir = await getApplicationCacheDirectory();
|
|
var zipPath = join(cacheDir.path, '${item.name}_${cloudArchive.name}');
|
|
await _client.read2File(
|
|
cloudArchive.path!,
|
|
zipPath,
|
|
onProgress: (count, total) {
|
|
print('Downloaded: $count/$total');
|
|
},
|
|
);
|
|
await extractFileToDisk(
|
|
zipPath,
|
|
cacheDir.path,
|
|
callback: (entry) {
|
|
print('Unzip: ${entry.name}');
|
|
},
|
|
);
|
|
File(zipPath).delete();
|
|
|
|
var temp = File(join(cacheDir.path, basename(item.path)));
|
|
print('Temp path: ${temp.path}');
|
|
var fileSystemEntityType = temp.statSync().type;
|
|
|
|
switch (fileSystemEntityType) {
|
|
case FileSystemEntityType.directory:
|
|
var directory = Directory(item.path);
|
|
if (directory.existsSync()) {
|
|
directory.deleteSync(recursive: true);
|
|
}
|
|
Directory(temp.path);
|
|
Directory(temp.path).renameSync(item.path);
|
|
case FileSystemEntityType.file:
|
|
var file = File(item.path);
|
|
if (file.existsSync()) {
|
|
file.deleteSync();
|
|
}
|
|
temp.renameSync(item.path);
|
|
default:
|
|
print('Failed: $fileSystemEntityType');
|
|
}
|
|
|
|
if (context.mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('下载完成'),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
extension DateTimeExt on DateTime {
|
|
String get strHm => '$year/${padZero(month)}/${padZero(day)} ${padZero(hour)}:${padZero(minute)}';
|
|
|
|
String get strHms => '$strHm:${padZero(second)}';
|
|
|
|
String get strFileName => '${year}_${padZero(month)}_${padZero(day)}_${padZero(hour)}_${padZero(minute)}_${padZero(second)}';
|
|
|
|
String padZero(int num, [fix = 2]) => num.toString().padLeft(fix, '0');
|
|
}
|