Refactor geo assets

This commit is contained in:
problematicconsumer
2023-11-25 22:00:40 +03:30
parent 6040eae6ce
commit e2d9d5e53e
29 changed files with 594 additions and 507 deletions

View File

@@ -10,6 +10,7 @@ import 'package:hiddify/domain/constants.dart';
import 'package:hiddify/domain/core_facade.dart';
import 'package:hiddify/domain/core_service_failure.dart';
import 'package:hiddify/domain/singbox/singbox.dart';
import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
import 'package:hiddify/services/files_editor_service.dart';
import 'package:hiddify/services/platform_services.dart';
import 'package:hiddify/services/singbox/singbox_service.dart';
@@ -19,6 +20,7 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
CoreFacadeImpl(
this.singbox,
this.filesEditor,
this.geoAssetPathResolver,
this.platformServices,
this.clash,
this.debug,
@@ -27,6 +29,7 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
final SingboxService singbox;
final FilesEditorService filesEditor;
final GeoAssetPathResolver geoAssetPathResolver;
final PlatformServices platformServices;
final ClashApi clash;
final bool debug;
@@ -38,8 +41,8 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
return exceptionHandler(
() async {
final options = await configOptions();
final geoip = filesEditor.resolveGeoAssetPath(options.geoipPath);
final geosite = filesEditor.resolveGeoAssetPath(options.geositePath);
final geoip = geoAssetPathResolver.resolvePath(options.geoipPath);
final geosite = geoAssetPathResolver.resolvePath(options.geositePath);
if (!await File(geoip).exists() || !await File(geosite).exists()) {
return left(const CoreMissingGeoAssets());
}

View File

@@ -1,168 +0,0 @@
import 'dart:io';
import 'package:dartx/dartx_io.dart';
import 'package:dio/dio.dart';
import 'package:fpdart/fpdart.dart';
import 'package:hiddify/data/local/dao/dao.dart';
import 'package:hiddify/data/repository/exception_handlers.dart';
import 'package:hiddify/domain/rules/geo_asset.dart';
import 'package:hiddify/domain/rules/geo_asset_failure.dart';
import 'package:hiddify/domain/rules/geo_assets_repository.dart';
import 'package:hiddify/services/files_editor_service.dart';
import 'package:hiddify/utils/custom_loggers.dart';
import 'package:rxdart/rxdart.dart';
import 'package:watcher/watcher.dart';
class GeoAssetsRepositoryImpl
with ExceptionHandler, InfraLogger
implements GeoAssetsRepository {
GeoAssetsRepositoryImpl({
required this.geoAssetsDao,
required this.dio,
required this.filesEditor,
});
final GeoAssetsDao geoAssetsDao;
final Dio dio;
final FilesEditorService filesEditor;
@override
TaskEither<GeoAssetFailure, ({GeoAsset geoip, GeoAsset geosite})>
getActivePair() {
return exceptionHandler(
() async {
final geoip = await geoAssetsDao.getActive(GeoAssetType.geoip);
final geosite = await geoAssetsDao.getActive(GeoAssetType.geosite);
if (geoip == null || geosite == null) {
return left(const GeoAssetFailure.activeAssetNotFound());
}
return right((geoip: geoip, geosite: geosite));
},
GeoAssetFailure.unexpected,
);
}
@override
Stream<Either<GeoAssetFailure, List<GeoAssetWithFileSize>>> watchAll() {
final persistedStream = geoAssetsDao.watchAll();
final filesStream = _watchGeoFiles();
return Rx.combineLatest2(
persistedStream,
filesStream,
(assets, files) => assets.map(
(e) {
final path = filesEditor.geoAssetPath(e.providerName, e.fileName);
final file = files.firstOrNullWhere((e) => e.path == path);
final stat = file?.statSync();
return (e, stat?.size);
},
).toList(),
).handleExceptions(GeoAssetUnexpectedFailure.new);
}
Iterable<File> _geoFiles = [];
Stream<Iterable<File>> _watchGeoFiles() async* {
yield await _readGeoFiles();
yield* Watcher(
filesEditor.geoAssetsDir.path,
pollingDelay: const Duration(seconds: 1),
).events.asyncMap((event) async {
await _readGeoFiles();
return _geoFiles;
});
}
Future<Iterable<File>> _readGeoFiles() async {
return _geoFiles = Directory(filesEditor.geoAssetsDir.path)
.listSync()
.whereType<File>()
.where((e) => e.extension == '.db');
}
@override
TaskEither<GeoAssetFailure, Unit> update(GeoAsset geoAsset) {
return exceptionHandler(
() async {
loggy.debug(
"checking latest release of [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
);
final response = await dio.get<Map>(geoAsset.repositoryUrl);
if (response.statusCode != 200 || response.data == null) {
return left(
GeoAssetFailure.unexpected("invalid response", StackTrace.current),
);
}
final path =
filesEditor.geoAssetPath(geoAsset.providerName, geoAsset.name);
final tagName = response.data!['tag_name'] as String;
loggy.debug("latest release of [${geoAsset.name}]: [$tagName]");
if (tagName == geoAsset.version && await File(path).exists()) {
await geoAssetsDao.edit(geoAsset.copyWith(lastCheck: DateTime.now()));
return left(const GeoAssetFailure.noUpdateAvailable());
}
final assets = (response.data!['assets'] as List)
.whereType<Map<String, dynamic>>();
final asset =
assets.firstOrNullWhere((e) => e["name"] == geoAsset.name);
if (asset == null) {
return left(
GeoAssetFailure.unexpected(
"couldn't find [${geoAsset.name}] on [${geoAsset.repositoryUrl}]",
StackTrace.current,
),
);
}
final downloadUrl = asset["browser_download_url"] as String;
loggy.debug("[${geoAsset.name}] download url: [$downloadUrl]");
final tempPath = "$path.tmp";
await File(path).parent.create(recursive: true);
await dio.download(downloadUrl, tempPath);
await File(tempPath).rename(path);
await geoAssetsDao.edit(
geoAsset.copyWith(
version: tagName,
lastCheck: DateTime.now(),
),
);
return right(unit);
},
GeoAssetFailure.unexpected,
);
}
@override
TaskEither<GeoAssetFailure, Unit> markAsActive(GeoAsset geoAsset) {
return exceptionHandler(
() async {
await geoAssetsDao.edit(geoAsset.copyWith(active: true));
return right(unit);
},
GeoAssetFailure.unexpected,
);
}
@override
TaskEither<GeoAssetFailure, Unit> addRecommended() {
return exceptionHandler(
() async {
final persistedIds = await geoAssetsDao
.watchAll()
.first
.then((value) => value.map((e) => e.id));
final missing =
recommendedGeoAssets.where((e) => !persistedIds.contains(e.id));
for (final geoAsset in missing) {
await geoAssetsDao.add(geoAsset);
}
return right(unit);
},
GeoAssetFailure.unexpected,
);
}
}

View File

@@ -2,7 +2,7 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:fpdart/fpdart.dart';
import 'package:hiddify/data/local/dao/dao.dart';
import 'package:hiddify/data/local/dao/profiles_dao.dart';
import 'package:hiddify/data/repository/exception_handlers.dart';
import 'package:hiddify/domain/enums.dart';
import 'package:hiddify/domain/profiles/profiles.dart';