From bc23fb414f683cbed0008a213766db2a6416fa61 Mon Sep 17 00:00:00 2001 From: Anton Terentev <111225722+GamerVII-NET@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:56:58 +0300 Subject: [PATCH] Update to v0.1.0-rc2 (#53) * Add LogHandler service for improved log processing Introduced a new LogHandler class to manage and process log data more effectively. Integrated LogHandler into OverviewPageViewModel and ServiceLocator for better error handling and logging capabilities. * Add detailed installation instructions to README.md This update includes prerequisites, step-by-step installation commands, troubleshooting tips, updating instructions, and uninstallation steps for the GamerVII Launcher. These additions aim to provide clear, comprehensive guidance for users to correctly install, update, and uninstall the launcher. * Add README.md to Gml.Client project in solution This commit updates the solution file to include the README.md for the Gml.Client project. The addition helps in documenting the project directly within the solution, providing better context and guidance for developers. * Update submodule link Gml.Client * Prevent further processing of error data Added a return statement at the beginning of the HandleErrorData method to immediately exit the function. This ensures that no additional code is executed within this method when it is called. --------- Co-authored-by: GamerVII-NET --- Gml.Launcher.sln | 1 + README.md | 66 ++++++++++++++++ src/Gml.Client | 2 +- .../ResourceKeysDictionary.Template.cs | 1 + .../Resources/ResourceKeysDictionary.cs | 1 + .../Assets/Resources/Resources.Designer.cs | 8 ++ .../Assets/Resources/Resources.en.resx | 3 + .../Assets/Resources/Resources.resx | 3 + .../Assets/Resources/Resources.ru.resx | 3 + .../Core/Converters/AsyncSkinRenderLoader.cs | 6 +- .../Core/Extensions/ServiceLocator.cs | 25 +----- src/Gml.Launcher/Core/Services/LogHandler.cs | 76 +++++++++++++++++++ src/Gml.Launcher/Program.cs | 34 ++++++++- .../ViewModels/Base/PageViewModelBase.cs | 6 +- .../ViewModels/Pages/LoginPageViewModel.cs | 17 +---- .../ViewModels/Pages/OverviewPageViewModel.cs | 46 +++++++---- .../ViewModels/SplashScreenViewModel.cs | 56 ++++++++++---- .../Views/Pages/SettingsPageView.axaml.cs | 6 +- .../Views/SplashScreen/SplashScreen.axaml.cs | 25 +++++- 19 files changed, 307 insertions(+), 78 deletions(-) create mode 100644 src/Gml.Launcher/Core/Services/LogHandler.cs diff --git a/Gml.Launcher.sln b/Gml.Launcher.sln index d85bee9..ef47c58 100644 --- a/Gml.Launcher.sln +++ b/Gml.Launcher.sln @@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{09A802 load-repositories.bat = load-repositories.bat load-repositories.sh = load-repositories.sh .github\workflows\dotnet.yml = .github\workflows\dotnet.yml + src\Gml.Client\README.md = src\Gml.Client\README.md EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gml.Launcher", "src\Gml.Launcher\Gml.Launcher.csproj", "{F2771E71-C782-4713-862F-217694DDDFF5}" diff --git a/README.md b/README.md index 8729e6f..9f8a3fc 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,69 @@ GamerVII Launcher ======= The Minecraft Launcher is a user-friendly application designed to streamline the process of launching Minecraft and managing game settings. It provides an intuitive interface and essential features to enhance the Minecraft gaming experience. + +## Installation + +### Prerequisites + +Before installing the GamerVII Launcher, ensure you have the following prerequisites: + +- **.NET 8.0 SDK:** You need to have .NET 8.0 SDK installed on your system. You can download it + from [Microsoft's official website](https://dotnet.microsoft.com/download/dotnet/8.0) or use a package manager + suitable for your operating system. + +- **Git:** Ensure Git is installed on your system. You can download it from + the [Git website](https://git-scm.com/downloads) or use a package manager. + +### Steps to Install GamerVII Launcher + +1. **Clone the Repository:** + Open a terminal and clone the repository using Git with the `--recursive` option: + ```bash + git clone --recursive https://github.com/GamerVII-NET/minecraft-launcher.git + cd minecraft-launcher + ``` + +2. **Build the Project:** + Restore the dependencies and build the project using the .NET CLI: + ```bash + dotnet restore + dotnet build + ``` + +3. **Run the Launcher:** + Once the project is built, you can run the launcher using the following command: + ```bash + dotnet run --project path/to/your/project + ``` + +### Troubleshooting + +If you encounter any issues during the installation, ensure the following: + +- Ensure the .NET SDK is correctly installed and the `DOTNET_HOME` environment variable is set. +- Ensure Git is correctly installed and available in the terminal. +- Make sure you have the necessary permissions to run the build and execute the application. + +For additional help, check the project's issue tracker or community forums. + +### Updating + +To update the GamerVII Launcher to the latest version, navigate to the project directory and pull the latest changes +from the repository: + +```bash +git pull origin main +git submodule update --recursive --remote +dotnet build +``` + +Then, run the launcher again using the command mentioned earlier. + +### Uninstallation + +To uninstall the GamerVII Launcher, simply delete the project directory: + +```bash +rm -rf minecraft-launcher +``` diff --git a/src/Gml.Client b/src/Gml.Client index 23e0443..faec62c 160000 --- a/src/Gml.Client +++ b/src/Gml.Client @@ -1 +1 @@ -Subproject commit 23e04439a5770dac99457b3ce1197737bf59a92b +Subproject commit faec62c0c40f89a4f2fe35c4b30d59f5468ef82b diff --git a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs index a81d364..ba02922 100644 --- a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs +++ b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.Template.cs @@ -19,6 +19,7 @@ public static class ResourceKeysDictionary public const string ProfileNotConfigured = "ProfileNotConfigured"; public const string UpdatingDescription = "UpdatingDescription"; public const string InvalidAuthData = "InvalidAuthData"; + public const string InvalidSession = "InvalidSession"; public const string Reconnecting = "Reconnecting"; public const string LostConnection = "LostConnection"; public const string CheckUpdates = "CheckUpdates"; diff --git a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs index b641583..70a79eb 100644 --- a/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs +++ b/src/Gml.Launcher/Assets/Resources/ResourceKeysDictionary.cs @@ -19,6 +19,7 @@ public static class ResourceKeysDictionary public const string ProfileNotConfigured = "ProfileNotConfigured"; public const string UpdatingDescription = "UpdatingDescription"; public const string InvalidAuthData = "InvalidAuthData"; + public const string InvalidSession = "InvalidSession"; public const string Reconnecting = "Reconnecting"; public const string LostConnection = "LostConnection"; public const string CheckUpdates = "CheckUpdates"; diff --git a/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs b/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs index 916933e..889d28b 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs +++ b/src/Gml.Launcher/Assets/Resources/Resources.Designer.cs @@ -274,5 +274,13 @@ public static string GameProfileError { return ResourceManager.GetString("GameProfileError", resourceCulture); } } + /// + /// Ищет локализованную строку, похожую на ProfileNotConfigured. + /// + public static string InvalidSession { + get { + return ResourceManager.GetString("InvalidSession", resourceCulture); + } + } } } diff --git a/src/Gml.Launcher/Assets/Resources/Resources.en.resx b/src/Gml.Launcher/Assets/Resources/Resources.en.resx index ba38ddd..dbea516 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.en.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.en.resx @@ -141,4 +141,7 @@ Error initializing the game profile. + + Your game session in the launcher has expired, please log in again. + diff --git a/src/Gml.Launcher/Assets/Resources/Resources.resx b/src/Gml.Launcher/Assets/Resources/Resources.resx index 52adde4..d46adb8 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.resx @@ -149,4 +149,7 @@ Error initializing the game profile. + + Your game session in the launcher has expired, please log in again. + diff --git a/src/Gml.Launcher/Assets/Resources/Resources.ru.resx b/src/Gml.Launcher/Assets/Resources/Resources.ru.resx index 0be8cae..5f16720 100644 --- a/src/Gml.Launcher/Assets/Resources/Resources.ru.resx +++ b/src/Gml.Launcher/Assets/Resources/Resources.ru.resx @@ -141,4 +141,7 @@ Ошибка инициализации игрового профиля. + + Ваша игровая сессия в лаунчере истекла, авторизуйтесь заново + diff --git a/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs b/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs index 107c8c9..1e52d29 100644 --- a/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs +++ b/src/Gml.Launcher/Core/Converters/AsyncSkinRenderLoader.cs @@ -9,6 +9,7 @@ using Avalonia.Media.Imaging; using Gml.Client; using Gml.Launcher.Core.Services; +using Sentry; namespace Gml.Launcher.Core.Converters; @@ -63,9 +64,10 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE if (!cts.Token.IsCancellationRequested) sender.Source = bitmap; } - catch (Exception e) + catch (Exception exception) { - Console.WriteLine(e); + Console.WriteLine(exception); + SentrySdk.CaptureException(exception); } finally { diff --git a/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs b/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs index ed9b035..ddec67e 100644 --- a/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs +++ b/src/Gml.Launcher/Core/Extensions/ServiceLocator.cs @@ -24,12 +24,12 @@ public static AppBuilder RegisterServices(this AppBuilder builder) RegisterLocalizationService(); RegisterSystemService(systemService); + RegisterLogHelper(systemService); var manager = RegisterGmlManager(systemService, installationDirectory); var storageService = RegisterStorage(); CheckAndChangeInstallationFolder(storageService, manager); CheckAndChangeLanguage(storageService, systemService); - InitializeSentry(); AppDomain.CurrentDomain.UnhandledException += (_, args) => { @@ -39,28 +39,9 @@ public static AppBuilder RegisterServices(this AppBuilder builder) return builder; } - private static void InitializeSentry() + private static void RegisterLogHelper(SystemService systemService) { - var sentryUrl = GmlClientManager.GetSentryLink(ResourceKeysDictionary.Host).Result; - - try - { - if (!string.IsNullOrEmpty(sentryUrl)) - SentrySdk.Init(options => - { - options.Dsn = sentryUrl; - options.Debug = true; - options.TracesSampleRate = 1.0; - options.DiagnosticLevel = SentryLevel.Debug; - options.IsGlobalModeEnabled = true; - options.SendDefaultPii = true; - options.MaxAttachmentSize = 10 * 1024 * 1024; - }); - } - catch (Exception exception) - { - Console.WriteLine(exception); - } + Locator.CurrentMutable.RegisterConstant(new LogHandler()); } private static void CheckAndChangeLanguage(LocalStorageService storageService, SystemService systemService) diff --git a/src/Gml.Launcher/Core/Services/LogHandler.cs b/src/Gml.Launcher/Core/Services/LogHandler.cs new file mode 100644 index 0000000..f7ac7e4 --- /dev/null +++ b/src/Gml.Launcher/Core/Services/LogHandler.cs @@ -0,0 +1,76 @@ +using System; +using System.Diagnostics; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text.RegularExpressions; +using Sentry; + +namespace Gml.Launcher.Core.Services; + +public class LogHandler +{ + private readonly Subject _errorDataSubject = new(); + + + public LogHandler() + { + var errorDataObservable = _errorDataSubject + .Where(data => !string.IsNullOrEmpty(data)) + .Buffer(() => _errorDataSubject.Where(data => data.Contains(""))) + .Select(lines => string.Join(Environment.NewLine, lines)); + + errorDataObservable.Subscribe(HandleErrorData); + } + + private void HandleErrorData(string data) + { + return; + Debug.WriteLine(data); + + if (data.Contains("Exception", StringComparison.OrdinalIgnoreCase) || + data.Contains("", StringComparison.OrdinalIgnoreCase)) + { + var exception = ExtractException(data); + ShowError(ResourceKeysDictionary.GameProfileError, data); + SentrySdk.CaptureException(exception); + } + + if (data.Contains("[gml-patch]", StringComparison.OrdinalIgnoreCase)) + { + } + else + { + ShowError(ResourceKeysDictionary.GameProfileError, data); + SentrySdk.CaptureException(new Exception(data)); + } + } + + private Exception ExtractException(string data) + { + var throwableRegex = new Regex(@"", RegexOptions.Singleline); + var match = throwableRegex.Match(data); + + if (match.Success) + { + var stackTrace = match.Groups[1].Value; + return new Exception(stackTrace); + } + + return new Exception(data); + } + + private void ShowError(string key, string message) + { + // Реализуйте здесь показ ошибок пользователю + } + + private static class ResourceKeysDictionary + { + public static string GameProfileError = "GameProfileError"; + } + + public void ProcessLogs(string data) + { + _errorDataSubject.OnNext(data); + } +} diff --git a/src/Gml.Launcher/Program.cs b/src/Gml.Launcher/Program.cs index ff89e66..1dd0586 100644 --- a/src/Gml.Launcher/Program.cs +++ b/src/Gml.Launcher/Program.cs @@ -2,6 +2,8 @@ using System.Reactive; using Avalonia; using Avalonia.ReactiveUI; +using Gml.Client; +using Gml.Launcher.Assets; using Gml.Launcher.Core.Extensions; using ReactiveUI; using Sentry; @@ -15,13 +17,15 @@ public static void Main(string[] args) { try { + InitializeSentry(); RxApp.DefaultExceptionHandler = Observer.Create(GlobalExceptionHandler); BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); } - catch (Exception e) + catch (Exception exception) { - Console.WriteLine(e); + SentrySdk.CaptureException(exception); + Console.WriteLine(exception); } } @@ -39,4 +43,30 @@ public static AppBuilder BuildAvaloniaApp() .LogToTrace() .UseReactiveUI(); } + + + + private static void InitializeSentry() + { + var sentryUrl = GmlClientManager.GetSentryLink(ResourceKeysDictionary.Host).Result; + + try + { + if (!string.IsNullOrEmpty(sentryUrl)) + SentrySdk.Init(options => + { + options.Dsn = sentryUrl; + options.Debug = true; + options.TracesSampleRate = 1.0; + options.DiagnosticLevel = SentryLevel.Debug; + options.IsGlobalModeEnabled = true; + options.SendDefaultPii = true; + options.MaxAttachmentSize = 10 * 1024 * 1024; + }); + } + catch (Exception exception) + { + Console.WriteLine(exception); + } + } } diff --git a/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs b/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs index 11d19be..20dd324 100644 --- a/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs +++ b/src/Gml.Launcher/ViewModels/Base/PageViewModelBase.cs @@ -9,6 +9,7 @@ using Gml.Launcher.Core.Exceptions; using Gml.Launcher.Core.Services; using ReactiveUI; +using Sentry; using Splat; namespace Gml.Launcher.ViewModels.Base; @@ -71,9 +72,10 @@ async void RunThreadTask() await func(); tcs.SetResult(null); } - catch (Exception ex) + catch (Exception exception) { - tcs.SetException(ex); + tcs.SetException(exception); + SentrySdk.CaptureException(exception); } } diff --git a/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs index 740f2d1..efaf441 100644 --- a/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/LoginPageViewModel.cs @@ -13,6 +13,7 @@ using Gml.Launcher.Core.Services; using Gml.Launcher.ViewModels.Base; using ReactiveUI; +using Sentry; using Splat; namespace Gml.Launcher.ViewModels.Pages; @@ -101,7 +102,7 @@ private async void CheckAuth() { var authUser = await _storageService.GetAsync(StorageConstants.User); - if (authUser is { IsAuth: true }) + if (authUser is { IsAuth: true } && authUser.ExpiredDate > DateTime.Now) { _screen.Router.Navigate.Execute(new OverviewPageViewModel(_screen, authUser, _onClosed)); await _gmlClientManager.OpenServerConnection(authUser); @@ -112,16 +113,6 @@ private async Task OnAuth(CancellationToken arg) { try { - // this.Manager - // .CreateMessage() - // .Accent("#1751C3") - // .Animates(true) - // .Background("#333") - // .HasBadge("Info") - // .HasMessage("Update will be installed on next application restart. This message will be dismissed after 5 seconds.") - // .Dismiss().WithDelay(TimeSpan.FromSeconds(5)) - // .Queue(); - //28823c6e1c503fa9b051fec15e9c5986 IsProcessing = true; var authInfo = await _gmlClientManager.Auth(Login, Password, _systemService.GetHwid()); @@ -151,9 +142,9 @@ private async Task OnAuth(CancellationToken arg) Errors = new ObservableCollection(authInfo.Details); } } - catch (Exception e) + catch (Exception exception) { - Console.WriteLine(e); + SentrySdk.CaptureException(exception); } finally { diff --git a/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs b/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs index eda94d8..e8f3407 100644 --- a/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs +++ b/src/Gml.Launcher/ViewModels/Pages/OverviewPageViewModel.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; @@ -15,6 +17,7 @@ using Avalonia.Threading; using GamerVII.Notification.Avalonia; using Gml.Client; +using Gml.Client.Helpers; using Gml.Client.Models; using Gml.Launcher.Assets; using Gml.Launcher.Core.Exceptions; @@ -26,6 +29,7 @@ using Gml.Web.Api.Dto.Profile; using ReactiveUI; using ReactiveUI.Fody.Helpers; +using Sentry; using Splat; namespace Gml.Launcher.ViewModels.Pages; @@ -38,6 +42,7 @@ public class OverviewPageViewModel : PageViewModelBase private readonly MainWindowViewModel _mainViewModel; private readonly IDisposable? _maxCountLoaded; private readonly IObservable _onClosed; + private readonly LogHandler _logHandler; private readonly IDisposable _profileNameChanged; private readonly IStorageService _storageService; private readonly ISystemService _systemService; @@ -48,11 +53,17 @@ internal OverviewPageViewModel(IScreen screen, IObservable onClosed, IGmlClientManager? gmlManager = null, ISystemService? systemService = null, - IStorageService? storageService = null) : base(screen) + IStorageService? storageService = null, + LogHandler? logHandler = null) : base(screen) { _mainViewModel = screen as MainWindowViewModel ?? throw new Exception("Not valid screen"); User = user; _onClosed = onClosed; + + _logHandler = logHandler + ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(LogHandler)); + _systemService = systemService ?? Locator.Current.GetService() ?? throw new ServiceNotFoundException(typeof(ISystemService)); @@ -154,6 +165,7 @@ await ExecuteFromNewThread(async () => { try { + var profileInfo = await GetProfileInfo(); if (profileInfo is { Data: not null }) @@ -161,6 +173,7 @@ await ExecuteFromNewThread(async () => _gameProcess?.Close(); _gameProcess = await GenerateProcess(cancellationToken, profileInfo); _gameProcess.Start(); + _gameProcess.StartWatch(); _gameProcess.BeginOutputReadLine(); _gameProcess.BeginErrorReadLine(); @@ -178,7 +191,7 @@ await ExecuteFromNewThread(async () => { ShowError(ResourceKeysDictionary.Error, LocalizationService.GetString(ResourceKeysDictionary.JavaNotFound)); - + SentrySdk.CaptureException(exception); Console.WriteLine(exception); } catch (IOException ioException) when (_systemService.IsDiskFull(ioException)) @@ -186,12 +199,14 @@ await ExecuteFromNewThread(async () => ShowError(ResourceKeysDictionary.Error, LocalizationService.GetString(ResourceKeysDictionary.IsDiskFull)); + SentrySdk.CaptureException(ioException); Console.WriteLine(ioException); } catch (Exception exception) { ShowError(ResourceKeysDictionary.Error, string.Join(". ", exception.Message)); + SentrySdk.CaptureException(exception); Console.WriteLine(exception); } finally @@ -217,29 +232,27 @@ private async Task GenerateProcess(CancellationToken cancellationToken, await _gmlManager.DownloadNotInstalledFiles(profileInfo.Data, cancellationToken); - Process process = await _gmlManager.GetProcess(profileInfo.Data, _systemService.GetOsType()); + var process = await _gmlManager.GetProcess(profileInfo.Data, _systemService.GetOsType()); process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { - Console.WriteLine(e.Data); - - // ToDo: Add sentry java logging - // if (e.Data.Contains("log4j:Throwable")) - // { - // - // } + Debug.WriteLine(e.Data); + _logHandler.ProcessLogs(e.Data); } }; process.ErrorDataReceived += (sender, e) => { - Console.WriteLine(e?.Data); - if (!string.IsNullOrEmpty(e.Data) && !e.Data.Contains("[gml-patch]")) + if (e.Data is null || string.IsNullOrEmpty(e.Data)) { - ShowError(ResourceKeysDictionary.GameProfileError, e.Data); + return; } + + Debug.WriteLine(e.Data); + + _logHandler.ProcessLogs(e.Data); }; await _gmlManager.ClearFiles(profileInfo.Data); @@ -302,18 +315,19 @@ await _gmlManager.UpdateDiscordRpcState( } catch (TaskCanceledException exception) { + SentrySdk.CaptureException(exception); Console.WriteLine(exception); await Reconnect(); } catch (HttpRequestException exception) { + SentrySdk.CaptureException(exception); Console.WriteLine(exception); await Reconnect(); } - catch (Exception ex) + catch (Exception exception) { - Console.WriteLine(ex); - // ToDo: Send To service + SentrySdk.CaptureException(exception); } } diff --git a/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs b/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs index ad7c28d..f8852bc 100644 --- a/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs +++ b/src/Gml.Launcher/ViewModels/SplashScreenViewModel.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Gml.Client; +using Gml.Client.Models; using Gml.Launcher.Assets; using Gml.Launcher.Core.Exceptions; using Gml.Launcher.Core.Services; @@ -12,19 +13,27 @@ using Gml.Web.Api.Domains.System; using GmlCore.Interfaces.Storage; using ReactiveUI.Fody.Helpers; +using Sentry; using Splat; namespace Gml.Launcher.ViewModels; public class SplashScreenViewModel : WindowViewModelBase { + private readonly IStorageService _storageService; private readonly ILocalizationService _localizationService; private readonly IGmlClientManager _manager; private readonly ISystemService _systemService; - public SplashScreenViewModel(ISystemService? systemService = null, IGmlClientManager? manager = null, + public SplashScreenViewModel( + ISystemService? systemService = null, + IGmlClientManager? manager = null, + IStorageService? storage = null, ILocalizationService? localizationService = null) { + _storageService = storage ?? Locator.Current.GetService() + ?? throw new ServiceNotFoundException(typeof(IStorageService));; + _systemService = systemService ?? Locator.Current.GetService() ?? throw new ServiceNotFoundException(typeof(ISystemService)); @@ -40,30 +49,47 @@ public SplashScreenViewModel(ISystemService? systemService = null, IGmlClientMan [Reactive] public string StatusText { get; set; } [Reactive] public bool InfinityLoading { get; set; } = true; [Reactive] public short Progress { get; set; } + [Reactive] public bool IsAuth { get; set; } + public ILocalizationService LocalizationService => _localizationService; public async Task InitializeAsync() { - var osType = _systemService.GetOsType(); - var osArch = RuntimeInformation.ProcessArchitecture; + try + { + var osType = _systemService.GetOsType(); + var osArch = RuntimeInformation.ProcessArchitecture; - await _systemService.LoadSystemData(); - ChangeState(_localizationService.GetString(ResourceKeysDictionary.CheckUpdates), true); + await _systemService.LoadSystemData(); + ChangeState(_localizationService.GetString(ResourceKeysDictionary.CheckUpdates), true); - var versionInfo = await CheckActualVersion(osType, osArch); + var versionInfo = await CheckActualVersion(osType, osArch); - if (!versionInfo.IsActuallVersion) - { - ChangeState(_localizationService.GetString(ResourceKeysDictionary.InstallingUpdates), false); + if (!versionInfo.IsActuallVersion) + { + ChangeState(_localizationService.GetString(ResourceKeysDictionary.InstallingUpdates), false); + + var exePath = Process.GetCurrentProcess().MainModule?.FileName + ?? throw new Exception(ResourceKeysDictionary.FailedOs); + + var process = _manager.ProgressChanged.Subscribe( + percentage => Progress = Convert.ToInt16(percentage)); - var exePath = Process.GetCurrentProcess().MainModule?.FileName - ?? throw new Exception(ResourceKeysDictionary.FailedOs); + await _manager.UpdateCurrentLauncher(versionInfo, osType, Path.GetFileName(exePath)); - var process = _manager.ProgressChanged.Subscribe( - percentage => Progress = Convert.ToInt16(percentage)); + process.Dispose(); + } - await _manager.UpdateCurrentLauncher(versionInfo, osType, Path.GetFileName(exePath)); + var authUser = await _storageService.GetAsync(StorageConstants.User); - process.Dispose(); + var accessUser = await _manager.Auth(authUser?.AccessToken ?? string.Empty); + + await _storageService.SetAsync(StorageConstants.User, accessUser.User); + + IsAuth = accessUser.User.ExpiredDate > DateTime.Now && accessUser is { User.IsAuth: true }; + } + catch (Exception exception) + { + SentrySdk.CaptureException(exception); } } diff --git a/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs b/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs index fb8bd0e..dcb401a 100644 --- a/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs +++ b/src/Gml.Launcher/Views/Pages/SettingsPageView.axaml.cs @@ -12,6 +12,8 @@ using Gml.Launcher.Assets; using Gml.Launcher.ViewModels.Pages; using ReactiveUI; +using Sentry; + // using Sentry; namespace Gml.Launcher.Views.Pages; @@ -54,9 +56,7 @@ private async void OpenFileDialog(object? sender, RoutedEventArgs e) } catch (Exception exception) { - // Log the exception details to Sentry - // SentrySdk.CaptureException(exception); - // TODO Sentry send + SentrySdk.CaptureException(exception); // Existing log statement Console.WriteLine(exception.ToString()); diff --git a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs index 2692191..47155e2 100644 --- a/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs +++ b/src/Gml.Launcher/Views/SplashScreen/SplashScreen.axaml.cs @@ -1,9 +1,14 @@ +using System; using Avalonia.Controls; +using Avalonia.ReactiveUI; +using GamerVII.Notification.Avalonia; +using Gml.Launcher.Assets; using Gml.Launcher.ViewModels; +using Gml.Launcher.ViewModels.Pages; namespace Gml.Launcher.Views.SplashScreen; -public partial class SplashScreen : Window +public partial class SplashScreen : ReactiveWindow { public SplashScreen() { @@ -12,9 +17,25 @@ public SplashScreen() public MainWindow GetMainWindow() { - return new MainWindow + var mainWindow = new MainWindow { DataContext = new MainWindowViewModel() }; + + if (ViewModel?.IsAuth == true) + { + return mainWindow; + } + + mainWindow.ViewModel!.Router.Navigate.Execute(new LoginPageViewModel(mainWindow.ViewModel!, mainWindow.ViewModel!.OnClosed)); + mainWindow.ViewModel.Manager + .CreateMessage(true, "#D03E3E", + ViewModel!.LocalizationService.GetString(ResourceKeysDictionary.Error), + ViewModel!.LocalizationService.GetString(ResourceKeysDictionary.InvalidSession)) + .Dismiss() + .WithDelay(TimeSpan.FromSeconds(3)) + .Queue(); + return mainWindow; + } }