diff --git a/Nebula.Launcher/LauncherConVar.cs b/Nebula.Launcher/LauncherConVar.cs index 7c01241..57da4ca 100644 --- a/Nebula.Launcher/LauncherConVar.cs +++ b/Nebula.Launcher/LauncherConVar.cs @@ -14,8 +14,8 @@ public static class LauncherConVar public static readonly ConVar Favorites = ConVarBuilder.Build("server.favorites", []); - public static readonly ConVar AuthServers = ConVarBuilder.Build("launcher.authServers", [ - "https://auth.spacestation14.com/" + public static readonly ConVar AuthServers = ConVarBuilder.Build("launcher.authServers", [ + new AuthServerCredentials("WizDen", ["https://auth.spacestation14.com/", "https://auth.fallback.spacestation14.com/"]) ]); public static readonly ConVar CurrentLang = ConVarBuilder.Build("launcher.language", "en-US"); diff --git a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs index 14e7fce..afbe9a9 100644 --- a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs +++ b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text.Json.Serialization; @@ -40,23 +41,9 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage [GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!; public ObservableCollection Accounts { get; } = new(); - public ObservableCollection AuthUrls { get; } = new(); + public ObservableCollection AuthUrls { get; } = new(); - private AuthLoginPassword CurrentAlp - { - get => new(CurrentLogin, CurrentPassword, CurrentAuthServer); - set - { - CurrentLogin = value.Login; - CurrentPassword = value.Password; - CurrentAuthServer = value.AuthServer; - } - } - - public string AuthItemSelect - { - set => CurrentAuthServer = value; - } + [ObservableProperty] private AuthServerCredentials _authItemSelect; //Design think protected override void InitialiseInDesignMode() @@ -64,8 +51,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage AddAccount(new AuthLoginPassword("Binka", "12341", "")); AddAccount(new AuthLoginPassword("Binka", "12341", "")); - AuthUrls.Add("https://cinka.ru"); - AuthUrls.Add("https://cinka.ru"); + AuthUrls.Add(new AuthServerCredentials("Test",["example.com"])); } //Real think @@ -76,7 +62,10 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage public void AuthByProfile(ProfileAuthCredentials credentials) { - CurrentAlp = new AuthLoginPassword(credentials.Login, credentials.Password, credentials.AuthServer); + CurrentLogin = credentials.Login; + CurrentPassword = credentials.Password; + CurrentAuthServer = credentials.AuthServer; + DoAuth(); } @@ -87,43 +76,69 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage message.IsInfoClosable = false; PopupMessageService.Popup(message); + var serverCandidates = new List(); + + if (string.IsNullOrWhiteSpace(CurrentAuthServer)) + serverCandidates.AddRange(AuthItemSelect.Servers); + else + serverCandidates.Add(CurrentAuthServer); + Task.Run(async () => { - try + Exception? exception = null; + foreach (var server in serverCandidates) { - await AuthService.Auth(CurrentAlp, code); - message.Dispose(); - IsLogged = true; - ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth); - } - catch (AuthException e) - { - message.Dispose(); - - switch (e.Error.Code) + try { - case AuthenticateDenyCode.TfaRequired: - case AuthenticateDenyCode.TfaInvalid: - var p = ViewHelperService.GetViewModel(); - p.OnTfaEntered += OnTfaEntered; - PopupMessageService.Popup(p); - break; - case AuthenticateDenyCode.InvalidCredentials: - PopupMessageService.Popup("Invalid Credentials!"); - break; - default: - throw; + await TryAuth(CurrentLogin, CurrentPassword, server,code); + break; + } + catch (Exception e) + { + exception = e; } } - catch (Exception e) + + message.Dispose(); + + if (!IsLogged) { - message.Dispose(); - Logout(); - PopupMessageService.Popup(e); + PopupMessageService.Popup(new Exception("No one of auth server is available.", exception)); } }); } + private async Task TryAuth(string login, string password, string authServer,string? code) + { + try + { + await AuthService.Auth(new AuthLoginPassword(login, password, authServer), code); + CurrentLogin = login; + CurrentPassword = password; + CurrentAuthServer = authServer; + IsLogged = true; + ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth); + } + catch (AuthException e) + { + + switch (e.Error.Code) + { + case AuthenticateDenyCode.TfaRequired: + case AuthenticateDenyCode.TfaInvalid: + var p = ViewHelperService.GetViewModel(); + p.OnTfaEntered += OnTfaEntered; + PopupMessageService.Popup(p); + break; + case AuthenticateDenyCode.InvalidCredentials: + PopupMessageService.Popup("Invalid Credentials!"); + break; + default: + throw; + } + } + } + private void OnTfaEntered(string code) { DoAuth(code); @@ -176,7 +191,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage AuthUrls.Clear(); var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!; foreach (var url in authUrls) AuthUrls.Add(url); - if(authUrls.Length > 0) CurrentAuthServer = authUrls[0]; + if(authUrls.Length > 0) AuthItemSelect = authUrls[0]; var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent); @@ -184,7 +199,9 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage { try { - CurrentAlp = new AuthLoginPassword(currProfile.Login, string.Empty, currProfile.AuthServer); + CurrentLogin = currProfile.Login; + CurrentAuthServer = currProfile.AuthServer; + IsLogged = await AuthService.SetAuth(currProfile); } catch (Exception e) @@ -200,7 +217,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage [RelayCommand] private void OnSaveProfile() { - AddAccount(CurrentAlp); + AddAccount(new AuthLoginPassword(CurrentLogin, CurrentPassword, CurrentAuthServer)); _isProfilesEmpty = Accounts.Count == 0; UpdateAuthMenu(); DirtyProfile(); @@ -243,4 +260,9 @@ public sealed record ProfileAuthCredentials( string AuthServer, [property: JsonIgnore] ICommand OnSelect = default!, [property: JsonIgnore] ICommand OnDelete = default! - ); \ No newline at end of file +); + +public sealed record AuthServerCredentials( + string Name, + string[] Servers +); \ No newline at end of file diff --git a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml index ece2fdf..e5fe40b 100644 --- a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml +++ b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml @@ -118,7 +118,6 @@ - @@ -139,7 +138,7 @@ diff --git a/Nebula.Shared/CurrentConVar.cs b/Nebula.Shared/CurrentConVar.cs index 15f6f0e..5168f22 100644 --- a/Nebula.Shared/CurrentConVar.cs +++ b/Nebula.Shared/CurrentConVar.cs @@ -6,10 +6,16 @@ namespace Nebula.Shared; public static class CurrentConVar { public static readonly ConVar EngineManifestUrl = - ConVarBuilder.Build("engine.manifestUrl", ["https://robust-builds.cdn.spacestation14.com/manifest.json"]); + ConVarBuilder.Build("engine.manifestUrl", [ + "https://robust-builds.cdn.spacestation14.com/manifest.json", + "https://robust-builds.fallback.cdn.spacestation14.com/manifest.json" + ]); public static readonly ConVar EngineModuleManifestUrl = - ConVarBuilder.Build("engine.moduleManifestUrl", ["https://robust-builds.cdn.spacestation14.com/modules.json"]); + ConVarBuilder.Build("engine.moduleManifestUrl", [ + "https://robust-builds.cdn.spacestation14.com/modules.json", + "https://robust-builds.fallback.cdn.spacestation14.com/modules.json" + ]); public static readonly ConVar ManifestDownloadProtocolVersion = ConVarBuilder.Build("engine.manifestDownloadProtocolVersion", 1); @@ -17,8 +23,8 @@ public static class CurrentConVar public static readonly ConVar RobustAssemblyName = ConVarBuilder.Build("engine.robustAssemblyName", "Robust.Client"); - public static readonly ConVar Hub = ConVarBuilder.Build("launcher.hub", [ - "https://hub.spacestation14.com/api/servers" + public static readonly ConVar Hub = ConVarBuilder.Build("launcher.hub", [ + ["https://hub.spacestation14.com/api/servers", "https://auth.fallback.spacestation14.com/"] ]); public static readonly ConVar> EngineManifestBackup = diff --git a/Nebula.Shared/Services/HubService.cs b/Nebula.Shared/Services/HubService.cs index 1db87f3..63c756b 100644 --- a/Nebula.Shared/Services/HubService.cs +++ b/Nebula.Shared/Services/HubService.cs @@ -7,6 +7,7 @@ public class HubService { private readonly ConfigurationService _configurationService; private readonly RestService _restService; + private readonly DebugService _debugService; private readonly List _serverList = new(); @@ -14,10 +15,11 @@ public class HubService public Action? HubServerLoaded; public Action? HubServerLoadingError; - public HubService(ConfigurationService configurationService, RestService restService) + public HubService(ConfigurationService configurationService, RestService restService, DebugService debugService) { _configurationService = configurationService; _restService = restService; + _debugService = debugService; UpdateHub(); } @@ -37,17 +39,29 @@ public class HubService foreach (var urlStr in _configurationService.GetConfigValue(CurrentConVar.Hub)!) { - try + var invoked = false; + Exception? exception = null; + foreach (var uri in urlStr) { - var servers = - await _restService.GetAsync>(new Uri(urlStr), CancellationToken.None); - _serverList.AddRange(servers); - HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs(servers, HubServerChangeAction.Add)); - } - catch (Exception e) - { - HubServerLoadingError?.Invoke(e); + try + { + var servers = + await _restService.GetAsync>(new Uri(uri), CancellationToken.None); + _serverList.AddRange(servers); + HubServerChangedEventArgs?.Invoke(new HubServerChangedEventArgs(servers, HubServerChangeAction.Add)); + invoked = true; + break; + } + catch (Exception e) + { + _debugService.Error($"Failed to get servers for {uri}"); + _debugService.Error(e); + exception = e; + } } + + if(exception is not null && !invoked) + HubServerLoadingError?.Invoke(new Exception("No hub is available.", exception)); } IsUpdating = false; diff --git a/Nebula.sln.DotSettings.user b/Nebula.sln.DotSettings.user index 97aaa17..244caef 100644 --- a/Nebula.sln.DotSettings.user +++ b/Nebula.sln.DotSettings.user @@ -1,6 +1,7 @@  ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -11,4 +12,5 @@ ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + INFO \ No newline at end of file