mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
sync data using webdav
This commit is contained in:
205
lib/utils/data_sync.dart
Normal file
205
lib/utils/data_sync.dart
Normal file
@@ -0,0 +1,205 @@
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:venera/foundation/app.dart';
|
||||
import 'package:venera/foundation/appdata.dart';
|
||||
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||
import 'package:venera/foundation/favorites.dart';
|
||||
import 'package:venera/foundation/history.dart';
|
||||
import 'package:venera/foundation/log.dart';
|
||||
import 'package:venera/foundation/res.dart';
|
||||
import 'package:venera/network/app_dio.dart';
|
||||
import 'package:venera/utils/data.dart';
|
||||
import 'package:venera/utils/ext.dart';
|
||||
import 'package:webdav_client/webdav_client.dart' hide File;
|
||||
|
||||
import 'io.dart';
|
||||
|
||||
class DataSync with ChangeNotifier {
|
||||
DataSync._() {
|
||||
if (isEnabled) {
|
||||
downloadData();
|
||||
}
|
||||
HistoryManager().addListener(onDataChanged);
|
||||
LocalFavoritesManager().addListener(onDataChanged);
|
||||
ComicSource.addListener(onDataChanged);
|
||||
}
|
||||
|
||||
void onDataChanged() {
|
||||
if (isEnabled) {
|
||||
uploadData();
|
||||
}
|
||||
}
|
||||
|
||||
static DataSync? instance;
|
||||
|
||||
factory DataSync() => instance ?? (instance = DataSync._());
|
||||
|
||||
bool isDownloading = false;
|
||||
|
||||
bool isUploading = false;
|
||||
|
||||
bool haveWaitingTask = false;
|
||||
|
||||
bool get isEnabled {
|
||||
var config = appdata.settings['webdav'];
|
||||
return config is List && config.isNotEmpty;
|
||||
}
|
||||
|
||||
List<String>? _validateConfig() {
|
||||
var config = appdata.settings['webdav'];
|
||||
if (config is! List || (config.isNotEmpty && config.length != 3)) {
|
||||
return null;
|
||||
}
|
||||
if (config.whereType<String>().length != 3) {
|
||||
return null;
|
||||
}
|
||||
return List.from(config);
|
||||
}
|
||||
|
||||
Future<Res<bool>> uploadData() async {
|
||||
if (haveWaitingTask) return const Res(true);
|
||||
while (isDownloading || isUploading) {
|
||||
haveWaitingTask = true;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
haveWaitingTask = false;
|
||||
isUploading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
var config = _validateConfig();
|
||||
if (config == null) {
|
||||
return const Res.error('Invalid WebDAV configuration');
|
||||
}
|
||||
if (config.isEmpty) {
|
||||
return const Res(true);
|
||||
}
|
||||
String url = config[0];
|
||||
String user = config[1];
|
||||
String pass = config[2];
|
||||
|
||||
var proxy = await AppDio.getProxy();
|
||||
|
||||
var client = newClient(
|
||||
url,
|
||||
user: user,
|
||||
password: pass,
|
||||
adapter: IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
return HttpClient()
|
||||
..findProxy = (uri) => proxy == null ? "DIRECT" : "PROXY $proxy";
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await client.ping();
|
||||
} catch (e) {
|
||||
Log.error("Upload Data", 'Failed to connect to WebDAV server');
|
||||
return const Res.error('Failed to connect to WebDAV server');
|
||||
}
|
||||
|
||||
try {
|
||||
appdata.settings['dataVersion']++;
|
||||
await appdata.saveData();
|
||||
var data = await exportAppData();
|
||||
var time =
|
||||
(DateTime.now().millisecondsSinceEpoch ~/ 86400000).toString();
|
||||
var filename = time;
|
||||
filename += '-';
|
||||
filename += appdata.settings['dataVersion'].toString();
|
||||
filename += '.venera';
|
||||
var files = await client.readDir('/');
|
||||
files = files.where((e) => e.name!.endsWith('.venera')).toList();
|
||||
var old = files.firstWhereOrNull( (e) => e.name!.startsWith("$time-"));
|
||||
if (old != null) {
|
||||
await client.remove(old.name!);
|
||||
}
|
||||
if (files.length >= 10) {
|
||||
files.sort((a, b) => a.name!.compareTo(b.name!));
|
||||
await client.remove(files.first.name!);
|
||||
}
|
||||
await client.write(filename, await data.readAsBytes());
|
||||
Log.info("Upload Data", "Data uploaded successfully");
|
||||
return const Res(true);
|
||||
} catch (e, s) {
|
||||
Log.error("Upload Data", e, s);
|
||||
return Res.error(e.toString());
|
||||
}
|
||||
} finally {
|
||||
isUploading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Res<bool>> downloadData() async {
|
||||
if (haveWaitingTask) return const Res(true);
|
||||
while (isDownloading || isUploading) {
|
||||
haveWaitingTask = true;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
haveWaitingTask = false;
|
||||
isDownloading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
var config = _validateConfig();
|
||||
if (config == null) {
|
||||
return const Res.error('Invalid WebDAV configuration');
|
||||
}
|
||||
if (config.isEmpty) {
|
||||
return const Res(true);
|
||||
}
|
||||
String url = config[0];
|
||||
String user = config[1];
|
||||
String pass = config[2];
|
||||
|
||||
var proxy = await AppDio.getProxy();
|
||||
|
||||
var client = newClient(
|
||||
url,
|
||||
user: user,
|
||||
password: pass,
|
||||
adapter: IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
return HttpClient()
|
||||
..findProxy = (uri) => proxy == null ? "DIRECT" : "PROXY $proxy";
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
await client.ping();
|
||||
} catch (e) {
|
||||
Log.error("Data Sync", 'Failed to connect to WebDAV server');
|
||||
return const Res.error('Failed to connect to WebDAV server');
|
||||
}
|
||||
|
||||
try {
|
||||
var files = await client.readDir('/');
|
||||
files.sort((a, b) => b.name!.compareTo(a.name!));
|
||||
var file = files.firstWhereOrNull((e) => e.name!.endsWith('.venera'));
|
||||
var version =
|
||||
file!.name!.split('-').elementAtOrNull(1)?.split('.').first;
|
||||
if (version != null && int.tryParse(version) != null) {
|
||||
var currentVersion = appdata.settings['dataVersion'];
|
||||
if (currentVersion != null && int.parse(version) <= currentVersion) {
|
||||
Log.info("Data Sync", 'No new data to download');
|
||||
return const Res(true);
|
||||
}
|
||||
}
|
||||
Log.info("Data Sync", "Downloading data from WebDAV server");
|
||||
var localFile = File(FilePath.join(App.cachePath, file.name!));
|
||||
await client.read2File(file.name!, localFile.path);
|
||||
await importAppData(localFile, true);
|
||||
await localFile.delete();
|
||||
Log.info("Data Sync", "Data downloaded successfully");
|
||||
return const Res(true);
|
||||
} catch (e, s) {
|
||||
Log.error("Data Sync", e, s);
|
||||
return Res.error(e.toString());
|
||||
}
|
||||
} finally {
|
||||
isDownloading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user