feat: 初始功能

This commit is contained in:
Shiqvlizi Name
2026-05-23 18:16:50 +08:00
parent a5bfd8792e
commit 9a51259e9e
63 changed files with 5377 additions and 1 deletions

View File

@@ -0,0 +1,138 @@
using System.IO;
using System.Text.Json;
using CloudPrint.Client.Models;
using CloudPrint.Client.Services.Abstractions;
namespace CloudPrint.Client.Services;
public sealed class JsonSettingsService : ISettingsService
{
private static readonly JsonSerializerOptions SerializerOptions = new()
{
WriteIndented = true
};
private readonly string _settingsPath;
private readonly ISecretProtector _secretProtector;
public JsonSettingsService()
: this(new DpapiSecretProtector())
{
}
public JsonSettingsService(ISecretProtector secretProtector)
: this(secretProtector, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CloudPrint.Client", "settings.json"))
{
}
public JsonSettingsService(ISecretProtector secretProtector, string settingsPath)
{
if (string.IsNullOrWhiteSpace(settingsPath))
{
throw new ArgumentException("设置文件路径不能为空", nameof(settingsPath));
}
_secretProtector = secretProtector;
_settingsPath = settingsPath;
}
public ClientSettings Load()
{
if (!File.Exists(_settingsPath))
{
return new ClientSettings();
}
try
{
var json = File.ReadAllText(_settingsPath);
var dto = JsonSerializer.Deserialize<SettingsFileDto>(json, SerializerOptions);
return dto?.ToSettings(_secretProtector) ?? new ClientSettings();
}
catch
{
return new ClientSettings();
}
}
public void Save(ClientSettings settings)
{
ArgumentNullException.ThrowIfNull(settings);
var directory = Path.GetDirectoryName(_settingsPath);
if (!string.IsNullOrWhiteSpace(directory))
{
Directory.CreateDirectory(directory);
}
var json = JsonSerializer.Serialize(SettingsFileDto.FromSettings(settings, _secretProtector), SerializerOptions);
File.WriteAllText(_settingsPath, json);
}
private sealed class SettingsFileDto
{
public string ServerAddress { get; set; } = "http://localhost:8080";
public string ApiKey { get; set; } = string.Empty; // Legacy plaintext field.
public string ProtectedApiKey { get; set; } = string.Empty;
public string AdminUsername { get; set; } = string.Empty;
public string AdminAccessToken { get; set; } = string.Empty; // Legacy plaintext field.
public string ProtectedAdminAccessToken { get; set; } = string.Empty;
public string StoreName { get; set; } = "默认打印店";
public bool AllowInsecureGrpc { get; set; } = true;
public string LibraryRoot { get; set; } = string.Empty;
public string PrintCacheRoot { get; set; } = string.Empty;
public int MaxUploadSizeMb { get; set; } = 50;
public int HeartbeatIntervalSeconds { get; set; } = 15;
public ClientSettings ToSettings(ISecretProtector protector)
{
return new ClientSettings
{
ServerAddress = ServerAddress,
ApiKey = ReadSecret(ProtectedApiKey, ApiKey, protector),
AdminUsername = AdminUsername,
AdminAccessToken = ReadSecret(ProtectedAdminAccessToken, AdminAccessToken, protector),
StoreName = StoreName,
AllowInsecureGrpc = AllowInsecureGrpc,
LibraryRoot = LibraryRoot,
PrintCacheRoot = PrintCacheRoot,
MaxUploadSizeMb = MaxUploadSizeMb,
HeartbeatIntervalSeconds = HeartbeatIntervalSeconds
};
}
public static SettingsFileDto FromSettings(ClientSettings settings, ISecretProtector protector)
{
return new SettingsFileDto
{
ServerAddress = settings.ServerAddress,
ProtectedApiKey = protector.Protect(settings.ApiKey),
AdminUsername = settings.AdminUsername,
ProtectedAdminAccessToken = protector.Protect(settings.AdminAccessToken),
StoreName = settings.StoreName,
AllowInsecureGrpc = settings.AllowInsecureGrpc,
LibraryRoot = settings.LibraryRoot,
PrintCacheRoot = settings.PrintCacheRoot,
MaxUploadSizeMb = settings.MaxUploadSizeMb,
HeartbeatIntervalSeconds = settings.HeartbeatIntervalSeconds
};
}
private static string ReadSecret(string protectedValue, string legacyPlainText, ISecretProtector protector)
{
if (string.IsNullOrWhiteSpace(protectedValue))
{
return legacyPlainText;
}
try
{
return protector.Unprotect(protectedValue);
}
catch
{
return legacyPlainText;
}
}
}
}