feature(updater): Implement auto-updating system using AppCast protocol
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:auto_updater/auto_updater.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:moonwell_launcher/config.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/data/launcher_log_service.dart';
|
||||
|
||||
abstract interface class LauncherUpdateClient {
|
||||
Future<void> setFeedUrl(String feedUrl);
|
||||
|
||||
Future<void> disableScheduledChecks();
|
||||
|
||||
Future<void> checkInBackground();
|
||||
}
|
||||
|
||||
final class AutoUpdaterLauncherUpdateClient implements LauncherUpdateClient {
|
||||
@override
|
||||
Future<void> setFeedUrl(String feedUrl) => autoUpdater.setFeedURL(feedUrl);
|
||||
|
||||
@override
|
||||
Future<void> disableScheduledChecks() =>
|
||||
autoUpdater.setScheduledCheckInterval(0);
|
||||
|
||||
@override
|
||||
Future<void> checkInBackground() =>
|
||||
autoUpdater.checkForUpdates(inBackground: true);
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class LauncherUpdateService {
|
||||
LauncherUpdateService(LauncherLogService launcherLogService)
|
||||
: this.forTesting(
|
||||
launcherLogService: launcherLogService,
|
||||
updateClient: AutoUpdaterLauncherUpdateClient(),
|
||||
isWindows: Platform.isWindows,
|
||||
);
|
||||
|
||||
LauncherUpdateService.forTesting({
|
||||
required LauncherLogService launcherLogService,
|
||||
required LauncherUpdateClient updateClient,
|
||||
required bool isWindows,
|
||||
}) : _launcherLogService = launcherLogService,
|
||||
_updateClient = updateClient,
|
||||
_isWindows = isWindows;
|
||||
|
||||
final LauncherLogService _launcherLogService;
|
||||
final LauncherUpdateClient _updateClient;
|
||||
final bool _isWindows;
|
||||
|
||||
bool _hasChecked = false;
|
||||
|
||||
Future<void> checkForUpdates({
|
||||
String feedUrl = Config.launcherAppcastUrl,
|
||||
}) async {
|
||||
if (!_isWindows || _hasChecked) {
|
||||
return;
|
||||
}
|
||||
|
||||
final normalizedFeedUrl = feedUrl.trim();
|
||||
if (normalizedFeedUrl.isEmpty) {
|
||||
await _launcherLogService.info(
|
||||
'Launcher self-update is disabled because no AppCast URL is configured.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final uri = Uri.tryParse(normalizedFeedUrl);
|
||||
if (uri == null ||
|
||||
!uri.isAbsolute ||
|
||||
uri.scheme != 'https' ||
|
||||
!uri.hasAuthority ||
|
||||
uri.host.isEmpty) {
|
||||
await _launcherLogService.error(
|
||||
'Launcher self-update AppCast URL is invalid.',
|
||||
details: <String, Object?>{'feedUrl': normalizedFeedUrl},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_hasChecked = true;
|
||||
|
||||
try {
|
||||
await _updateClient.setFeedUrl(normalizedFeedUrl);
|
||||
await _updateClient.disableScheduledChecks();
|
||||
await _updateClient.checkInBackground();
|
||||
await _launcherLogService.info(
|
||||
'Launcher self-update check started.',
|
||||
details: <String, Object?>{'feedUrl': normalizedFeedUrl},
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
await _launcherLogService.error(
|
||||
'Launcher self-update check failed.',
|
||||
details: <String, Object?>{'feedUrl': normalizedFeedUrl},
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user