Add scheduled profile update

This commit is contained in:
problematicconsumer
2023-09-30 11:15:20 +03:30
parent b60b22d694
commit eb4db44c06
7 changed files with 105 additions and 5 deletions

View File

@@ -147,7 +147,6 @@ Future<void> initAppServices(
await Future.wait(
[
read(singboxServiceProvider).init(),
read(cronServiceProvider).startScheduler(),
],
);
_logger.debug('initialized app services');

View File

@@ -37,6 +37,17 @@ class AppView extends HookConsumerWidget with PresLogger {
theme: theme.light(),
darkTheme: theme.dark(),
title: Constants.appName,
// https://github.com/ponnamkarthik/FlutterToast/issues/393
builder: (context, child) => Overlay(
initialEntries: [
if (child != null) ...[
OverlayEntry(
builder: (context) => child,
),
],
],
),
);
}
}

View File

@@ -66,11 +66,11 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
).run();
}
void _schedule() {
Future<void> _schedule() async {
loggy.debug("scheduling app update checker");
ref.watch(cronServiceProvider).schedule(
return ref.read(cronServiceProvider).schedule(
key: 'app_update',
duration: const Duration(hours: 4),
duration: const Duration(hours: 8),
callback: () async {
await Future.delayed(const Duration(seconds: 5));
final updateState = await check();

View File

@@ -1,8 +1,11 @@
import 'package:hiddify/core/prefs/general_prefs.dart';
import 'package:hiddify/features/common/app_update_notifier.dart';
import 'package:hiddify/features/common/connectivity/connectivity_controller.dart';
import 'package:hiddify/features/common/window/window_controller.dart';
import 'package:hiddify/features/logs/notifier/notifier.dart';
import 'package:hiddify/features/profiles/notifier/notifier.dart';
import 'package:hiddify/features/system_tray/controller/system_tray_controller.dart';
import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/utils/platform_utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -12,6 +15,15 @@ part 'common_controllers.g.dart';
// https://github.com/rrousselGit/riverpod/discussions/2730
@Riverpod(keepAlive: true)
void commonControllers(CommonControllersRef ref) {
ref.listen(
introCompletedProvider,
(_, completed) async {
if (completed) {
await ref.read(cronServiceProvider).startScheduler();
}
},
fireImmediately: true,
);
ref.listen(
logsNotifierProvider,
(previous, next) {},
@@ -26,6 +38,11 @@ void commonControllers(CommonControllersRef ref) {
(previous, next) {},
fireImmediately: true,
);
ref.listen(
profilesUpdateNotifierProvider,
(previous, next) {},
fireImmediately: true,
);
if (PlatformUtils.isDesktop) {
ref.listen(
windowControllerProvider,

View File

@@ -1 +1,2 @@
export 'profiles_notifier.dart';
export 'profiles_update_notifier.dart';

View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:fpdart/fpdart.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/router/router.dart';
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/domain/failures.dart';
import 'package:hiddify/domain/profiles/profiles.dart';
import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'profiles_update_notifier.g.dart';
typedef ProfileUpdateResult = ({
String name,
Either<ProfileFailure, Unit> failureOrSuccess
});
@Riverpod(keepAlive: true)
class ProfilesUpdateNotifier extends _$ProfilesUpdateNotifier with AppLogger {
@override
Stream<ProfileUpdateResult> build() {
ref.listenSelf(
(previous, next) {
if (next case AsyncData(value: final result)) {
final t = ref.read(translationsProvider);
final context = rootNavigatorKey.currentContext;
if (context == null || !context.mounted) return;
SnackBar(content: Text(t.profile.update.successMsg));
switch (result.failureOrSuccess) {
case Right():
CustomToast.success(t.profile.update.successMsg).show(context);
case Left(value: final err):
CustomToast.error(t.printError(err)).show(context);
}
}
},
);
_schedule();
return const Stream.empty();
}
Future<void> _schedule() async {
loggy.debug("scheduling profiles update worker");
return ref.read(cronServiceProvider).schedule(
key: 'profiles_update',
duration: const Duration(minutes: 10),
callback: () async {
final failureOrProfiles =
await ref.read(profilesRepositoryProvider).watchAll().first;
if (failureOrProfiles case Right(value: final profiles)) {
for (final profile in profiles) {
loggy.debug("checking profile: [${profile.name}]");
final updateInterval = profile.options?.updateInterval;
if (updateInterval != null &&
updateInterval <=
DateTime.now().difference(profile.lastUpdate)) {
final failureOrSuccess = await ref
.read(profilesRepositoryProvider)
.update(profile)
.run();
state = AsyncData(
(name: profile.name, failureOrSuccess: failureOrSuccess),
);
} else {
loggy.debug("skipping profile: [${profile.name}]");
}
}
}
},
);
}
}

View File

@@ -28,7 +28,6 @@ class CronService with InfraLogger {
}) {
loggy.debug("scheduling [$key]");
jobs[key] = (key, duration, callback);
_scheduler?.trigger();
}
Future<void> run(Job job) async {