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 setFeedUrl(String feedUrl); Future disableScheduledChecks(); Future checkInBackground(); } final class AutoUpdaterLauncherUpdateClient implements LauncherUpdateClient { @override Future setFeedUrl(String feedUrl) => autoUpdater.setFeedURL(feedUrl); @override Future disableScheduledChecks() => autoUpdater.setScheduledCheckInterval(0); @override Future 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 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: {'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: {'feedUrl': normalizedFeedUrl}, ); } catch (error, stackTrace) { await _launcherLogService.error( 'Launcher self-update check failed.', details: {'feedUrl': normalizedFeedUrl}, error: error, stackTrace: stackTrace, ); } } }