Skip to content

Commit c879ac0

Browse files
authored
Merge pull request #2931 from marticliment/winget-native-package-caching
2 parents b5f2de6 + e8b0d92 commit c879ac0

File tree

6 files changed

+194
-149
lines changed

6 files changed

+194
-149
lines changed

src/UniGetUI.PackageEngine.Managers.WinGet/Providers/WinGetPackageDetailsProvider.cs

+3-50
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ namespace UniGetUI.PackageEngine.Managers.WingetManager
1414
internal sealed class WinGetPackageDetailsProvider : BasePackageDetailsProvider<UniGetUIManagers.PackageManager>
1515
{
1616
private static readonly Dictionary<string, string> __msstore_package_manifests = [];
17-
18-
private struct MicrosoftStoreProductType
19-
{
20-
public string productIds { get; set; }
21-
}
22-
17+
2318
public WinGetPackageDetailsProvider(WinGet manager) : base(manager) { }
2419

2520
protected override IEnumerable<string> GetInstallableVersions_UnSafe(IPackage package)
@@ -224,50 +219,8 @@ protected override IEnumerable<Uri> GetScreenshots_UnSafe(IPackage package)
224219

225220
private static CacheableIcon? GetWinGetPackageIcon(IPackage package)
226221
{
227-
if (WinGetHelper.Instance is not NativeWinGetHelper)
228-
return null;
229-
230-
PackageManager WinGetManager = ((NativeWinGetHelper)WinGetHelper.Instance).WinGetManager;
231-
WindowsPackageManager.Interop.WindowsPackageManagerFactory Factory = ((NativeWinGetHelper)WinGetHelper.Instance).Factory;
232-
233-
// Find the native package for the given Package object
234-
PackageCatalogReference Catalog = WinGetManager.GetPackageCatalogByName(package.Source.Name);
235-
if (Catalog is null)
236-
{
237-
Logger.Error("[WINGET COM] Failed to get catalog " + package.Source.Name + ". Is the package local?");
238-
return null;
239-
}
240-
241-
// Connect to catalog
242-
Catalog.AcceptSourceAgreements = true;
243-
ConnectResult ConnectResult = Catalog.Connect();
244-
if (ConnectResult.Status != ConnectResultStatus.Ok)
245-
{
246-
Logger.Error("[WINGET COM] Failed to connect to catalog " + package.Source.Name);
247-
return null;
248-
}
249-
250-
// Match only the exact same Id
251-
FindPackagesOptions packageMatchFilter = Factory.CreateFindPackagesOptions();
252-
PackageMatchFilter filters = Factory.CreatePackageMatchFilter();
253-
filters.Field = PackageMatchField.Id;
254-
filters.Value = package.Id;
255-
filters.Option = PackageFieldMatchOption.Equals;
256-
packageMatchFilter.Filters.Add(filters);
257-
packageMatchFilter.ResultLimit = 1;
258-
FindPackagesResult SearchResult = ConnectResult.PackageCatalog.FindPackages(packageMatchFilter);
259-
260-
if (SearchResult.Matches is null || SearchResult.Matches.Count == 0)
261-
{
262-
Logger.Error($"[WINGET COM] Package with Id={package.Id} was NOT found in catalog id=" + package.Source.Name);
263-
return null;
264-
}
265-
266-
// Get the Native Package
267-
CatalogPackage NativePackage = SearchResult.Matches.First().CatalogPackage;
268-
269-
// Extract data from NativeDetails
270-
CatalogPackageMetadata NativeDetails = NativePackage.DefaultInstallVersion.GetCatalogPackageMetadata();
222+
CatalogPackageMetadata? NativeDetails = NativePackageHandler.GetDetails(package);
223+
if (NativeDetails is null) return null;
271224

272225
// Get the actual icon and return it
273226
foreach (Icon? icon in NativeDetails.Icons.ToArray())

src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Diagnostics;
22
using System.Runtime.InteropServices;
33
using System.Text;
4+
using ABI.System.Collections.Generic;
45
using UniGetUI.Core.Data;
56
using UniGetUI.Core.Logging;
67
using UniGetUI.Core.SettingsEngine;
@@ -231,6 +232,14 @@ protected override ManagerStatus LoadManager()
231232
return status;
232233
}
233234

235+
// For future usage
236+
private void ReRegisterCOMServer()
237+
{
238+
WinGetHelper.Instance = new NativeWinGetHelper();
239+
NativePackageHandler.Clear();
240+
}
241+
242+
234243
public override void RefreshPackageIndexes()
235244
{
236245
Process p = new()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using System.Collections.Concurrent;
2+
using Microsoft.Management.Deployment;
3+
using UniGetUI.Core.Logging;
4+
using UniGetUI.PackageEngine.Enums;
5+
using UniGetUI.PackageEngine.Interfaces;
6+
7+
namespace UniGetUI.PackageEngine.Managers.WingetManager;
8+
9+
public static class NativePackageHandler
10+
{
11+
private static ConcurrentDictionary<long, CatalogPackage> __nativePackages = new();
12+
private static ConcurrentDictionary<long, CatalogPackageMetadata> __nativeDetails = new();
13+
private static ConcurrentDictionary<long, PackageInstallerInfo> __nativeInstallers_Install = new();
14+
private static ConcurrentDictionary<long, PackageInstallerInfo> __nativeInstallers_Uninstall = new();
15+
16+
/// <summary>
17+
/// Get (cache or load) the native package for the given package, if any;
18+
/// </summary>
19+
/// <returns></returns>
20+
public static CatalogPackage? GetPackage(IPackage package)
21+
{
22+
if (NativeWinGetHelper.ExternalFactory is null || NativeWinGetHelper.ExternalManager is null)
23+
return null;
24+
25+
__nativePackages.TryGetValue(package.GetHash(), out CatalogPackage? catalogPackage);
26+
if (catalogPackage is not null)
27+
return catalogPackage;
28+
29+
PackageCatalogReference Catalog = NativeWinGetHelper.ExternalManager.GetPackageCatalogByName(package.Source.Name);
30+
if (Catalog is null)
31+
{
32+
Logger.Error("Failed to get catalog " + package.Source.Name + ". Is the package local?");
33+
return null;
34+
}
35+
36+
// Connect to catalog
37+
Catalog.AcceptSourceAgreements = true;
38+
ConnectResult ConnectResult = Catalog.Connect();
39+
if (ConnectResult.Status != ConnectResultStatus.Ok)
40+
{
41+
Logger.Error("Failed to connect to catalog " + package.Source.Name);
42+
return null;
43+
}
44+
45+
// Match only the exact same Id
46+
FindPackagesOptions packageMatchFilter = NativeWinGetHelper.ExternalFactory.CreateFindPackagesOptions();
47+
PackageMatchFilter filters = NativeWinGetHelper.ExternalFactory.CreatePackageMatchFilter();
48+
filters.Field = PackageMatchField.Id;
49+
filters.Value = package.Id;
50+
filters.Option = PackageFieldMatchOption.Equals;
51+
packageMatchFilter.Filters.Add(filters);
52+
packageMatchFilter.ResultLimit = 1;
53+
var SearchResult = Task.Run(() => ConnectResult.PackageCatalog.FindPackages(packageMatchFilter));
54+
55+
if (SearchResult?.Result?.Matches is null ||
56+
SearchResult.Result.Matches.Count == 0)
57+
{
58+
Logger.Error("Failed to find package " + package.Id + " in catalog " + package.Source.Name);
59+
return null;
60+
}
61+
62+
// Get the Native Package
63+
catalogPackage = SearchResult.Result.Matches.First().CatalogPackage;
64+
AddPackage(package, catalogPackage);
65+
66+
return catalogPackage;
67+
}
68+
69+
/// <summary>
70+
/// Adds an external CatalogPackage to the internal database
71+
/// </summary>
72+
public static void AddPackage(IPackage package, CatalogPackage catalogPackage)
73+
{
74+
__nativePackages[package.GetHash()] = catalogPackage;
75+
}
76+
77+
/// <summary>
78+
/// Get (cached or load) the native package details for the given package, if any;
79+
/// </summary>
80+
public static CatalogPackageMetadata? GetDetails(IPackage package)
81+
{
82+
if (__nativeDetails.TryGetValue(package.GetHash(), out CatalogPackageMetadata? metadata))
83+
return metadata;
84+
85+
CatalogPackage? catalogPackage = GetPackage(package);
86+
metadata = catalogPackage?.DefaultInstallVersion?.GetCatalogPackageMetadata();
87+
metadata ??= catalogPackage?.InstalledVersion?.GetCatalogPackageMetadata();
88+
89+
if (metadata is not null)
90+
__nativeDetails[package.GetHash()] = metadata;
91+
92+
return metadata;
93+
}
94+
95+
/// <summary>
96+
/// Get (cached or load) the native installer for the given package, if any. The operation type determines wether
97+
/// </summary>
98+
public static PackageInstallerInfo? GetInstallationOptions(IPackage package, OperationType operation)
99+
{
100+
if (NativeWinGetHelper.ExternalFactory is null)
101+
return null;
102+
103+
PackageInstallerInfo? installerInfo = null;
104+
if (operation is OperationType.Uninstall)
105+
installerInfo = _getInstallationOptionsOnDict(package, ref __nativeInstallers_Uninstall, true);
106+
else
107+
installerInfo = _getInstallationOptionsOnDict(package, ref __nativeInstallers_Uninstall, false);
108+
109+
return installerInfo;
110+
}
111+
112+
public static void Clear()
113+
{
114+
__nativePackages.Clear();;
115+
__nativeDetails.Clear();;
116+
__nativeInstallers_Install.Clear();;
117+
__nativeInstallers_Uninstall.Clear();
118+
}
119+
120+
private static PackageInstallerInfo? _getInstallationOptionsOnDict(IPackage package, ref ConcurrentDictionary<long, PackageInstallerInfo> source, bool installed)
121+
{
122+
if (source.TryGetValue(package.GetHash(), out PackageInstallerInfo? installerInfo))
123+
return installerInfo;
124+
125+
PackageVersionInfo? catalogPackage;
126+
if (installed) catalogPackage = GetPackage(package)?.InstalledVersion;
127+
else catalogPackage = GetPackage(package)?.DefaultInstallVersion;
128+
129+
InstallOptions? options = NativeWinGetHelper.ExternalFactory?.CreateInstallOptions();
130+
installerInfo = catalogPackage?.GetApplicableInstaller(options);
131+
132+
if (installerInfo is not null)
133+
source[package.GetHash()] = installerInfo;
134+
135+
return installerInfo;
136+
}
137+
}

0 commit comments

Comments
 (0)