Add managed server profiles and account login
.NET port / test (macos-latest) (push) Canceled after 0s
.NET port / test (ubuntu-24.04) (push) Canceled after 0s
.NET port / test (windows-latest) (push) Canceled after 0s
.NET port / apple-client (push) Canceled after 0s
.NET port / cpp-conformance (push) Canceled after 0s
.NET port / test (macos-latest) (push) Canceled after 0s
.NET port / test (ubuntu-24.04) (push) Canceled after 0s
.NET port / test (windows-latest) (push) Canceled after 0s
.NET port / apple-client (push) Canceled after 0s
.NET port / cpp-conformance (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace VoiceCat.Core;
|
||||
|
||||
public enum ServerAuthentication { Guest, Account }
|
||||
|
||||
public sealed record ServerProfile(Guid Id, string Host, ushort Port, ServerAuthentication Authentication, string? Username, string? Nickname)
|
||||
{
|
||||
public static ServerProfile Create(string host, ushort port, ServerAuthentication authentication, string? username = null, string? nickname = null, Guid? id = null)
|
||||
{
|
||||
host = host.Trim(); username = Normalize(username); nickname = Normalize(nickname);
|
||||
if (host.Length == 0) throw new ArgumentException("Server host is required.", nameof(host));
|
||||
if (port == 0) throw new ArgumentOutOfRangeException(nameof(port));
|
||||
if (authentication == ServerAuthentication.Account && username is null) throw new ArgumentException("Username is required for account authentication.", nameof(username));
|
||||
return new(id.GetValueOrDefault(Guid.NewGuid()), host, port, authentication,
|
||||
authentication == ServerAuthentication.Account ? username : null,
|
||||
authentication == ServerAuthentication.Guest ? nickname : null);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string DisplayName => Authentication == ServerAuthentication.Account
|
||||
? $"{Username}@{Host}:{Port}"
|
||||
: $"{Host}:{Port} (Guest{(Nickname is null ? "" : $": {Nickname}")})";
|
||||
|
||||
internal bool IsValid => Id != Guid.Empty && !string.IsNullOrWhiteSpace(Host) && Port != 0 &&
|
||||
(Authentication == ServerAuthentication.Guest || !string.IsNullOrWhiteSpace(Username));
|
||||
|
||||
private static string? Normalize(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||
}
|
||||
|
||||
public sealed class ServerProfileStore(string path)
|
||||
{
|
||||
private static readonly JsonSerializerOptions Json = new()
|
||||
{
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public IReadOnlyList<ServerProfile> Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(path)) return [];
|
||||
return (JsonSerializer.Deserialize<ServerProfile[]>(File.ReadAllBytes(path), Json) ?? [])
|
||||
.Where(profile => profile.IsValid).ToArray();
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or JsonException) { return []; }
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<ServerProfile> profiles)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(profiles);
|
||||
ServerProfile[] valid = profiles.Where(profile => profile is not null && profile.IsValid).ToArray();
|
||||
string fullPath = Path.GetFullPath(path);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
|
||||
string temporary = fullPath + "." + Guid.NewGuid().ToString("N") + ".tmp";
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(temporary, JsonSerializer.SerializeToUtf8Bytes(valid, Json));
|
||||
File.Move(temporary, fullPath, true);
|
||||
}
|
||||
finally { if (File.Exists(temporary)) File.Delete(temporary); }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user