diff --git a/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs b/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs
index af8023774..9502afb1b 100644
--- a/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs
+++ b/src/UniGetUI.Core.IconEngine.Tests/IconCacheEngineTests.cs
@@ -4,33 +4,58 @@ namespace UniGetUI.Core.IconEngine.Tests
{
public static class IconCacheEngineTests
{
- [Theory]
- [InlineData("https://marticliment.com/resources/wingetui.png",
- new byte[] { 0x24, 0x4e, 0x42, 0xb6, 0xbe, 0x44, 0x04, 0x66, 0xc8, 0x77, 0xf7, 0x68, 0x8a, 0xe0, 0xa9, 0x45, 0xfb, 0x2e, 0x66, 0x8c, 0x41, 0x84, 0x1f, 0x2d, 0x10, 0xcf, 0x92, 0xd4, 0x0d, 0x8c, 0xbb, 0xf6 },
- "TestManager", "Package1")]
- public static async Task TestCacheEngineForSha256(string url, byte[] data, string managerName, string packageId)
+ [Fact]
+ public static async Task TestCacheEngineForSha256()
{
- string extension = url.Split(".")[^1];
+ Uri ICON_1 = new Uri("https://marticliment.com/resources/wingetui.png");
+ byte[] HASH_1 = [0x24, 0x4e, 0x42, 0xb6, 0xbe, 0x44, 0x04, 0x66, 0xc8, 0x77, 0xf7, 0x68, 0x8a, 0xe0, 0xa9, 0x45, 0xfb, 0x2e, 0x66, 0x8c, 0x41, 0x84, 0x1f, 0x2d, 0x10, 0xcf, 0x92, 0xd4, 0x0d, 0x8c, 0xbb, 0xf6];
+ Uri ICON_2 = new Uri("https://marticliment.com/resources/elevenclock.png");
+ byte[] HASH_2 = [0x9E, 0xB8, 0x7A, 0x5A, 0x64, 0xCA, 0x6D, 0x8D, 0x0A, 0x7B, 0x98, 0xC5, 0x4F, 0x6A, 0x58, 0x72, 0xFD, 0x94, 0xC9, 0xA6, 0x82, 0xB3, 0x2B, 0x90, 0x70, 0x66, 0x66, 0x1C, 0xBF, 0x81, 0x97, 0x97];
+
+ string managerName = "TestManager";
+ string packageId = "Package55";
+
+ string extension = ICON_1.ToString().Split(".")[^1];
string expectedFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, managerName, packageId + "." + extension);
if (File.Exists(expectedFile))
{
File.Delete(expectedFile);
}
- CacheableIcon icon = new(new Uri(url), data);
- string path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ // Download a hashed icon
+ CacheableIcon icon = new(ICON_1, HASH_1);
+ string? path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
DateTime oldModificationDate = File.GetLastWriteTime(path);
- icon = new CacheableIcon(new Uri(url.Replace("icon", "nonexistingicon")), data);
- path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ // Test the same icon, modification date shouldn't change
+ icon = new CacheableIcon(ICON_1, HASH_1);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
DateTime newModificationDate = File.GetLastWriteTime(path);
Assert.Equal(oldModificationDate, newModificationDate);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
+
+ // Attempt to retrieve a different icon. The modification date SHOULD have changed
+ icon = new CacheableIcon(ICON_2, HASH_2);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
+ DateTime newIconModificationDate = File.GetLastWriteTime(path);
+
+ Assert.NotEqual(oldModificationDate, newIconModificationDate);
+ Assert.Equal(expectedFile, path);
+ Assert.True(File.Exists(path));
+
+ // Give an invalid hash: The icon should not be cached not returned
+ icon = new CacheableIcon(ICON_2, HASH_1);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.Null(path);
+ Assert.False(File.Exists(path));
}
[Theory]
@@ -44,23 +69,29 @@ public static async Task TestCacheEngineForPackageVersion(string url, string ver
File.Delete(expectedFile);
}
+ // Download an icon through version verification
CacheableIcon icon = new(new Uri(url), version);
- string path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ string? path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
DateTime oldModificationDate = File.GetLastWriteTime(path);
+ // Test the same version, the icon should not get touched
icon = new CacheableIcon(new Uri(url), version);
- path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
DateTime newModificationDate = File.GetLastWriteTime(path);
Assert.Equal(oldModificationDate, newModificationDate);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
+ // Test a new version, the icon should be downloaded again
icon = new CacheableIcon(new Uri(url), version + "-beta0");
- path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
DateTime newNewModificationDate = File.GetLastWriteTime(path);
Assert.NotEqual(oldModificationDate, newNewModificationDate);
@@ -68,39 +99,104 @@ public static async Task TestCacheEngineForPackageVersion(string url, string ver
Assert.True(File.Exists(path));
}
- [Theory]
- [InlineData("https://marticliment.com/resources/wingetui.png", 47903, "TestManager", "Package3")]
- public static async Task TestCacheEngineForPackageSize(string url, long size, string managerName, string packageId)
+ [Fact]
+ public static async Task TestCacheEngineForIconUri()
{
- string extension = url.Split(".")[^1];
+ Uri URI_1 = new Uri("https://marticliment.com/resources/wingetui.png");
+ Uri URI_2 = new Uri("https://marticliment.com/resources/elevenclock.png");
+ string managerName = "TestManager";
+ string packageId = "Package12";
+
+ string extension = URI_1.ToString().Split(".")[^1];
string expectedFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, managerName, packageId + "." + extension);
if (File.Exists(expectedFile))
{
File.Delete(expectedFile);
}
- CacheableIcon icon = new(new Uri(url), size);
- string path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ // Download an icon through URI verification
+ CacheableIcon icon = new(URI_1);
+ string? path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
DateTime oldModificationDate = File.GetLastWriteTime(path);
- icon = new CacheableIcon(new Uri(url), size);
- path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ // Test the same URI, the icon should not get touched
+ icon = new CacheableIcon(URI_1);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
DateTime newModificationDate = File.GetLastWriteTime(path);
Assert.Equal(oldModificationDate, newModificationDate);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
- icon = new CacheableIcon(new Uri(url), size + 1);
- path = await IconCacheEngine.DownloadIconOrCache(icon, managerName, packageId);
+ // Test a new URI, the icon should be downloaded again
+ icon = new CacheableIcon(URI_2);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
DateTime newNewModificationDate = File.GetLastWriteTime(path);
Assert.NotEqual(oldModificationDate, newNewModificationDate);
Assert.Equal(expectedFile, path);
Assert.True(File.Exists(path));
}
+
+ [Fact]
+ public static async Task TestCacheEngineForPackageSize()
+ {
+ Uri ICON_1 = new Uri("https://marticliment.com/resources/wingetui.png");
+ int ICON_1_SIZE = 47903;
+ Uri ICON_2 = new Uri("https://marticliment.com/resources/elevenclock.png");
+ int ICON_2_SIZE = 19747;
+ string managerName = "TestManager";
+ string packageId = "Package3";
+
+ // Clear any cache for reproducable data
+ string extension = ICON_1.ToString().Split(".")[^1];
+ string expectedFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, managerName, packageId + "." + extension);
+ if (File.Exists(expectedFile))
+ {
+ File.Delete(expectedFile);
+ }
+
+ // Cache an icon
+ CacheableIcon icon = new(ICON_1, ICON_1_SIZE);
+ string? path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
+ Assert.Equal(expectedFile, path);
+ Assert.True(File.Exists(path));
+
+ DateTime oldModificationDate = File.GetLastWriteTime(path);
+
+ // Attempt to retrieve the same icon again.
+ icon = new CacheableIcon(ICON_1, ICON_1_SIZE);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
+ DateTime newModificationDate = File.GetLastWriteTime(path);
+
+ // The modification date shouldn't have changed
+ Assert.Equal(oldModificationDate, newModificationDate);
+ Assert.Equal(expectedFile, path);
+ Assert.True(File.Exists(path));
+
+ // Attempt to retrieve a different icon. The modification date SHOULD have changed
+ icon = new CacheableIcon(ICON_2, ICON_2_SIZE);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.NotNull(path);
+ DateTime newIconModificationDate = File.GetLastWriteTime(path);
+
+ Assert.NotEqual(oldModificationDate, newIconModificationDate);
+ Assert.Equal(expectedFile, path);
+ Assert.True(File.Exists(path));
+
+ // Give an invalid size: The icon should not be cached not returned
+ icon = new CacheableIcon(ICON_1, ICON_1_SIZE + 1);
+ path = await IconCacheEngine.GetCacheOrDownloadIcon(icon, managerName, packageId);
+ Assert.Null(path);
+ Assert.False(File.Exists(path));
+ }
}
}
diff --git a/src/UniGetUI.Core.IconStore/IconCacheEngine.cs b/src/UniGetUI.Core.IconStore/IconCacheEngine.cs
index 27ca6b6f7..228bfb8a5 100644
--- a/src/UniGetUI.Core.IconStore/IconCacheEngine.cs
+++ b/src/UniGetUI.Core.IconStore/IconCacheEngine.cs
@@ -5,10 +5,9 @@
namespace UniGetUI.Core.IconEngine
{
- public enum CachedIconVerificationMethod
+ public enum IconValidationMethod
{
- None,
- Sha256Checksum,
+ SHA256,
FileSize,
PackageVersion,
UriSource
@@ -17,36 +16,55 @@ public enum CachedIconVerificationMethod
public readonly struct CacheableIcon
{
public readonly Uri Url;
- public readonly byte[] Sha256 = [];
+ public readonly byte[] SHA256 = [];
public readonly string Version = "";
public readonly long Size = -1;
- public readonly CachedIconVerificationMethod VerificationMethod;
+ public readonly IconValidationMethod ValidationMethod;
+ ///
+ /// Build a cacheable icon with SHA256 verification
+ ///
+ ///
+ ///
public CacheableIcon(Uri uri, byte[] Sha256)
{
Url = uri;
- this.Sha256 = Sha256;
- VerificationMethod = CachedIconVerificationMethod.Sha256Checksum;
+ this.SHA256 = Sha256;
+ ValidationMethod = IconValidationMethod.SHA256;
}
+ ///
+ /// Build a cacheable icon with Version verification
+ ///
+ ///
+ ///
public CacheableIcon(Uri uri, string version)
{
Url = uri;
Version = version;
- VerificationMethod = CachedIconVerificationMethod.PackageVersion;
+ ValidationMethod = IconValidationMethod.PackageVersion;
}
+ ///
+ /// Build a cacheable icon with Size verification
+ ///
+ ///
+ ///
public CacheableIcon(Uri uri, long size)
{
Url = uri;
Size = size;
- VerificationMethod = CachedIconVerificationMethod.FileSize;
+ ValidationMethod = IconValidationMethod.FileSize;
}
+ ///
+ /// Build a cacheable icon with Uri verification
+ ///
+ ///
public CacheableIcon(Uri icon)
{
Url = icon;
- VerificationMethod = CachedIconVerificationMethod.UriSource;
+ ValidationMethod = IconValidationMethod.UriSource;
}
}
@@ -59,11 +77,11 @@ public static class IconCacheEngine
/// The name of the PackageManager
/// the Id of the package
/// A path to a local icon file
- public static async Task DownloadIconOrCache(CacheableIcon? _icon, string ManagerName, string PackageId)
+ public static async Task GetCacheOrDownloadIcon(CacheableIcon? _icon, string ManagerName, string PackageId)
{
if (_icon is null)
{
- return "";
+ return null;
}
var icon = (CacheableIcon)_icon;
@@ -76,121 +94,182 @@ public static async Task DownloadIconOrCache(CacheableIcon? _icon, strin
extension = "png";
}
- string FilePath = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}");
- string VersionPath = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}.version");
- string UriPath = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}.uri");
- string FileDirectory = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName);
- if (!Directory.Exists(FileDirectory))
+ string cachedIconFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}");
+ string iconVersionFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}.version");
+ string iconUriFile = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName, $"{PackageId}.{extension}.uri");
+ string iconLocation = Path.Join(CoreData.UniGetUICacheDirectory_Icons, ManagerName);
+ if (!Directory.Exists(iconLocation))
{
- Directory.CreateDirectory(FileDirectory);
+ Directory.CreateDirectory(iconLocation);
}
- bool FileExists = File.Exists(FilePath);
- bool IsFileValid = false;
- if (FileExists)
+ // Verify if the cached icon is valid
+ bool isLocalCacheValid = false;
+ bool localCacheExists = File.Exists(cachedIconFile);
+ if (localCacheExists)
{
- switch (icon.VerificationMethod)
- {
- case CachedIconVerificationMethod.FileSize:
- try
- {
- long size = await CoreTools.GetFileSizeAsyncAsLong(icon.Url);
- IsFileValid = size == icon.Size;
- }
- catch (Exception e)
- {
- Logger.Warn($"Failed to verify icon file size for {icon.Url} through FileSize with error {e.Message}");
- }
- break;
-
- case CachedIconVerificationMethod.Sha256Checksum:
- try
- {
- byte[] hash = await CalculateFileHashAsync(FilePath);
- IsFileValid = hash.SequenceEqual(icon.Sha256);
- }
- catch (Exception e)
- {
- Logger.Warn($"Failed to verify icon file size for {icon.Url} through Sha256 with error {e.Message}");
- }
- break;
-
- case CachedIconVerificationMethod.PackageVersion:
- try
- {
- if (File.Exists(VersionPath))
- {
- string localVersion = File.ReadAllText(VersionPath);
- IsFileValid = localVersion == icon.Version;
- }
- }
- catch (Exception e)
- {
- Logger.Warn($"Failed to verify icon file size for {icon.Url} through PackageVersion with error {e.Message}");
- }
- break;
-
- case CachedIconVerificationMethod.UriSource:
- try
- {
- if (File.Exists(UriPath))
- {
- string localVersion = File.ReadAllText(UriPath);
- IsFileValid = localVersion == icon.Url.ToString();
- }
- }
- catch (Exception e)
- {
- Logger.Warn($"Failed to verify icon file size for {icon.Url} through UriSource with error {e.Message}");
- }
- break;
-
- default:
- Logger.ImportantInfo($"Icon {icon.Url} for package {PackageId} on manager {ManagerName} does not use a valid cache verification method");
- IsFileValid = true;
- break;
- }
- }
-
- Logger.Debug($"Icon for package {PackageId} on manager {ManagerName} with Uri={icon.Url} has been determined to be {(IsFileValid ? "VALID" : "INVALID")} through verification method {icon.VerificationMethod}");
-
- if (!IsFileValid)
- {
- using HttpClient client = new(CoreData.GenericHttpClientParameters);
- client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);
- if (File.Exists(FilePath))
+ isLocalCacheValid = icon.ValidationMethod switch
{
- File.Delete(FilePath);
- }
+ IconValidationMethod.FileSize => ValidateByImageSize(icon, cachedIconFile),
+ IconValidationMethod.SHA256 => await ValidateBySHA256(icon, cachedIconFile),
+ IconValidationMethod.PackageVersion => await ValidateByVersion(icon, iconVersionFile),
+ IconValidationMethod.UriSource => await ValidateByUri(icon, iconUriFile),
+ _ => throw new InvalidDataException("Invalid icon validation method"),
+ };
+ }
- HttpResponseMessage response = await client.GetAsync(icon.Url);
- response.EnsureSuccessStatusCode();
- using (Stream stream = await response.Content.ReadAsStreamAsync())
- using (FileStream fileStream = File.Create(FilePath))
- {
- await stream.CopyToAsync(fileStream);
- }
+ // If a valid cache was found, return that cache
+ if (isLocalCacheValid)
+ {
+ Logger.Debug($"Icon for package {PackageId} is VALID and won't be downloaded again (verification method is {icon.ValidationMethod})");
+ return cachedIconFile;
+ // Exit the function
+ }
+ else if (localCacheExists)
+ {
+ Logger.ImportantInfo($"Icon for Package={PackageId} Manager={ManagerName} Uri={icon.Url} is NOT VALID (verification method is {icon.ValidationMethod})");
+ }
+ else
+ {
+ Logger.Debug($"Icon for package {PackageId} on manager {ManagerName} was not found on cache, downloading it...");
+ }
- if (icon.VerificationMethod == CachedIconVerificationMethod.PackageVersion)
- {
- await File.WriteAllTextAsync(VersionPath, icon.Version);
- }
+ // If the cache is determined to NOT be valid, delete cache
+ DeteteCachedFiles(cachedIconFile, iconVersionFile, iconUriFile);
- if (icon.VerificationMethod == CachedIconVerificationMethod.UriSource)
- {
- await File.WriteAllTextAsync(UriPath, icon.Url.ToString());
- }
+ // After discarding the cache, regenerate it
+ using HttpClient client = new(CoreData.GenericHttpClientParameters);
+ client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);
+ HttpResponseMessage response = await client.GetAsync(icon.Url);
+ response.EnsureSuccessStatusCode();
+ using (Stream stream = await response.Content.ReadAsStreamAsync())
+ using (FileStream fileStream = File.Create(cachedIconFile))
+ {
+ await stream.CopyToAsync(fileStream);
}
- Logger.Info($"Icon for package {PackageId} stored on {FilePath}");
- return FilePath;
+ if (icon.ValidationMethod is IconValidationMethod.PackageVersion)
+ await File.WriteAllTextAsync(iconVersionFile, icon.Version);
+
+ if (icon.ValidationMethod is IconValidationMethod.UriSource)
+ await File.WriteAllTextAsync(iconUriFile, icon.Url.ToString());
+
+ Logger.Info($"Icon for package {PackageId} stored on {cachedIconFile}");
+
+ // Ensure the new icon has been properly downloaded
+ bool isNewCacheValid = icon.ValidationMethod switch
+ {
+ IconValidationMethod.FileSize => ValidateByImageSize(icon, cachedIconFile),
+ IconValidationMethod.SHA256 => await ValidateBySHA256(icon, cachedIconFile),
+ IconValidationMethod.PackageVersion => true, // The validation result would be always true
+ IconValidationMethod.UriSource => true, // The validation result would be always true
+ _ => throw new InvalidDataException("Invalid icon validation method"),
+ };
+
+ if (isNewCacheValid)
+ {
+ Logger.Info($"NEWLY DOWNLOADED Icon for Package={PackageId} Manager={ManagerName} Uri={icon.Url} is VALID (verification method is {icon.ValidationMethod})");
+ return cachedIconFile;
+ }
+ else
+ {
+ Logger.Warn($"NEWLY DOWNLOADED Icon for Pacakge={PackageId} Manager={ManagerName} Uri={icon.Url} is NOT VALID and will be discarded (verification method is {icon.ValidationMethod})");
+ DeteteCachedFiles(cachedIconFile, iconVersionFile, iconUriFile);
+ return null;
+ }
}
- private static async Task CalculateFileHashAsync(string filePath)
+ ///
+ /// Checks whether a cached image is valid or not depending on the size (in bytes) of the image
+ ///
+ ///
+ ///
+ ///
+ private static bool ValidateByImageSize(CacheableIcon icon, string cachedIconPath)
{
- using FileStream stream = File.OpenRead(filePath);
- using SHA256 sha256 = SHA256.Create();
- return await sha256.ComputeHashAsync(stream);
+ try
+ {
+ FileInfo fileInfo = new FileInfo(cachedIconPath);
+ return icon.Size == fileInfo.Length;
+ }
+ catch (Exception e)
+ {
+ Logger.Warn($"Failed to verify icon file size for {icon.Url} via FileSize with error {e.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Checks whether a cached image is valid or not depending on its SHA256 hash
+ ///
+ ///
+ ///
+ ///
+ private static async Task ValidateBySHA256(CacheableIcon icon, string cachedIconPath)
+ {
+ try
+ {
+ using FileStream stream = File.OpenRead(cachedIconPath);
+ using SHA256 sha256 = SHA256.Create();
+ return (await sha256.ComputeHashAsync(stream)).SequenceEqual(icon.SHA256);
+ }
+ catch (Exception e)
+ {
+ Logger.Warn($"Failed to verify icon file size for {icon.Url} via Sha256 with error {e.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Checks whether a cached image is valid or not depending on the package version it was pulled from
+ ///
+ ///
+ ///
+ ///
+ private static async Task ValidateByVersion(CacheableIcon icon, string versionPath)
+ {
+ try
+ {
+ return File.Exists(versionPath) && (await File.ReadAllTextAsync(versionPath)) == icon.Version;
+ }
+ catch (Exception e)
+ {
+ Logger.Warn($"Failed to verify icon file size for {icon.Url} via PackageVersion with error {e.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// Checks whether a cached image is valid or not depending on the URI it was pulled from
+ ///
+ ///
+ ///
+ ///
+ private static async Task ValidateByUri(CacheableIcon icon, string uriPath)
+ {
+ try
+ {
+ return File.Exists(uriPath) && (await File.ReadAllTextAsync(uriPath)) == icon.Url.ToString();
+ }
+ catch (Exception e)
+ {
+ Logger.Warn($"Failed to verify icon file size for {icon.Url} via UriSource with error {e.Message}");
+ return false;
+ }
+ }
+
+ private static void DeteteCachedFiles(string iconFile, string versionFile, string uriFile)
+ {
+ try
+ {
+ if (File.Exists(iconFile)) File.Delete(iconFile);
+ if (File.Exists(versionFile)) File.Delete(versionFile);
+ if (File.Exists(uriFile)) File.Delete(uriFile);
+ }
+ catch (Exception e)
+ {
+ Logger.Warn($"An error occurred while deleting old icon cache: {e.Message}");
+ }
}
}
}
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Providers/WinGetPackageDetailsProvider.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Providers/WinGetPackageDetailsProvider.cs
index b9027ec6c..8db36f951 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/Providers/WinGetPackageDetailsProvider.cs
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Providers/WinGetPackageDetailsProvider.cs
@@ -39,9 +39,9 @@ protected override void GetDetails_UnSafe(IPackageDetails details)
return GetMicrosoftStoreIcon(package);
}
- Logger.Warn("Non-MSStore WinGet Native Icons have been forcefully disabled on code");
- return null;
- //return await GetWinGetPackageIcon(package);
+ // Logger.Warn("Non-MSStore WinGet Native Icons have been forcefully disabled on code");
+ // return null;
+ return GetWinGetPackageIcon(package);
}
protected override IEnumerable GetScreenshots_UnSafe(IPackage package)
@@ -222,7 +222,6 @@ protected override IEnumerable GetScreenshots_UnSafe(IPackage package)
return new CacheableIcon(new Uri(uri));
}
- // TODO: Need to work on retrieving WinGet icons
private static CacheableIcon? GetWinGetPackageIcon(IPackage package)
{
if (WinGetHelper.Instance is not NativeWinGetHelper)
@@ -245,7 +244,6 @@ protected override IEnumerable GetScreenshots_UnSafe(IPackage package)
// Connect to catalog
Catalog.AcceptSourceAgreements = true;
ConnectResult ConnectResult = Catalog.Connect();
- // ConnectResult ConnectResult = await Catalog.ConnectAsync();
if (ConnectResult.Status != ConnectResultStatus.Ok)
{
Logger.Error("[WINGET COM] Failed to connect to catalog " + package.Source.Name);
@@ -264,7 +262,7 @@ protected override IEnumerable GetScreenshots_UnSafe(IPackage package)
if (SearchResult.Matches is null || SearchResult.Matches.Count == 0)
{
- Logger.Error("[WINGET COM] Failed to find package " + package.Id + " in catalog " + package.Source.Name);
+ Logger.Error($"[WINGET COM] Package with Id={package.Id} was NOT found in catalog id=" + package.Source.Name);
return null;
}
@@ -274,15 +272,18 @@ protected override IEnumerable GetScreenshots_UnSafe(IPackage package)
// Extract data from NativeDetails
CatalogPackageMetadata NativeDetails = NativePackage.DefaultInstallVersion.GetCatalogPackageMetadata();
- CacheableIcon? Icon = null;
-
+ // Get the actual icon and return it
foreach (Icon? icon in NativeDetails.Icons.ToArray())
{
- Icon = new CacheableIcon(new Uri(icon.Url), icon.Sha256);
- Logger.Debug($"Found WinGet native icon for {package.Id} with URL={icon.Url}");
+ if (icon is not null && icon.Url is not null)
+ {
+ Logger.Debug($"Found WinGet native icon for {package.Id} with URL={icon.Url}");
+ return new CacheableIcon(new Uri(icon.Url), icon.Sha256);
+ }
}
- return Icon;
+ Logger.Debug($"Native WinGet icon for Package={package.Id} on catalog={package.Source.Name} was not found :(");
+ return null;
}
}
}
diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs
index ebe1d8977..a8632a0d5 100644
--- a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs
+++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Package.cs
@@ -178,11 +178,11 @@ public virtual Uri GetIconUrl()
try
{
CacheableIcon? icon = Manager.GetPackageIconUrl(this);
- string path = IconCacheEngine.DownloadIconOrCache(icon, Manager.Name, Id).GetAwaiter().GetResult();
+ string? path = IconCacheEngine.GetCacheOrDownloadIcon(icon, Manager.Name, Id).GetAwaiter().GetResult();
Uri Icon;
- if (path == "") Icon = new Uri("ms-appx:///Assets/Images/package_color.png");
- else Icon = new Uri("file:///" + path);
+ if (path is null) Icon = new Uri("ms-appx:///Assets/Images/package_color.png");
+ else Icon = new Uri("file:///" + path);
Logger.Debug($"Icon for package {Id} was loaded from {Icon}");
return Icon;
diff --git a/src/UniGetUI/Pages/SettingsPage.xaml b/src/UniGetUI/Pages/SettingsPage.xaml
index 8e79db45a..6d94b0395 100644
--- a/src/UniGetUI/Pages/SettingsPage.xaml
+++ b/src/UniGetUI/Pages/SettingsPage.xaml
@@ -89,9 +89,15 @@
ButtonText="Export"
Click="ExportSettings"
/>
+
diff --git a/src/UniGetUI/Pages/SettingsPage.xaml.cs b/src/UniGetUI/Pages/SettingsPage.xaml.cs
index f194dce6b..a326392df 100644
--- a/src/UniGetUI/Pages/SettingsPage.xaml.cs
+++ b/src/UniGetUI/Pages/SettingsPage.xaml.cs
@@ -312,20 +312,20 @@ void EnableOrDisableEntries()
EnableOrDisableEntries();
MainLayout.Children.Add(ManagerExpander);
- }
- }
- public MainWindow GetWindow()
- {
- return MainApp.Instance.MainWindow;
- }
- public int GetHwnd()
- {
- return (int)WinRT.Interop.WindowNative.GetWindowHandle(GetWindow());
+ LoadIconCacheSize();
+ }
}
- private void OpenWelcomeWizard(object sender, EventArgs e)
+ private async void LoadIconCacheSize()
{
+ double realSize = (await Task.Run(() =>
+ {
+ return Directory.GetFiles(CoreData.UniGetUICacheDirectory_Icons, "*", SearchOption.AllDirectories)
+ .Sum(file => new FileInfo(file).Length);
+ })) / 1048576d;
+ double roundedSize = ((int)(realSize*100))/100d;
+ ResetIconCache.Header = CoreTools.Translate("The local icon cache currently takes {0} MB", roundedSize);
}
private void ImportSettings(object sender, EventArgs e)
@@ -475,20 +475,6 @@ private void DisableDownloadingNewTranslations_StateChanged(object sender, Event
private void TextboxCard_ValueChanged(object sender, EventArgs e)
{ ExperimentalSettingsExpander.ShowRestartRequiredBanner(); }
- private void ResetIconCache_Click(object sender, EventArgs e)
- {
- try
- {
- Directory.Delete(CoreData.UniGetUICacheDirectory_Icons, true);
- }
- catch (Exception ex)
- {
- Logger.Error("An error occurred while deleting icon cache");
- Logger.Error(ex);
- }
- ExperimentalSettingsExpander.ShowRestartRequiredBanner();
- }
-
private async void DoBackup_Click(object sender, EventArgs e)
{
DialogHelper.ShowLoadingDialog(CoreTools.Translate("Performing backup, please wait..."));
@@ -555,5 +541,20 @@ private void UseUserGSudoToggle_StateChanged(object sender, EventArgs e)
{
ExperimentalSettingsExpander.ShowRestartRequiredBanner();
}
+
+ private void ResetIconCache_OnClick(object? sender, EventArgs e)
+ {
+ try
+ {
+ Directory.Delete(CoreData.UniGetUICacheDirectory_Icons, true);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("An error occurred while deleting icon cache");
+ Logger.Error(ex);
+ }
+ GeneralSettingsExpander.ShowRestartRequiredBanner();
+ LoadIconCacheSize();
+ }
}
}