diff --git a/.idea/.idea.Nebula/.idea/avalonia.xml b/.idea/.idea.Nebula/.idea/avalonia.xml
index 6c38c66..42497a3 100644
--- a/.idea/.idea.Nebula/.idea/avalonia.xml
+++ b/.idea/.idea.Nebula/.idea/avalonia.xml
@@ -25,6 +25,7 @@
+
diff --git a/Nebula.Launcher/LauncherConVar.cs b/Nebula.Launcher/LauncherConVar.cs
new file mode 100644
index 0000000..cd13180
--- /dev/null
+++ b/Nebula.Launcher/LauncherConVar.cs
@@ -0,0 +1,20 @@
+using Nebula.Launcher.ViewModels.Pages;
+using Nebula.Shared.Services;
+
+namespace Nebula.Launcher;
+
+public static class LauncherConVar
+{
+ public static readonly ConVar AuthProfiles =
+ ConVarBuilder.Build("auth.profiles.v2", []);
+
+ public static readonly ConVar AuthCurrent =
+ ConVarBuilder.Build("auth.current.v2");
+
+ public static readonly ConVar Favorites =
+ ConVarBuilder.Build("server.favorites", []);
+
+ public static readonly ConVar AuthServers = ConVarBuilder.Build("launcher.authServers", [
+ "https://auth.spacestation14.com/"
+ ]);
+}
\ No newline at end of file
diff --git a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs
index 87ca87b..74e2279 100644
--- a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs
+++ b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -38,7 +39,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
[GenerateProperty] private AuthService AuthService { get; } = default!;
[GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!;
- public ObservableCollection Accounts { get; } = new();
+ public ObservableCollection Accounts { get; } = new();
public ObservableCollection AuthUrls { get; } = new();
private AuthLoginPassword CurrentAlp
@@ -52,6 +53,9 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
}
}
+
+ private CurrentAuthInfo? _currAuthTemp;
+
public string AuthItemSelect
{
set => CurrentAuthServer = value;
@@ -71,37 +75,61 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
ReadAuthConfig();
}
- public void AuthByAlp(AuthLoginPassword authLoginPassword)
+ public void AuthByProfile(ProfileAuthCredentials credentials)
{
- CurrentAlp = authLoginPassword;
+ CurrentAlp = new AuthLoginPassword(credentials.Login, credentials.Password, credentials.AuthServer);
DoAuth();
}
- public void DoAuth()
+ public void DoAuth(string? code = null)
{
var message = ViewHelperService.GetViewModel();
message.InfoText = "Auth think, please wait...";
message.IsInfoClosable = false;
- Console.WriteLine("AUTH SHIT");
PopupMessageService.Popup(message);
Task.Run(async () =>
{
- if (await AuthService.Auth(CurrentAlp))
+ try
{
+ await AuthService.Auth(CurrentAlp, code);
message.Dispose();
IsLogged = true;
- ConfigurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
+ ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth);
}
- else
+ catch (AuthException e)
+ {
+ message.Dispose();
+
+ 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;
+ }
+ }
+ catch (Exception e)
{
message.Dispose();
Logout();
- PopupMessageService.Popup("Well, shit is happened: " + AuthService.Reason);
+ PopupMessageService.Popup(e);
}
});
}
+ private void OnTfaEntered(string code)
+ {
+ DoAuth(code);
+ }
+
public void Logout()
{
IsLogged = false;
@@ -118,10 +146,10 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
private void AddAccount(AuthLoginPassword authLoginPassword)
{
- var onDelete = new DelegateCommand(OnDeleteProfile);
- var onSelect = new DelegateCommand(AuthByAlp);
+ var onDelete = new DelegateCommand(OnDeleteProfile);
+ var onSelect = new DelegateCommand(AuthByProfile);
- var alpm = new AuthLoginPasswordModel(
+ var alpm = new ProfileAuthCredentials(
authLoginPassword.Login,
authLoginPassword.Password,
authLoginPassword.AuthServer,
@@ -134,25 +162,39 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
Accounts.Add(alpm);
}
- private void ReadAuthConfig()
+ private async void ReadAuthConfig()
{
+ var message = ViewHelperService.GetViewModel();
+ message.InfoText = "Read configuration file, please wait...";
+ message.IsInfoClosable = false;
+ PopupMessageService.Popup(message);
foreach (var profile in
- ConfigurationService.GetConfigValue(CurrentConVar.AuthProfiles)!)
- AddAccount(profile);
+ ConfigurationService.GetConfigValue(LauncherConVar.AuthProfiles)!)
+ AddAccount(new AuthLoginPassword(profile.Login, profile.Password, profile.AuthServer));
if (Accounts.Count == 0) UpdateAuthMenu();
- var currProfile = ConfigurationService.GetConfigValue(CurrentConVar.AuthCurrent);
+ AuthUrls.Clear();
+ var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!;
+ foreach (var url in authUrls) AuthUrls.Add(url);
+
+ var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent);
if (currProfile != null)
{
- CurrentAlp = currProfile;
- DoAuth();
+ try
+ {
+ CurrentAlp = new AuthLoginPassword(currProfile.Login, string.Empty, currProfile.AuthServer);
+ IsLogged = await AuthService.SetAuth(currProfile);
+ }
+ catch (Exception e)
+ {
+ message.Dispose();
+ PopupMessageService.Popup(e);
+ }
}
-
- AuthUrls.Clear();
- var authUrls = ConfigurationService.GetConfigValue(CurrentConVar.AuthServers)!;
- foreach (var url in authUrls) AuthUrls.Add(url);
+
+ message.Dispose();
}
[RelayCommand]
@@ -164,7 +206,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
DirtyProfile();
}
- private void OnDeleteProfile(AuthLoginPasswordModel account)
+ private void OnDeleteProfile(ProfileAuthCredentials account)
{
Accounts.Remove(account);
_isProfilesEmpty = Accounts.Count == 0;
@@ -187,20 +229,18 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
private void DirtyProfile()
{
- ConfigurationService.SetConfigValue(CurrentConVar.AuthProfiles,
- Accounts.Select(a => (AuthLoginPassword)a).ToArray());
+ ConfigurationService.SetConfigValue(LauncherConVar.AuthProfiles,
+ Accounts.ToArray());
}
public void OnPageOpen(object? args)
{
-
}
}
-
-public record AuthLoginPasswordModel(
+public sealed record ProfileAuthCredentials(
string Login,
string Password,
string AuthServer,
- ICommand OnSelect = default!,
- ICommand OnDelete = default!)
- : AuthLoginPassword(Login, Password, AuthServer);
\ No newline at end of file
+ [property: JsonIgnore] ICommand OnSelect = default!,
+ [property: JsonIgnore] ICommand OnDelete = default!
+ );
\ No newline at end of file
diff --git a/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs
index 6bf0221..64b9152 100644
--- a/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs
+++ b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs
@@ -22,7 +22,7 @@ public partial class ServerListViewModel
{
FavoriteServers.Clear();
- var servers = ConfigurationService.GetConfigValue(CurrentConVar.Favorites);
+ var servers = ConfigurationService.GetConfigValue(LauncherConVar.Favorites);
if (servers is null || servers.Length == 0)
{
return;
@@ -44,17 +44,17 @@ public partial class ServerListViewModel
public void AddFavorite(RobustUrl robustUrl)
{
- var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList();
+ var servers = (ConfigurationService.GetConfigValue(LauncherConVar.Favorites) ?? []).ToList();
servers.Add(robustUrl.ToString());
- ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray());
+ ConfigurationService.SetConfigValue(LauncherConVar.Favorites, servers.ToArray());
UpdateFavoriteEntries();
}
public void RemoveFavorite(ServerEntryModelView entryModelView)
{
- var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList();
+ var servers = (ConfigurationService.GetConfigValue(LauncherConVar.Favorites) ?? []).ToList();
servers.Remove(entryModelView.Address.ToString());
- ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray());
+ ConfigurationService.SetConfigValue(LauncherConVar.Favorites, servers.ToArray());
entryModelView.IsFavorite = false;
UpdateFavoriteEntries();
}
diff --git a/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs b/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs
new file mode 100644
index 0000000..62511ae
--- /dev/null
+++ b/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs
@@ -0,0 +1,29 @@
+using System;
+using Nebula.Launcher.Views.Popup;
+using Nebula.Shared.Services;
+
+namespace Nebula.Launcher.ViewModels.Popup;
+
+[ConstructGenerator, ViewModelRegister(typeof(TfaView))]
+public partial class TfaViewModel : PopupViewModelBase
+{
+ public Action? OnTfaEntered;
+
+ protected override void InitialiseInDesignMode()
+ {
+ }
+
+ protected override void Initialise()
+ {
+ }
+
+ public void OnTfaEnter(string code)
+ {
+ OnTfaEntered?.Invoke(code);
+ Dispose();
+ }
+
+ [GenerateProperty] public override PopupMessageService PopupMessageService { get; }
+ public override string Title => "2fa";
+ public override bool IsClosable => true;
+}
\ No newline at end of file
diff --git a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
index e7e7827..a257c01 100644
--- a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
+++ b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
@@ -185,10 +185,10 @@ public partial class ServerEntryModelView : ViewModelBase
{
{ "ROBUST_AUTH_USERID", authProv?.UserId.ToString() },
{ "ROBUST_AUTH_TOKEN", authProv?.Token.Token },
- { "ROBUST_AUTH_SERVER", authProv?.AuthLoginPassword.AuthServer },
+ { "ROBUST_AUTH_SERVER", authProv?.AuthServer },
{ "ROBUST_AUTH_PUBKEY", buildInfo.BuildInfo.Auth.PublicKey },
{ "GAME_URL", Address.ToString() },
- { "AUTH_LOGIN", authProv?.AuthLoginPassword.Login }
+ { "AUTH_LOGIN", authProv?.Login }
},
CreateNoWindow = true,
UseShellExecute = false,
@@ -253,8 +253,7 @@ public partial class ServerEntryModelView : ViewModelBase
CurrLog.Append(e.Data);
}
}
-
-
+
public void ReadLog()
{
PopupMessageService.Popup(CurrLog);
@@ -286,7 +285,6 @@ public partial class ServerEntryModelView : ViewModelBase
{
Links.Add(link);
}
-
}
private static string FindDotnetPath()
diff --git a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml
index dd3933b..608b9e3 100644
--- a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml
+++ b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml
@@ -31,7 +31,7 @@
ItemsSource="{Binding Accounts}"
Padding="0">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Nebula.Launcher/Views/Popup/TfaView.axaml.cs b/Nebula.Launcher/Views/Popup/TfaView.axaml.cs
new file mode 100644
index 0000000..daddcbb
--- /dev/null
+++ b/Nebula.Launcher/Views/Popup/TfaView.axaml.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Nebula.Launcher.ViewModels.Popup;
+
+namespace Nebula.Launcher.Views.Popup;
+
+public partial class TfaView : UserControl
+{
+ public List Boxes = new();
+
+ public TfaView()
+ {
+ InitializeComponent();
+
+ foreach (var textBox in TContainer.Children.Select(UnzipBox))
+ {
+ var currIndex = Boxes.Count;
+ Boxes.Add(textBox);
+ textBox.TextChanged += (_,_) => OnTextChanged(currIndex);
+ textBox.PastingFromClipboard += OnPasteFromClipboard;
+ textBox.KeyUp += (sender, args) =>
+ {
+ if (args.Key == Key.Back && string.IsNullOrEmpty(textBox.Text)) OnTextChanged(currIndex);
+ };
+ textBox.KeyDown += (sender, args) =>
+ {
+ textBox.Text = args.KeySymbol;
+ textBox.SelectionStart = 1;
+ //OnTextChanged(currIndex);
+ };
+ }
+ }
+
+ private void OnPasteFromClipboard(object? sender, RoutedEventArgs e)
+ {
+ // TODO: CLIPBOARD THINK
+ }
+
+ private void OnTextChanged(int index)
+ {
+ var box = Boxes[index];
+
+ if (string.IsNullOrEmpty(box.Text))
+ {
+ if(index == 0) return;
+ index--;
+ }
+ else
+ {
+ if(!int.TryParse(box.Text, out var _))
+ {
+ box.Text = "";
+ return;
+ }
+
+ if (index == 5)
+ {
+ CheckupCode();
+ return;
+ }
+ index++;
+ }
+
+ Boxes[index].Focus();
+ }
+
+ private void CheckupCode()
+ {
+ var str = "";
+ foreach (var vtTextBox in Boxes)
+ {
+ if(string.IsNullOrEmpty(vtTextBox.Text)) return;
+ str += vtTextBox.Text;
+ }
+
+ ((TfaViewModel)DataContext!).OnTfaEnter(str);
+ }
+
+ private TextBox UnzipBox(Control control)
+ {
+ var box = (Border)control;
+ return (TextBox)box.Child!;
+ }
+
+ public TfaView(TfaViewModel tfaViewModel) : this()
+ {
+ DataContext = tfaViewModel;
+ }
+
+ private void Button_OnClick(object? sender, RoutedEventArgs e)
+ {
+ CheckupCode();
+ }
+}
\ No newline at end of file
diff --git a/Nebula.Launcher/Views/ServerEntryView.axaml b/Nebula.Launcher/Views/ServerEntryView.axaml
index d2c4d7f..3f42ce4 100644
--- a/Nebula.Launcher/Views/ServerEntryView.axaml
+++ b/Nebula.Launcher/Views/ServerEntryView.axaml
@@ -228,7 +228,7 @@
AuthServers = ConVarBuilder.Build("launcher.authServers", [
- "https://auth.spacestation14.com/"
- ]);
-
- public static readonly ConVar AuthProfiles =
- ConVarBuilder.Build("auth.profiles", []);
-
- public static readonly ConVar AuthCurrent =
- ConVarBuilder.Build("auth.current");
-
- public static readonly ConVar Favorites =
- ConVarBuilder.Build("server.favorites", []);
-
public static readonly ConVar> EngineManifestBackup =
ConVarBuilder.Build>("engine.manifest.backup");
public static readonly ConVar ModuleManifestBackup =
diff --git a/Nebula.Shared/Models/Auth/LoginToken.cs b/Nebula.Shared/Models/Auth/LoginToken.cs
index 09abe04..e7b69fd 100644
--- a/Nebula.Shared/Models/Auth/LoginToken.cs
+++ b/Nebula.Shared/Models/Auth/LoginToken.cs
@@ -1,13 +1,3 @@
namespace Nebula.Shared.Models.Auth;
-public readonly struct LoginToken
-{
- public readonly string Token;
- public readonly DateTimeOffset ExpireTime;
-
- public LoginToken(string token, DateTimeOffset expireTime)
- {
- Token = token;
- ExpireTime = expireTime;
- }
-}
\ No newline at end of file
+public sealed record LoginToken(string Token, DateTimeOffset ExpireTime);
\ No newline at end of file
diff --git a/Nebula.Shared/Services/AuthService.cs b/Nebula.Shared/Services/AuthService.cs
index 9b9f6b0..d6e2b7b 100644
--- a/Nebula.Shared/Services/AuthService.cs
+++ b/Nebula.Shared/Services/AuthService.cs
@@ -1,5 +1,9 @@
-using System.Net.Http.Headers;
+using System.Net;
+using System.Net.Http.Headers;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using Nebula.Shared.Models.Auth;
+using Nebula.Shared.Utils;
namespace Nebula.Shared.Services;
@@ -10,11 +14,9 @@ public class AuthService(
CancellationService cancellationService)
{
private readonly HttpClient _httpClient = new();
+ public CurrentAuthInfo? SelectedAuth { get; private set; }
- public string Reason = "";
- public CurrentAuthInfo? SelectedAuth { get; internal set; }
-
- public async Task Auth(AuthLoginPassword authLoginPassword)
+ public async Task Auth(AuthLoginPassword authLoginPassword, string? code = null)
{
var authServer = authLoginPassword.AuthServer;
var login = authLoginPassword.Login;
@@ -24,20 +26,24 @@ public class AuthService(
var authUrl = new Uri($"{authServer}api/auth/authenticate");
- var result =
- await restService.PostAsync(
- new AuthenticateRequest(login, password), authUrl, cancellationService.Token);
-
- if (result.Value is null)
+ try
{
- Reason = result.Message;
- return false;
+ var result =
+ await restService.PostAsync(
+ new AuthenticateRequest(login, null, password, code), authUrl, cancellationService.Token);
+
+ SelectedAuth = new CurrentAuthInfo(result.UserId,
+ new LoginToken(result.Token, result.ExpireTime), authLoginPassword.Login, authLoginPassword.AuthServer);
+ }
+ catch (RestRequestException e)
+ {
+ Console.WriteLine(e.Content);
+ if (e.StatusCode != HttpStatusCode.Unauthorized) throw;
+ var err = await e.Content.AsJson();
+
+ if (err is null) throw;
+ throw new AuthException(err);
}
-
- SelectedAuth = new CurrentAuthInfo(result.Value.UserId,
- new LoginToken(result.Value.Token, result.Value.ExpireTime), authLoginPassword);
-
- return true;
}
public void ClearAuth()
@@ -45,17 +51,17 @@ public class AuthService(
SelectedAuth = null;
}
- public void SetAuth(Guid guid, string token, string login, string authServer)
+ public async Task SetAuth(CurrentAuthInfo info)
{
- SelectedAuth = new CurrentAuthInfo(guid, new LoginToken(token, DateTimeOffset.Now),
- new AuthLoginPassword(login, "", authServer));
+ SelectedAuth = info;
+ return await EnsureToken();
}
public async Task EnsureToken()
{
if (SelectedAuth is null) return false;
- var authUrl = new Uri($"{SelectedAuth.AuthLoginPassword.AuthServer}api/auth/ping");
+ var authUrl = new Uri($"{SelectedAuth.AuthServer}api/auth/ping");
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, authUrl);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("SS14Auth", SelectedAuth.Token.Token);
@@ -67,6 +73,24 @@ public class AuthService(
}
}
-public sealed record CurrentAuthInfo(Guid UserId, LoginToken Token, AuthLoginPassword AuthLoginPassword);
+public sealed record CurrentAuthInfo(Guid UserId, LoginToken Token, string Login, string AuthServer);
-public record AuthLoginPassword(string Login, string Password, string AuthServer);
\ No newline at end of file
+public record AuthLoginPassword(string Login, string Password, string AuthServer);
+
+public sealed record AuthDenyError(string[] Errors, AuthenticateDenyCode Code);
+
+public sealed class AuthException(AuthDenyError error) : Exception
+{
+ public AuthDenyError Error { get; } = error;
+}
+
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum AuthenticateDenyCode
+{
+ None = 0,
+ InvalidCredentials = 1,
+ AccountUnconfirmed = 2,
+ TfaRequired = 3,
+ TfaInvalid = 4,
+ AccountLocked = 5,
+}
diff --git a/Nebula.Shared/Services/ContentService.cs b/Nebula.Shared/Services/ContentService.cs
index c29cfe3..b5223af 100644
--- a/Nebula.Shared/Services/ContentService.cs
+++ b/Nebula.Shared/Services/ContentService.cs
@@ -17,13 +17,12 @@ public partial class ContentService(
var info = new RobustBuildInfo();
info.Url = url;
var bi = await restService.GetAsync(url.InfoUri, cancellationToken);
- if (bi.Value is null) throw new NoNullAllowedException();
- info.BuildInfo = bi.Value;
+ info.BuildInfo = bi;
info.RobustManifestInfo = info.BuildInfo.Build.Acz
? new RobustManifestInfo(new RobustPath(info.Url, "manifest.txt"), new RobustPath(info.Url, "download"),
- bi.Value.Build.ManifestHash)
+ bi.Build.ManifestHash)
: new RobustManifestInfo(new Uri(info.BuildInfo.Build.ManifestUrl),
- new Uri(info.BuildInfo.Build.ManifestDownloadUrl), bi.Value.Build.ManifestHash);
+ new Uri(info.BuildInfo.Build.ManifestDownloadUrl), bi.Build.ManifestHash);
return info;
}
diff --git a/Nebula.Shared/Services/EngineService.cs b/Nebula.Shared/Services/EngineService.cs
index b80f6fd..447f72d 100644
--- a/Nebula.Shared/Services/EngineService.cs
+++ b/Nebula.Shared/Services/EngineService.cs
@@ -40,12 +40,10 @@ public sealed class EngineService
_debugService.Log("Fetching engine manifest from: " + CurrentConVar.EngineManifestUrl);
var info = await _restService.GetAsync>(
new Uri(_varService.GetConfigValue(CurrentConVar.EngineManifestUrl)!), cancellationToken);
- if (info.Value is null)
- throw new Exception("Engine version info is null");
-
- VersionInfos = info.Value;
- _varService.SetConfigValue(CurrentConVar.EngineManifestBackup, info.Value);
+ VersionInfos = info;
+
+ _varService.SetConfigValue(CurrentConVar.EngineManifestBackup, info);
}
catch (Exception e)
{
@@ -64,11 +62,11 @@ public sealed class EngineService
var moduleInfo = await _restService.GetAsync(
new Uri(_varService.GetConfigValue(CurrentConVar.EngineModuleManifestUrl)!), cancellationToken);
- if (moduleInfo.Value is null)
+ if (moduleInfo is null)
throw new Exception("Module version info is null");
- ModuleInfos = moduleInfo.Value.Modules;
- _varService.SetConfigValue(CurrentConVar.ModuleManifestBackup, moduleInfo.Value);
+ ModuleInfos = moduleInfo.Modules;
+ _varService.SetConfigValue(CurrentConVar.ModuleManifestBackup, moduleInfo);
}
catch (Exception e)
{
@@ -177,7 +175,7 @@ public sealed class EngineService
var engineVersionObj = Version.Parse(engineVersion);
var module = ModuleInfos[moduleName];
- var selectedVersion = module.Versions.Select(kv => new { Version = Version.Parse(kv.Key), kv.Key, kv.Value })
+ var selectedVersion = module.Versions.Select(kv => new { Version = Version.Parse(kv.Key), kv.Key, kv })
.Where(kv => engineVersionObj >= kv.Version)
.MaxBy(kv => kv.Version);
diff --git a/Nebula.Shared/Services/RestService.cs b/Nebula.Shared/Services/RestService.cs
index 5273960..65bcc3b 100644
--- a/Nebula.Shared/Services/RestService.cs
+++ b/Nebula.Shared/Services/RestService.cs
@@ -23,19 +23,26 @@ public class RestService
_debug = debug;
}
- public async Task> GetAsync(Uri uri, CancellationToken cancellationToken) where T : notnull
+ public async Task GetAsync(Uri uri, CancellationToken cancellationToken) where T : notnull
{
var response = await _client.GetAsync(uri, cancellationToken);
return await ReadResult(response, cancellationToken);
}
- public async Task GetAsyncDefault(Uri uri, T defaultValue, CancellationToken cancellationToken)
+ public async Task GetAsyncDefault(Uri uri, T defaultValue, CancellationToken cancellationToken) where T : notnull
{
- var result = await GetAsync(uri, cancellationToken);
- return result.Value ?? defaultValue;
+ try
+ {
+ return await GetAsync(uri, cancellationToken);
+ }
+ catch (Exception e)
+ {
+ _debug.Error(e);
+ return defaultValue;
+ }
}
- public async Task> PostAsync(T information, Uri uri, CancellationToken cancellationToken) where K : notnull
+ public async Task PostAsync(T information, Uri uri, CancellationToken cancellationToken) where K : notnull
{
var json = JsonSerializer.Serialize(information, _serializerOptions);
var content = new StringContent(json, Encoding.UTF8, "application/json");
@@ -43,7 +50,7 @@ public class RestService
return await ReadResult(response, cancellationToken);
}
- public async Task> PostAsync(Stream stream, Uri uri, CancellationToken cancellationToken) where T : notnull
+ public async Task PostAsync(Stream stream, Uri uri, CancellationToken cancellationToken) where T : notnull
{
using var multipartFormContent =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture));
@@ -52,61 +59,32 @@ public class RestService
return await ReadResult(response, cancellationToken);
}
- public async Task> DeleteAsync(Uri uri, CancellationToken cancellationToken) where T : notnull
+ public async Task DeleteAsync(Uri uri, CancellationToken cancellationToken) where T : notnull
{
var response = await _client.DeleteAsync(uri, cancellationToken);
return await ReadResult(response, cancellationToken);
}
- private async Task> ReadResult(HttpResponseMessage response, CancellationToken cancellationToken) where T : notnull
+ private async Task ReadResult(HttpResponseMessage response, CancellationToken cancellationToken) where T : notnull
{
var content = await response.Content.ReadAsStringAsync(cancellationToken);
- if (typeof(T) == typeof(RawResult))
- return (new RestResult(new RawResult(content), null, response.StatusCode) as RestResult)!;
-
+ if (typeof(T) == typeof(string) && content is T t)
+ return t;
+
if (response.IsSuccessStatusCode)
{
_debug.Debug($"SUCCESSFUL GET CONTENT {typeof(T)}");
- return new RestResult(await response.Content.AsJson(), null,
- response.StatusCode);
+ return await response.Content.AsJson();
}
- throw new HttpRequestException();
+ throw new RestRequestException(response.Content, response.StatusCode);
}
}
-public class RestResult
+public sealed class RestRequestException(HttpContent content, HttpStatusCode statusCode) : Exception
{
- public string Message = "Ok";
- public HttpStatusCode StatusCode;
- public T Value;
-
- public RestResult(T value, string? message, HttpStatusCode statusCode)
- {
- Value = value;
- if (message != null) Message = message;
- StatusCode = statusCode;
- }
-
- public static implicit operator T(RestResult result)
- {
- return result.Value;
- }
-}
-
-public class RawResult
-{
- public string Result;
-
- public RawResult(string result)
- {
- Result = result;
- }
-
- public static implicit operator string(RawResult result)
- {
- return result.Result;
- }
+ public HttpStatusCode StatusCode { get; } = statusCode;
+ public HttpContent Content { get; } = content;
}
\ No newline at end of file