Files
umbrix/lib/features/profile/notifier/profiles_update_notifier.dart

128 lines
3.9 KiB
Dart
Raw Normal View History

2023-11-26 21:20:58 +03:30
import 'package:dartx/dartx.dart';
2024-01-03 22:30:49 +03:30
import 'package:hiddify/core/preferences/general_preferences.dart';
2023-12-01 12:56:24 +03:30
import 'package:hiddify/core/preferences/preferences_provider.dart';
2023-11-26 21:20:58 +03:30
import 'package:hiddify/features/profile/data/profile_data_providers.dart';
import 'package:hiddify/features/profile/model/profile_entity.dart';
import 'package:hiddify/utils/custom_loggers.dart';
import 'package:meta/meta.dart';
import 'package:neat_periodic_task/neat_periodic_task.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'profiles_update_notifier.g.dart';
2024-01-04 10:56:26 +03:30
typedef ProfileUpdateStatus = ({String name, bool success});
2023-11-26 21:20:58 +03:30
@Riverpod(keepAlive: true)
class ForegroundProfilesUpdateNotifier
extends _$ForegroundProfilesUpdateNotifier with AppLogger {
static const prefKey = "profiles_update_check";
static const interval = Duration(minutes: 15);
@override
2024-01-04 10:56:26 +03:30
Stream<ProfileUpdateStatus?> build() {
2023-11-26 21:20:58 +03:30
var cycleCount = 0;
2024-01-04 10:56:26 +03:30
_scheduler = NeatPeriodicTaskScheduler(
2023-11-26 21:20:58 +03:30
name: 'profiles update worker',
interval: interval,
timeout: const Duration(minutes: 5),
task: () async {
loggy.debug("cycle [${cycleCount++}]");
await updateProfiles();
},
);
ref.onDispose(() async {
2024-01-04 10:56:26 +03:30
await _scheduler?.stop();
_scheduler = null;
2023-11-26 21:20:58 +03:30
});
2024-03-02 22:53:14 +03:30
if (ref.watch(Preferences.introCompleted)) {
2024-01-03 22:30:49 +03:30
loggy.debug("intro done, starting");
2024-01-04 10:56:26 +03:30
_scheduler?.start();
2024-01-03 22:30:49 +03:30
} else {
loggy.debug("intro in process, skipping");
}
2024-01-04 10:56:26 +03:30
return const Stream.empty();
}
NeatPeriodicTaskScheduler? _scheduler;
bool _forceNextRun = false;
Future<void> trigger() async {
loggy.debug("triggering update");
_forceNextRun = true;
await _scheduler?.trigger();
2023-11-26 21:20:58 +03:30
}
@visibleForTesting
Future<void> updateProfiles() async {
2024-01-04 10:56:26 +03:30
var force = false;
if (_forceNextRun) {
force = true;
_forceNextRun = false;
}
2023-11-26 21:20:58 +03:30
try {
final previousRun = DateTime.tryParse(
2023-12-01 12:56:24 +03:30
ref.read(sharedPreferencesProvider).requireValue.getString(prefKey) ??
"",
2023-11-26 21:20:58 +03:30
);
2024-01-04 10:56:26 +03:30
if (!force &&
previousRun != null &&
previousRun.add(interval) > DateTime.now()) {
2023-11-26 21:20:58 +03:30
loggy.debug("too soon! previous run: [$previousRun]");
return;
}
2024-01-04 10:56:26 +03:30
loggy.debug(
"${force ? "[FORCED] " : ""}running, previous run: [$previousRun]",
);
2023-11-26 21:20:58 +03:30
final remoteProfiles = await ref
.read(profileRepositoryProvider)
.requireValue
.watchAll()
.map(
(event) => event.getOrElse((f) {
loggy.error("error getting profiles");
throw f;
}).whereType<RemoteProfileEntity>(),
)
.first;
await for (final profile in Stream.fromIterable(remoteProfiles)) {
final updateInterval = profile.options?.updateInterval;
2024-01-04 10:56:26 +03:30
if (force ||
updateInterval != null &&
updateInterval <=
DateTime.now().difference(profile.lastUpdate)) {
2023-11-26 21:20:58 +03:30
await ref
.read(profileRepositoryProvider)
.requireValue
.updateSubscription(profile)
.mapLeft(
2024-01-04 10:56:26 +03:30
(l) {
loggy.debug("error updating profile [${profile.id}]", l);
state = AsyncData((name: profile.name, success: false));
},
).map(
(_) {
loggy.debug("profile [${profile.id}] updated successfully");
state = AsyncData((name: profile.name, success: true));
},
).run();
2023-11-26 21:20:58 +03:30
} else {
loggy.debug(
"skipping profile [${profile.id}] update. last successful update: [${profile.lastUpdate}] - interval: [${profile.options?.updateInterval}]",
);
}
}
} finally {
await ref
.read(sharedPreferencesProvider)
2023-12-01 12:56:24 +03:30
.requireValue
2023-11-26 21:20:58 +03:30
.setString(prefKey, DateTime.now().toIso8601String());
}
}
}