settings_re9

This commit is contained in:
lincube
2026-03-14 23:52:26 +08:00
parent 689be7b585
commit 85b70c4a8a
20 changed files with 1190 additions and 146 deletions

View File

@@ -7,7 +7,7 @@ using Avalonia.Media.Imaging;
namespace LanMountainDesktop.Services.PluginMarket;
internal sealed class AirAppMarketIconService : IDisposable
public sealed class AirAppMarketIconService : IDisposable
{
private readonly HttpClient _httpClient;
@@ -20,7 +20,7 @@ internal sealed class AirAppMarketIconService : IDisposable
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0");
}
public async Task<Bitmap> LoadAsync(
internal async Task<Bitmap> LoadAsync(
AirAppMarketPluginEntry plugin,
CancellationToken cancellationToken = default)
{
@@ -40,6 +40,26 @@ internal sealed class AirAppMarketIconService : IDisposable
return new Bitmap(memory);
}
public async Task<Bitmap> LoadAsync(
LanMountainDesktop.Services.Settings.PluginMarketPluginInfo plugin,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(plugin);
if (AirAppMarketDefaults.TryResolveWorkspaceFile(plugin.IconUrl, out var localIconPath))
{
return new Bitmap(localIconPath);
}
using var response = await _httpClient.GetAsync(plugin.IconUrl, cancellationToken);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
using var memory = new MemoryStream();
await stream.CopyToAsync(memory, cancellationToken);
memory.Position = 0;
return new Bitmap(memory);
}
public void Dispose()
{
_httpClient.Dispose();

View File

@@ -438,6 +438,29 @@ internal sealed class AirAppMarketSharedContractEntry
}
}
internal sealed class AirAppMarketPluginDependencyEntry
{
public string Id { get; init; } = string.Empty;
public string Version { get; init; } = string.Empty;
public string AssemblyName { get; init; } = string.Empty;
public AirAppMarketPluginDependencyEntry ValidateAndNormalize(string sourceName)
{
return new AirAppMarketPluginDependencyEntry
{
Id = AirAppMarketIndexDocument.NormalizeValue(Id)
?? throw new InvalidOperationException(
$"Market index '{sourceName}' is missing dependency id for a plugin entry."),
Version = AirAppMarketIndexDocument.NormalizeVersion(Version, nameof(Version), sourceName),
AssemblyName = AirAppMarketIndexDocument.NormalizeValue(AssemblyName)
?? throw new InvalidOperationException(
$"Market index '{sourceName}' is missing assemblyName for dependency '{Id}'.")
};
}
}
internal sealed class AirAppMarketPluginEntry
{
public string Id { get; init; } = string.Empty;
@@ -476,6 +499,8 @@ internal sealed class AirAppMarketPluginEntry
public List<string> Tags { get; init; } = [];
public List<AirAppMarketPluginDependencyEntry> SharedContracts { get; init; } = [];
public DateTimeOffset PublishedAt { get; init; }
public DateTimeOffset UpdatedAt { get; init; }
@@ -495,6 +520,21 @@ internal sealed class AirAppMarketPluginEntry
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(tag => tag, StringComparer.OrdinalIgnoreCase)
.ToList();
var normalizedDependencies = new List<AirAppMarketPluginDependencyEntry>((SharedContracts ?? []).Count);
var seenDependencies = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var dependency in SharedContracts ?? [])
{
var normalizedDependency = dependency.ValidateAndNormalize(sourceName);
var dependencyKey = $"{normalizedDependency.Id}@{normalizedDependency.Version}";
if (!seenDependencies.Add(dependencyKey))
{
throw new InvalidOperationException(
$"Market index '{sourceName}' declares duplicate dependency '{dependencyKey}' for plugin '{Id}'.");
}
normalizedDependencies.Add(normalizedDependency);
}
var normalizedSha = AirAppMarketIndexDocument.NormalizeValue(Sha256)?.ToLowerInvariant()
?? throw new InvalidOperationException(
@@ -590,6 +630,7 @@ internal sealed class AirAppMarketPluginEntry
HomepageUrl = normalizedHomepageUrl,
RepositoryUrl = normalizedRepositoryUrl,
Tags = normalizedTags,
SharedContracts = normalizedDependencies,
PublishedAt = PublishedAt,
UpdatedAt = UpdatedAt,
ReleaseNotes = AirAppMarketIndexDocument.NormalizeValue(ReleaseNotes)

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace LanMountainDesktop.Services.PluginMarket;
internal sealed class AirAppMarketReadmeService : IDisposable
public sealed class AirAppMarketReadmeService : IDisposable
{
private readonly HttpClient _httpClient;
@@ -19,7 +19,7 @@ internal sealed class AirAppMarketReadmeService : IDisposable
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LanMountainDesktop-PluginMarketplace/1.0");
}
public async Task<string> LoadAsync(
internal async Task<string> LoadAsync(
AirAppMarketPluginEntry plugin,
CancellationToken cancellationToken = default)
{
@@ -35,6 +35,22 @@ internal sealed class AirAppMarketReadmeService : IDisposable
return await response.Content.ReadAsStringAsync(cancellationToken);
}
public async Task<string> LoadAsync(
LanMountainDesktop.Services.Settings.PluginMarketPluginInfo plugin,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(plugin);
if (AirAppMarketDefaults.TryResolveWorkspaceFile(plugin.ReadmeUrl, out var localReadmePath))
{
return await File.ReadAllTextAsync(localReadmePath, cancellationToken);
}
using var response = await _httpClient.GetAsync(plugin.ReadmeUrl, cancellationToken);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(cancellationToken);
}
public void Dispose()
{
_httpClient.Dispose();