Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable COM API access to correlate with the tracking database only #3670

Merged
merged 4 commits into from Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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