import 'dart:async'; import 'dart:io'; import 'package:logging/logging.dart'; import 'package:moonwell_launcher/features/downloader/application/download_manager.dart'; import 'package:moonwell_launcher/features/downloader/domain/entities/download_request.dart'; import 'package:moonwell_launcher/service_container.dart'; final _log = Logger('Downloader'); Future main(List arguments) async { await configureDependencies(); _setupLogging(); final manager = getIt(); // Start the download and keep a handle to the subscription final stream = manager.start( id: 'client', request: DownloadRequest( destinationPath: '/Users/kalistratovm/Games/MoonWell/client.zip', ), ); final done = Completer(); // exit code completer late StreamSubscription sub; // Graceful shutdown on Ctrl-C / SIGTERM final sigintSub = ProcessSignal.sigint.watch(); sigintSub.listen((_) async { _log.warning('SIGINT received. Cancelling all downloads…'); await manager.cancelAll(); await sub.cancel(); if (!done.isCompleted) { done.complete(130); // 130 = terminated by Ctrl-C } }); final sigtermSub = ProcessSignal.sigterm.watch().listen((_) async { _log.warning('SIGTERM received. Cancelling all downloads…'); await manager.cancelAll(); await sub.cancel(); done.complete(143); // 143 = terminated by SIGTERM }); sub = stream.listen( (p) { _log.info('Speed: ${p.speed}'); _log.info('ETA: ${p.eta}'); _log.info('Done: ${p.downloaded}/${p.total}'); }, onError: (e, st) async { _log.severe('Download error', e, st); await sigtermSub.cancel(); done.complete(1); }, onDone: () async { _log.info('Download completed'); await sigtermSub.cancel(); done.complete(0); }, cancelOnError: true, ); // ⬇️ Keep process alive until one of the completions above fires final code = await done.future; exit(code); } void _setupLogging() { Logger.root.level = Level.INFO; Logger.root.onRecord.listen((rec) { final color = switch (rec.level) { Level.SEVERE || Level.SHOUT => '\x1B[31m', Level.WARNING => '\x1B[33m', Level.INFO => '\x1B[36m', _ => '\x1B[90m', }; stdout.writeln( '$color[${rec.time.toIso8601String()}] ' '${rec.level.name.padRight(7)} ' '${rec.loggerName}: ${rec.message}\x1B[0m', ); if (rec.error != null) stdout.writeln(' Error: ${rec.error}'); if (rec.stackTrace != null) stdout.writeln(' Stack: ${rec.stackTrace}'); }); }