add nuget icon cache
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="5.3.0-1.25521.106" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="5.3.0-1.25521.106" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.3.0-1.25521.106" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.3.0-1.25521.106" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.0-rc.2.25502.107" />
|
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.0-rc.2.25502.107" />
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.0-rc.2.25502.107" />
|
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.0-rc.2.25502.107" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Razor.Utilities.Shared" Version="10.0.0-preview.25521.106" />
|
<PackageVersion Include="Microsoft.AspNetCore.Razor.Utilities.Shared" Version="10.0.0-preview.25521.106" />
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
namespace SharpIDE.Application.Features.Nuget;
|
||||||
|
|
||||||
|
public enum NugetPackageIconFormat
|
||||||
|
{
|
||||||
|
Png,
|
||||||
|
Jpg
|
||||||
|
}
|
||||||
|
public class NugetPackageIconCacheService(IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||||
|
|
||||||
|
public async Task<(byte[]? bytes, NugetPackageIconFormat?)> GetNugetPackageIcon(string packageId, Uri? iconUrl)
|
||||||
|
{
|
||||||
|
var appdataFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
var cacheFolder = Path.Combine(appdataFolderPath, "SharpIDE", "NugetPackageIconCache");
|
||||||
|
Directory.CreateDirectory(cacheFolder);
|
||||||
|
var packageIconFilePath = Path.Combine(cacheFolder, $"{packageId}.bin");
|
||||||
|
if (File.Exists(packageIconFilePath))
|
||||||
|
{
|
||||||
|
var bytes = await File.ReadAllBytesAsync(packageIconFilePath);
|
||||||
|
return (bytes, GetImageFormat(bytes));
|
||||||
|
}
|
||||||
|
else if (iconUrl is null)
|
||||||
|
{
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
var iconBytes = await httpClient.GetByteArrayAsync(iconUrl);
|
||||||
|
await File.WriteAllBytesAsync(packageIconFilePath, iconBytes);
|
||||||
|
return (iconBytes, GetImageFormat(iconBytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NugetPackageIconFormat? GetImageFormat(byte[] imageBytes)
|
||||||
|
{
|
||||||
|
// PNG files start with 89 50 4E 47 0D 0A 1A 0A
|
||||||
|
if (imageBytes is [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, ..])
|
||||||
|
{
|
||||||
|
return NugetPackageIconFormat.Png;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JPEG files start with FF D8 and end with FF D9
|
||||||
|
if (imageBytes is [0xFF, 0xD8, .., 0xFF, 0xD9])
|
||||||
|
{
|
||||||
|
return NugetPackageIconFormat.Jpg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
<PackageReference Include="LibGit2Sharp" />
|
<PackageReference Include="LibGit2Sharp" />
|
||||||
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
|
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Shared.VSCodeDebugProtocol" />
|
<PackageReference Include="Microsoft.VisualStudio.Shared.VSCodeDebugProtocol" />
|
||||||
<!-- If any Microsoft.Build.*.dll (Excluding Locator) ends up in the output, it will be prioritised for loading by MSBuild Nodes -->
|
<!-- If any Microsoft.Build.*.dll (Excluding Locator) ends up in the output, it will be prioritised for loading by MSBuild Nodes -->
|
||||||
<PackageReference Include="Ardalis.GuardClauses" />
|
<PackageReference Include="Ardalis.GuardClauses" />
|
||||||
|
|||||||
@@ -38,12 +38,15 @@ public partial class DiAutoload : Node
|
|||||||
services.AddScoped<FileChangedService>();
|
services.AddScoped<FileChangedService>();
|
||||||
services.AddScoped<DotnetUserSecretsService>();
|
services.AddScoped<DotnetUserSecretsService>();
|
||||||
services.AddScoped<NugetClientService>();
|
services.AddScoped<NugetClientService>();
|
||||||
|
services.AddScoped<NugetPackageIconCacheService>();
|
||||||
services.AddScoped<IdeFileWatcher>();
|
services.AddScoped<IdeFileWatcher>();
|
||||||
services.AddScoped<IdeNavigationHistoryService>();
|
services.AddScoped<IdeNavigationHistoryService>();
|
||||||
services.AddScoped<IdeOpenTabsFileManager>();
|
services.AddScoped<IdeOpenTabsFileManager>();
|
||||||
services.AddScoped<RoslynAnalysis>();
|
services.AddScoped<RoslynAnalysis>();
|
||||||
services.AddScoped<IdeFileOperationsService>();
|
services.AddScoped<IdeFileOperationsService>();
|
||||||
services.AddScoped<SharpIdeSolutionModificationService>();
|
services.AddScoped<SharpIdeSolutionModificationService>();
|
||||||
|
|
||||||
|
services.AddHttpClient();
|
||||||
services.AddLogging(builder =>
|
services.AddLogging(builder =>
|
||||||
{
|
{
|
||||||
builder.AddConsole();
|
builder.AddConsole();
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public partial class PackageEntry : MarginContainer
|
|||||||
private static readonly Color Source_4_Color = new Color("966a00");
|
private static readonly Color Source_4_Color = new Color("966a00");
|
||||||
private static readonly Color Source_5_Color = new Color("efaeae");
|
private static readonly Color Source_5_Color = new Color("efaeae");
|
||||||
|
|
||||||
|
[Inject] private readonly NugetPackageIconCacheService _nugetPackageIconCacheService = null!;
|
||||||
|
|
||||||
public IdePackageResult PackageResult { get; set; } = null!;
|
public IdePackageResult PackageResult { get; set; } = null!;
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -35,26 +37,24 @@ public partial class PackageEntry : MarginContainer
|
|||||||
_currentVersionLabel.Text = string.Empty;
|
_currentVersionLabel.Text = string.Empty;
|
||||||
//_latestVersionLabel.Text = $"Latest: {PackageResult.PackageSearchMetadata.vers.LatestVersion}";
|
//_latestVersionLabel.Text = $"Latest: {PackageResult.PackageSearchMetadata.vers.LatestVersion}";
|
||||||
_sourceNamesContainer.QueueFreeChildren();
|
_sourceNamesContainer.QueueFreeChildren();
|
||||||
|
|
||||||
var iconUrl = PackageResult.PackageSearchMetadata.IconUrl;
|
_ = Task.GodotRun(async () =>
|
||||||
if (iconUrl != null)
|
|
||||||
{
|
{
|
||||||
var httpRequest = new HttpRequest(); // Godot's abstraction
|
var (iconBytes, iconFormat) = await _nugetPackageIconCacheService.GetNugetPackageIcon(PackageResult.PackageSearchMetadata.Identity.Id, PackageResult.PackageSearchMetadata.IconUrl);
|
||||||
AddChild(httpRequest);
|
var image = new Image();
|
||||||
httpRequest.RequestCompleted += (result, responseCode, headers, body) =>
|
var error = iconFormat switch
|
||||||
{
|
{
|
||||||
if (responseCode is 200)
|
NugetPackageIconFormat.Png => image.LoadPngFromBuffer(iconBytes),
|
||||||
{
|
NugetPackageIconFormat.Jpg => image.LoadJpgFromBuffer(iconBytes),
|
||||||
var image = new Image();
|
_ => Error.FileUnrecognized
|
||||||
image.LoadPngFromBuffer(body);
|
|
||||||
image.Resize(32, 32, Image.Interpolation.Lanczos);
|
|
||||||
var loadedImageTexture = ImageTexture.CreateFromImage(image);
|
|
||||||
_packageIconTextureRect.Texture = loadedImageTexture;
|
|
||||||
}
|
|
||||||
httpRequest.QueueFree();
|
|
||||||
};
|
};
|
||||||
httpRequest.Request(iconUrl.ToString());
|
if (error is Error.Ok)
|
||||||
}
|
{
|
||||||
|
image.Resize(32, 32, Image.Interpolation.Lanczos); // Probably should cache resized images instead
|
||||||
|
var loadedImageTexture = ImageTexture.CreateFromImage(image);
|
||||||
|
await this.InvokeAsync(() => _packageIconTextureRect.Texture = loadedImageTexture);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var source in PackageResult.PackageSources)
|
foreach (var source in PackageResult.PackageSources)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<ProjectReference Include="..\SharpIDE.Application\SharpIDE.Application.csproj" />
|
<ProjectReference Include="..\SharpIDE.Application\SharpIDE.Application.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||||
<PackageReference Include="ObservableCollections" />
|
<PackageReference Include="ObservableCollections" />
|
||||||
<PackageReference Include="ObservableCollections.R3" />
|
<PackageReference Include="ObservableCollections.R3" />
|
||||||
|
|||||||
Reference in New Issue
Block a user