- tweak: Migrate v3 profiles

This commit is contained in:
2025-07-10 15:22:15 +03:00
parent 83d116003b
commit 34fd4ebf4c
19 changed files with 320 additions and 159 deletions

View File

@@ -2,8 +2,8 @@ using System.Collections.Generic;
using System.Globalization;
using Nebula.Launcher.Models;
using Nebula.Launcher.Models.Auth;
using Nebula.Launcher.ViewModels.Pages;
using Nebula.Shared.Services;
using Nebula.Shared.Services.ConfigMigrations;
namespace Nebula.Launcher;
@@ -11,11 +11,16 @@ public static class LauncherConVar
{
public static readonly ConVar<bool> DoMigration =
ConVarBuilder.Build("migration.doMigrate", true);
public static readonly ConVar<ProfileAuthCredentials[]> AuthProfiles =
ConVarBuilder.Build<ProfileAuthCredentials[]>("auth.profiles.v2", []);
public static readonly ConVar<AuthTokenCredentials[]> AuthProfiles =
ConVarBuilder.BuildWithMigration<AuthTokenCredentials[]>("auth.profiles.v3",
MigrationQueueBuilder.Instance
.With(new ProfileMigrationV2("auth.profiles.v2","auth.profiles.v3"))
.Build(),
[]);
public static readonly ConVar<CurrentAuthInfo?> AuthCurrent =
ConVarBuilder.Build<CurrentAuthInfo?>("auth.current.v2");
public static readonly ConVar<AuthTokenCredentials?> AuthCurrent =
ConVarBuilder.Build<AuthTokenCredentials?>("auth.current.v2");
public static readonly ConVar<string[]> Favorites =
ConVarBuilder.Build<string[]>("server.favorites", []);

View File

@@ -1,11 +1,10 @@
using System.Text.Json.Serialization;
using System.Windows.Input;
using Nebula.Shared.Services;
namespace Nebula.Launcher.Models.Auth;
public sealed record ProfileAuthCredentials(
string Login,
string Password,
string AuthServer,
AuthTokenCredentials Credentials,
[property: JsonIgnore] ICommand OnSelect = default!,
[property: JsonIgnore] ICommand OnDelete = default!);

View File

@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Nebula.Launcher.ViewModels.Pages;
using Nebula.Shared;
using Nebula.Shared.Models;
using Nebula.Shared.Services;
@@ -10,7 +11,7 @@ using Nebula.Shared.Services;
namespace Nebula.Launcher.ProcessHelper;
[ServiceRegister(isSingleton:false)]
public sealed class GameProcessStartInfoProvider(DotnetResolverService resolverService, AuthService authService) :
public sealed class GameProcessStartInfoProvider(DotnetResolverService resolverService, AccountInfoViewModel accountInfoViewModel) :
DotnetProcessStartInfoProviderBase(resolverService)
{
private string? _publicKey;
@@ -34,7 +35,7 @@ public sealed class GameProcessStartInfoProvider(DotnetResolverService resolverS
{
var baseStart = await base.GetProcessStartInfo();
var authProv = authService.SelectedAuth;
var authProv = accountInfoViewModel.Credentials;
if(authProv is null)
throw new Exception("Client is without selected auth");

View File

@@ -41,17 +41,17 @@ public partial class MainViewModel : ViewModelBase
[ObservableProperty] private bool _popup;
[ObservableProperty] private ListItemTemplate? _selectedListItem;
public bool IsLoggedIn => AuthService.SelectedAuth is not null;
public string LoginName => AuthService.SelectedAuth?.Login ?? string.Empty;
public bool IsLoggedIn => AccountInfoViewModel.Credentials is not null;
public string LoginName => AccountInfoViewModel.Credentials?.Login ?? string.Empty;
public string LoginText => Services.LocalisationService.GetString("auth-current-login-name",
public string LoginText => LocalisationService.GetString("auth-current-login-name",
new Dictionary<string, object>
{
{ "login", LoginName }
});
[GenerateProperty] private LocalisationService LocalisationService { get; }
[GenerateProperty] private AuthService AuthService { get; }
[GenerateProperty] private LocalisationService LocalisationService { get; } // Не убирать! Без этой хуйни вся локализация идет в пизду!
[GenerateProperty] private AccountInfoViewModel AccountInfoViewModel { get; }
[GenerateProperty] private DebugService DebugService { get; } = default!;
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
[GenerateProperty] private ContentService ContentService { get; } = default!;
@@ -66,7 +66,7 @@ public partial class MainViewModel : ViewModelBase
{
Items = new ObservableCollection<ListItemTemplate>(_templates.Select(a=>
{
return new ListItemTemplate(a.ModelType, a.IconKey, LocalisationService.GetString(a.Label));
return a with { Label = LocalisationService.GetString(a.Label) };
}
));
RequirePage<AccountInfoViewModel>();
@@ -74,6 +74,15 @@ public partial class MainViewModel : ViewModelBase
protected override void Initialise()
{
AccountInfoViewModel.PropertyChanged += (sender, args) =>
{
if (args.PropertyName != nameof(AccountInfoViewModel.Credentials))
return;
OnPropertyChanged(nameof(LoginText));
OnPropertyChanged(nameof(IsLoggedIn));
};
_logger = DebugService.GetLogger(this);
using var stream = typeof(MainViewModel).Assembly
@@ -89,6 +98,11 @@ public partial class MainViewModel : ViewModelBase
CheckMigration();
var loadingHandler = ViewHelperService.GetViewModel<LoadingContextViewModel>();
loadingHandler.LoadingName = LocalisationService.GetString("migration-config-task");
loadingHandler.IsCancellable = false;
ConfigurationService.MigrateConfigs(loadingHandler);
if (!VCRuntimeDllChecker.AreVCRuntimeDllsPresent())
{
OnPopupRequired(LocalisationService.GetString("vcruntime-check-error"));
@@ -146,12 +160,6 @@ public partial class MainViewModel : ViewModelBase
CurrentPage = obj;
}
public void InvokeChangeAuth()
{
OnPropertyChanged(nameof(IsLoggedIn));
OnPropertyChanged(nameof(LoginText));
}
public void PopupMessage(PopupViewModelBase viewModelBase)
{
if (CurrentPopup == null)
@@ -184,6 +192,11 @@ public partial class MainViewModel : ViewModelBase
RequirePage<AccountInfoViewModel>();
}
public void OpenRootPath()
{
ExplorerHelper.OpenFolder(FileService.RootPath);
}
public void OpenLink()
{
Helper.OpenBrowser("https://durenko.tatar/nebula");

View File

@@ -10,6 +10,7 @@ using Nebula.Launcher.Models.Auth;
using Nebula.Launcher.Services;
using Nebula.Launcher.ViewModels.Popup;
using Nebula.Launcher.Views.Pages;
using Nebula.Shared.Models.Auth;
using Nebula.Shared.Services;
using Nebula.Shared.Services.Logging;
using Nebula.Shared.Utils;
@@ -35,9 +36,9 @@ public partial class AccountInfoViewModel : ViewModelBase
[ObservableProperty] private bool _isLogged;
[ObservableProperty] private bool _doRetryAuth;
[ObservableProperty] private AuthTokenCredentials? _credentials;
private bool _isProfilesEmpty;
[GenerateProperty] private LocalisationService LocalisationService { get; }
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
[GenerateProperty] private ConfigurationService ConfigurationService { get; } = default!;
[GenerateProperty] private DebugService DebugService { get; }
@@ -54,8 +55,8 @@ public partial class AccountInfoViewModel : ViewModelBase
//Design think
protected override void InitialiseInDesignMode()
{
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
AddAccount(new AuthTokenCredentials(Guid.Empty, LoginToken.Empty, "Binka", ""));
AddAccount(new AuthTokenCredentials(Guid.Empty, LoginToken.Empty, "Binka", ""));
AuthUrls.Add(new AuthServerCredentials("Test",["example.com"]));
}
@@ -67,13 +68,31 @@ public partial class AccountInfoViewModel : ViewModelBase
Task.Run(ReadAuthConfig);
}
public void AuthByProfile(ProfileAuthCredentials credentials)
public async void AuthByProfile(ProfileAuthCredentials credentials)
{
CurrentLogin = credentials.Login;
CurrentPassword = credentials.Password;
CurrentAuthServer = credentials.AuthServer;
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
message.InfoText = LocalisationService.GetString("auth-try-auth-profile");
message.IsInfoClosable = false;
PopupMessageService.Popup(message);
DoAuth();
try
{
await CatchAuthError(async () => await TryAuth(credentials.Credentials), () => message.Dispose());
}
catch (Exception ex)
{
CurrentLogin = credentials.Credentials.Login;
CurrentAuthServer = credentials.Credentials.AuthServer;
var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), ex);
_logger.Error(unexpectedError);
PopupMessageService.Popup(unexpectedError);
return;
}
ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, Credentials);
message.Dispose();
}
public void DoAuth(string? code = null)
@@ -117,22 +136,28 @@ public partial class AccountInfoViewModel : ViewModelBase
});
}
private async Task TryAuth(CurrentAuthInfo currentAuthInfo)
private async Task TryAuth(AuthTokenCredentials authTokenCredentials)
{
CurrentLogin = currentAuthInfo.Login;
CurrentAuthServer = currentAuthInfo.AuthServer;
await AuthService.SetAuth(currentAuthInfo);
CurrentLogin = authTokenCredentials.Login;
CurrentAuthServer = authTokenCredentials.AuthServer;
await SetAuth(authTokenCredentials);
IsLogged = true;
}
private async Task SetAuth(AuthTokenCredentials authTokenCredentials)
{
await AuthService.EnsureToken(authTokenCredentials);
Credentials = authTokenCredentials;
}
private async Task TryAuth(string login, string password, string authServer, string? code)
{
await AuthService.Auth(new AuthLoginPassword(login, password, authServer), code);
Credentials = await AuthService.Auth(login, password, authServer, code);
CurrentLogin = login;
CurrentPassword = password;
CurrentAuthServer = authServer;
IsLogged = true;
ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth);
ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, Credentials);
}
private async Task CatchAuthError(Func<Task> a, Action? onError)
@@ -142,7 +167,6 @@ public partial class AccountInfoViewModel : ViewModelBase
try
{
await a();
ViewHelperService.GetViewModel<MainViewModel>().InvokeChangeAuth();
}
catch (AuthException e)
{
@@ -200,8 +224,7 @@ public partial class AccountInfoViewModel : ViewModelBase
public void Logout()
{
IsLogged = false;
AuthService.ClearAuth();
ViewHelperService.GetViewModel<MainViewModel>().InvokeChangeAuth();
Credentials = null;
}
private void UpdateAuthMenu()
@@ -212,15 +235,13 @@ public partial class AccountInfoViewModel : ViewModelBase
AuthViewSpan = 1;
}
private void AddAccount(AuthLoginPassword authLoginPassword)
private void AddAccount(AuthTokenCredentials credentials)
{
var onDelete = new DelegateCommand<ProfileAuthCredentials>(OnDeleteProfile);
var onSelect = new DelegateCommand<ProfileAuthCredentials>(AuthByProfile);
var alpm = new ProfileAuthCredentials(
authLoginPassword.Login,
authLoginPassword.Password,
authLoginPassword.AuthServer,
credentials,
onSelect,
onDelete);
@@ -238,7 +259,7 @@ public partial class AccountInfoViewModel : ViewModelBase
PopupMessageService.Popup(message);
foreach (var profile in
ConfigurationService.GetConfigValue(LauncherConVar.AuthProfiles)!)
AddAccount(new AuthLoginPassword(profile.Login, profile.Password, profile.AuthServer));
AddAccount(profile);
if (Accounts.Count == 0) UpdateAuthMenu();
@@ -281,7 +302,9 @@ public partial class AccountInfoViewModel : ViewModelBase
[RelayCommand]
private void OnSaveProfile()
{
AddAccount(new AuthLoginPassword(CurrentLogin, CurrentPassword, CurrentAuthServer));
if(Credentials is null) return;
AddAccount(Credentials);
_isProfilesEmpty = Accounts.Count == 0;
UpdateAuthMenu();
DirtyProfile();
@@ -322,6 +345,6 @@ public partial class AccountInfoViewModel : ViewModelBase
private void DirtyProfile()
{
ConfigurationService.SetConfigValue(LauncherConVar.AuthProfiles,
Accounts.ToArray());
Accounts.Select(a => a.Credentials).ToArray());
}
}

View File

@@ -15,8 +15,8 @@ public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadi
[GenerateProperty] public CancellationService CancellationService { get; }
[ObservableProperty] private int _currJobs;
[ObservableProperty] private int _resolvedJobs;
[ObservableProperty] private string _message = string.Empty;
public string LoadingName { get; set; } = LocalisationService.GetString("popup-loading");
public bool IsCancellable { get; set; } = true;
@@ -44,6 +44,11 @@ public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadi
return ResolvedJobs;
}
public void SetLoadingMessage(string message)
{
Message = message + "\n" + Message;
}
public void Cancel(){
if(!IsCancellable) return;
CancellationService.Cancel();
@@ -56,5 +61,30 @@ public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadi
protected override void InitialiseInDesignMode()
{
SetJobsCount(5);
SetResolvedJobsCount(2);
string[] debugMessages = {
"Debug: Starting phase 1...",
"Debug: Loading assets...",
"Debug: Connecting to server...",
"Debug: Fetching user data...",
"Debug: Applying configurations...",
"Debug: Starting phase 2...",
"Debug: Rendering UI...",
"Debug: Preparing scene...",
"Debug: Initializing components...",
"Debug: Running diagnostics...",
"Debug: Checking dependencies...",
"Debug: Verifying files...",
"Debug: Cleaning up cache...",
"Debug: Finalizing setup...",
"Debug: Setup complete.",
"Debug: Ready for launch."
};
foreach (string message in debugMessages)
{
SetLoadingMessage(message);
}
}
}

View File

@@ -47,7 +47,7 @@ public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, ILis
public LogPopupModelView CurrLog;
public RobustUrl Address { get; private set; }
[GenerateProperty] private AuthService AuthService { get; }
[GenerateProperty] private AccountInfoViewModel AccountInfoViewModel { get; }
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
[GenerateProperty] private DebugService DebugService { get; } = default!;
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
@@ -174,7 +174,7 @@ public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, ILis
private async Task RunInstanceAsync(bool ignoreLoginCredentials = false)
{
if (!ignoreLoginCredentials && AuthService.SelectedAuth is null)
if (!ignoreLoginCredentials && AccountInfoViewModel.Credentials is null)
{
var warningContext = ViewHelperService.GetViewModel<IsLoginCredentialsNullPopupViewModel>()
.WithServerEntry(this);

View File

@@ -127,10 +127,30 @@
Padding="0"
CornerRadius="0"
Command="{Binding OpenAuthPage}">
<Panel>
<TextBlock Foreground="#777777" IsVisible="{Binding IsLoggedIn}" Text="{Binding LoginText}"/>
<TextBlock Foreground="#777777" IsVisible="{Binding !IsLoggedIn}" Text="{services:LocaledText auth-current-login-no-name}"/>
</Panel>
<StackPanel Spacing="5" Orientation="Horizontal">
<Svg
Height="40"
Path="/Assets/svg/user.svg"
Width="10" />
<Panel>
<TextBlock Foreground="#777777" IsVisible="{Binding IsLoggedIn}" Text="{Binding LoginText}"/>
<TextBlock Foreground="#777777" IsVisible="{Binding !IsLoggedIn}" Text="{services:LocaledText auth-current-login-no-name}"/>
</Panel>
</StackPanel>
</Button>
<TextBlock>|</TextBlock>
<Button
Margin="0"
Padding="0"
CornerRadius="0"
Command="{Binding OpenRootPath}">
<StackPanel Orientation="Horizontal" Spacing="5">
<Svg
Height="40"
Path="/Assets/svg/folder.svg"
Width="10" />
<TextBlock Foreground="#777777" Text="{services:LocaledText goto-path-home}"/>
</StackPanel>
</Button>
<TextBlock>|</TextBlock>
<TextBlock Text="{Binding VersionInfo}"/>

View File

@@ -53,7 +53,7 @@
<Panel>
<StackPanel Margin="10,5,5,5" Orientation="Horizontal">
<Label>
<TextBlock Text="{Binding Login}" />
<TextBlock Text="{Binding Credentials.Login}" />
</Label>
</StackPanel>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
@@ -156,14 +156,6 @@
<customControls:LocalizedLabel LocalId="account-auth-button"/>
</Button>
</Border>
<Border BoxShadow="{StaticResource DefaultShadow}">
<Button
Command="{Binding SaveProfileCommand}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center">
<customControls:LocalizedLabel LocalId="account-auth-save"/>
</Button>
</Border>
<Button Command="{Binding ExpandAuthViewCommand}" HorizontalAlignment="Right">
<Label>
>

View File

@@ -33,5 +33,10 @@
<customControls:LocalizedLabel LocalId="task-cancel"/>
</Button>
</Panel>
<Panel>
<Border Background="{StaticResource DefaultForeground}" MinHeight="210">
<TextBlock TextWrapping="Wrap" Text="{Binding Message}" MaxLines="10" Margin="15"/>
</Border>
</Panel>
</StackPanel>
</UserControl>