Skip to content

Commit

Permalink
Enable COM API access to correlate with the tracking database only (#…
Browse files Browse the repository at this point in the history
…3670)

This change adds a flag that lets the caller specify that they are only interested in the installed tracking data, not the available packages.  With it set, one can correlate to the catalog via the tracking database without ever needing to access the remote source information.
  • Loading branch information
JohnMcPMS committed Sep 26, 2023
1 parent 804c125 commit c255b68
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 30 deletions.
4 changes: 0 additions & 4 deletions src/AppInstallerRepositoryCore/CompositeSource.cpp
Expand Up @@ -1412,15 +1412,12 @@ namespace AppInstaller::Repository
}
}

bool addedAvailablePackage = false;

// Directly search for the available package from tracking information.
if (trackingPackage)
{
auto availablePackage = GetTrackedPackageFromAvailableSource(result, trackedSource, trackingPackage->GetProperty(PackageProperty::Id));
if (availablePackage)
{
addedAvailablePackage = true;
compositePackage->AddAvailablePackage(std::move(availablePackage));
}
compositePackage->SetTracking(std::move(trackedSource), std::move(trackingPackage), std::move(trackingPackageVersion));
Expand Down Expand Up @@ -1453,7 +1450,6 @@ namespace AppInstaller::Repository
});

// For non pinning cases. We found some matching packages here, don't keep going.
addedAvailablePackage = true;
compositePackage->AddAvailablePackage(std::move(availablePackage));
}
}
Expand Down
Expand Up @@ -225,6 +225,10 @@ namespace AppInstaller::Repository
// Set background update check interval.
void SetBackgroundUpdateInterval(TimeSpan interval);

// Indicates that we are only interested in the PackageTrackingCatalog for the source.
// Must be set before Open to have effect, and will prevent the underlying source from being updated or opened.
void InstalledPackageInformationOnly(bool value);

// Execute a search on the source.
SearchResult Search(const SearchRequest& request) const;

Expand Down Expand Up @@ -287,6 +291,7 @@ namespace AppInstaller::Repository
bool m_isSourceToBeAdded = false;
bool m_isComposite = false;
std::optional<TimeSpan> m_backgroundUpdateInterval;
bool m_installedPackageInformationOnly = false;
mutable PackageTrackingCatalog m_trackingCatalog;
};
}
119 changes: 94 additions & 25 deletions src/AppInstallerRepositoryCore/RepositorySource.cpp
Expand Up @@ -202,6 +202,53 @@ namespace AppInstaller::Repository
SourceDetails m_details;
std::exception_ptr m_exception;
};

// A wrapper that doesn't actually forward the search requests.
struct TrackingOnlySourceWrapper : public ISource
{
TrackingOnlySourceWrapper(std::shared_ptr<ISourceReference> wrapped) : m_wrapped(std::move(wrapped))
{
m_identifier = m_wrapped->GetIdentifier();
}

const std::string& GetIdentifier() const override { return m_identifier; }

SourceDetails& GetDetails() const override { return m_wrapped->GetDetails(); }

SourceInformation GetInformation() const override { return m_wrapped->GetInformation(); }

SearchResult Search(const SearchRequest&) const override { return {}; }

void* CastTo(ISourceType) override { return nullptr; }

private:
std::shared_ptr<ISourceReference> m_wrapped;
std::string m_identifier;
};

// A wrapper to create another wrapper.
struct TrackingOnlyReferenceWrapper : public ISourceReference
{
TrackingOnlyReferenceWrapper(std::shared_ptr<ISourceReference> wrapped) : m_wrapped(std::move(wrapped)) {}

std::string GetIdentifier() override { return m_wrapped->GetIdentifier(); }

SourceDetails& GetDetails() override { return m_wrapped->GetDetails(); }

SourceInformation GetInformation() override { return m_wrapped->GetInformation(); }

bool SetCustomHeader(std::optional<std::string>) override { return false; }

void SetCaller(std::string caller) override { m_wrapped->SetCaller(std::move(caller)); }

std::shared_ptr<ISource> Open(IProgressCallback&) override
{
return std::make_shared<TrackingOnlySourceWrapper>(m_wrapped);
}

private:
std::shared_ptr<ISourceReference> m_wrapped;
};
}

std::unique_ptr<ISourceFactory> ISourceFactory::GetForType(std::string_view type)
Expand Down Expand Up @@ -475,6 +522,11 @@ namespace AppInstaller::Repository
m_backgroundUpdateInterval = interval;
}

void Source::InstalledPackageInformationOnly(bool value)
{
m_installedPackageInformationOnly = value;
}

SearchResult Source::Search(const SearchRequest& request) const
{
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_source);
Expand Down Expand Up @@ -554,51 +606,68 @@ namespace AppInstaller::Repository

if (!m_source)
{
std::vector<std::shared_ptr<ISourceReference>>* sourceReferencesToOpen = nullptr;
std::vector<std::shared_ptr<ISourceReference>> sourceReferencesForTrackingOnly;
std::unique_ptr<SourceList> sourceList;

// Check for updates before opening.
for (auto& sourceReference : m_sourceReferences)
if (m_installedPackageInformationOnly)
{
auto& details = sourceReference->GetDetails();
if (ShouldUpdateBeforeOpen(details, m_backgroundUpdateInterval))
sourceReferencesToOpen = &sourceReferencesForTrackingOnly;

// Create a wrapper for each reference
for (auto& sourceReference : m_sourceReferences)
{
try
sourceReferencesForTrackingOnly.emplace_back(std::make_shared<TrackingOnlyReferenceWrapper>(sourceReference));
}
}
else
{
// Check for updates before opening.
for (auto& sourceReference : m_sourceReferences)
{
auto& details = sourceReference->GetDetails();
if (ShouldUpdateBeforeOpen(details, m_backgroundUpdateInterval))
{
// TODO: Consider adding a context callback to indicate we are doing the same action
// to avoid the progress bar fill up multiple times.
if (BackgroundUpdateSourceFromDetails(details, progress))
try
{
if (sourceList == nullptr)
// TODO: Consider adding a context callback to indicate we are doing the same action
// to avoid the progress bar fill up multiple times.
if (BackgroundUpdateSourceFromDetails(details, progress))
{
sourceList = std::make_unique<SourceList>();
if (sourceList == nullptr)
{
sourceList = std::make_unique<SourceList>();
}

auto detailsInternal = sourceList->GetSource(details.Name);
detailsInternal->LastUpdateTime = details.LastUpdateTime;
sourceList->SaveMetadata(*detailsInternal);
}
else
{
AICLI_LOG(Repo, Error, << "Failed to update source: " << details.Name);
result.emplace_back(details);
}

auto detailsInternal = sourceList->GetSource(details.Name);
detailsInternal->LastUpdateTime = details.LastUpdateTime;
sourceList->SaveMetadata(*detailsInternal);
}
else
catch (...)
{
AICLI_LOG(Repo, Error, << "Failed to update source: " << details.Name);
LOG_CAUGHT_EXCEPTION();
AICLI_LOG(Repo, Warning, << "Failed to update source: " << details.Name);
result.emplace_back(details);
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
AICLI_LOG(Repo, Warning, << "Failed to update source: " << details.Name);
result.emplace_back(details);
}
}

sourceReferencesToOpen = &m_sourceReferences;
}

if (m_sourceReferences.size() > 1)
if (sourceReferencesToOpen->size() > 1)
{
AICLI_LOG(Repo, Info, << "Multiple sources available, creating aggregated source.");
auto aggregatedSource = std::make_shared<CompositeSource>("*DefaultSource");
std::vector<std::shared_ptr<OpenExceptionProxy>> openExceptionProxies;

for (auto& sourceReference : m_sourceReferences)
for (auto& sourceReference : *sourceReferencesToOpen)
{
AICLI_LOG(Repo, Info, << "Adding to aggregated source: " << sourceReference->GetDetails().Name);

Expand Down Expand Up @@ -628,7 +697,7 @@ namespace AppInstaller::Repository
}
else
{
m_source = m_sourceReferences[0]->Open(progress);
m_source = (*sourceReferencesToOpen)[0]->Open(progress);
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
Expand Up @@ -28,13 +28,17 @@ namespace winrt::Microsoft::Management::Deployment::implementation

if (IsBackgroundProcessForPolicy())
{
// Delay the default update interval for these background processes
static constexpr winrt::Windows::Foundation::TimeSpan s_PackageCatalogUpdateIntervalDelay_Base = 168h; //1 week

// Add a bit of randomness to the default interval time
std::default_random_engine randomEngine(std::random_device{}());
std::uniform_int_distribution<long long> distribution(0, 604800);

m_packageCatalogBackgroundUpdateInterval = s_PackageCatalogUpdateIntervalDelay_Base + std::chrono::seconds(distribution(randomEngine));

// Prevent any update / data processing by default for these background processes
m_installedPackageInformationOnly = true;
}
}
void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions options)
Expand Down Expand Up @@ -95,6 +99,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
auto copy = catalogImpl->m_sourceReference;
copy.SetCaller(callerName);
copy.SetBackgroundUpdateInterval(catalog.PackageCatalogBackgroundUpdateInterval());
copy.InstalledPackageInformationOnly(catalog.InstalledPackageInformationOnly());
copy.Open(progress);
remoteSources.emplace_back(std::move(copy));
}
Expand Down Expand Up @@ -137,6 +142,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
source = m_sourceReference;
source.SetCaller(callerName);
source.SetBackgroundUpdateInterval(PackageCatalogBackgroundUpdateInterval());
source.InstalledPackageInformationOnly(m_installedPackageInformationOnly);
source.Open(progress);
}

Expand Down Expand Up @@ -216,6 +222,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
return m_acceptSourceAgreements;
}

void PackageCatalogReference::PackageCatalogBackgroundUpdateInterval(winrt::Windows::Foundation::TimeSpan const& value)
{
if (IsComposite())
Expand All @@ -229,4 +236,19 @@ namespace winrt::Microsoft::Management::Deployment::implementation
{
return m_packageCatalogBackgroundUpdateInterval;
}

bool PackageCatalogReference::InstalledPackageInformationOnly()
{
return m_installedPackageInformationOnly;
}

void PackageCatalogReference::InstalledPackageInformationOnly(bool value)
{
if (IsComposite())
{
throw winrt::hresult_illegal_state_change();
}

m_installedPackageInformationOnly = value;
}
}
Expand Up @@ -22,12 +22,14 @@ namespace winrt::Microsoft::Management::Deployment::implementation
winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::SourceAgreement> SourceAgreements();
hstring AdditionalPackageCatalogArguments();
void AdditionalPackageCatalogArguments(hstring const& value);
// Contract 6.0
// Contract 6
bool AcceptSourceAgreements();
void AcceptSourceAgreements(bool value);
// Contract 8.0
winrt::Windows::Foundation::TimeSpan PackageCatalogBackgroundUpdateInterval();
void PackageCatalogBackgroundUpdateInterval(winrt::Windows::Foundation::TimeSpan const& value);
bool InstalledPackageInformationOnly();
void InstalledPackageInformationOnly(bool value);

#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
private:
Expand All @@ -37,6 +39,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
::AppInstaller::Repository::Source m_sourceReference;
std::optional<std::string> m_additionalPackageCatalogArguments;
bool m_acceptSourceAgreements = true;
bool m_installedPackageInformationOnly = false;
std::once_flag m_sourceAgreementsOnceFlag;
winrt::Windows::Foundation::TimeSpan m_packageCatalogBackgroundUpdateInterval = winrt::Windows::Foundation::TimeSpan::zero();
#endif
Expand Down
4 changes: 4 additions & 0 deletions src/Microsoft.Management.Deployment/PackageManager.idl
Expand Up @@ -754,6 +754,10 @@ namespace Microsoft.Management.Deployment
{
/// Time interval for package catalog to check for an update. Setting to zero will disable the check for update.
Windows.Foundation.TimeSpan PackageCatalogBackgroundUpdateInterval;

// When set to true, the opened catalog will only provide the information regarding packages installed from this catalog.
// In this mode, no external resources should be required.
Boolean InstalledPackageInformationOnly;
}
}

Expand Down

0 comments on commit c255b68

Please sign in to comment.