Skip to content

Commit

Permalink
Fixes OrchardCMS#10311 : Remove ShellDescriptorManager dependency on …
Browse files Browse the repository at this point in the history
…YesSql.ISession
  • Loading branch information
TFleury committed Dec 3, 2022
1 parent e56f34f commit a4dc194
Showing 1 changed file with 39 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OrchardCore.Data.Documents;
using OrchardCore.Environment.Extensions;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Environment.Shell.Descriptor;
using OrchardCore.Environment.Shell.Descriptor.Models;
using OrchardCore.Modules;
using YesSql;

namespace OrchardCore.Environment.Shell.Data.Descriptors
{
Expand All @@ -25,70 +24,66 @@ public class ShellDescriptorManager : IShellDescriptorManager
private readonly IEnumerable<ShellFeature> _alwaysEnabledFeatures;
private readonly IEnumerable<IShellDescriptorManagerEventHandler> _shellDescriptorManagerEventHandlers;
private readonly IExtensionManager _extensionManager;
private readonly ISession _session;
private readonly IDocumentStore _documentStore;
private readonly ILogger _logger;

private ShellDescriptor _shellDescriptor;

public ShellDescriptorManager(
ShellSettings shellSettings,
IShellConfiguration shellConfiguration,
IEnumerable<ShellFeature> shellFeatures,
IEnumerable<IShellDescriptorManagerEventHandler> shellDescriptorManagerEventHandlers,
IExtensionManager extensionManager,
ISession session,
IDocumentStore documentStore,
ILogger<ShellDescriptorManager> logger)
{
_shellSettings = shellSettings;
_shellConfiguration = shellConfiguration;
_alwaysEnabledFeatures = shellFeatures.Where(f => f.AlwaysEnabled).ToArray();
_shellDescriptorManagerEventHandlers = shellDescriptorManagerEventHandlers;
_extensionManager = extensionManager;
_session = session;
_documentStore = documentStore;
_logger = logger;
}

public async Task<ShellDescriptor> GetShellDescriptorAsync()
{
// Prevent multiple queries during the same request
if (_shellDescriptor == null)
(bool cacheable, ShellDescriptor shellDescriptor) = await _documentStore.GetOrCreateImmutableAsync(ShellDescriptorFactory);

if (shellDescriptor.SerialNumber== 0)
{
_shellDescriptor = await _session.Query<ShellDescriptor>().FirstOrDefaultAsync();
return null;
}

if (_shellDescriptor != null)
{
var configuredFeatures = new ConfiguredFeatures();
_shellConfiguration.Bind(configuredFeatures);
if (cacheable) {
// Init shell descriptor and load features
var configuredFeatures = new ConfiguredFeatures();
_shellConfiguration.Bind(configuredFeatures);

var features = _alwaysEnabledFeatures
.Concat(configuredFeatures.Features.Select(id => new ShellFeature(id) { AlwaysEnabled = true }))
.Concat(_shellDescriptor.Features)
.Distinct();
var features = _alwaysEnabledFeatures
.Concat(configuredFeatures.Features.Select(id => new ShellFeature(id) { AlwaysEnabled = true }))
.Concat(shellDescriptor.Features)
.Distinct();

var featureIds = features.Select(sf => sf.Id).ToArray();
var featureIds = features.Select(sf => sf.Id).ToArray();

var missingDependencies = (await _extensionManager.LoadFeaturesAsync(featureIds))
.Select(entry => entry.FeatureInfo.Id)
.Except(featureIds)
.Select(id => new ShellFeature(id));
var missingDependencies = (await _extensionManager.LoadFeaturesAsync(featureIds))
.Select(entry => entry.FeatureInfo.Id)
.Except(featureIds)
.Select(id => new ShellFeature(id));

_shellDescriptor.Features = features
.Concat(missingDependencies)
.ToList();
}
shellDescriptor.Features = features
.Concat(missingDependencies)
.ToList();
}

return _shellDescriptor;
return shellDescriptor;
}

public async Task UpdateShellDescriptorAsync(int priorSerialNumber, IEnumerable<ShellFeature> enabledFeatures)
{
var shellDescriptorRecord = await GetShellDescriptorAsync();
var serialNumber = shellDescriptorRecord == null
? 0
: shellDescriptorRecord.SerialNumber;
var shellDescriptor = await _documentStore.GetOrCreateMutableAsync(ShellDescriptorFactory);

if (priorSerialNumber != serialNumber)
if (priorSerialNumber != shellDescriptor.SerialNumber)
{
throw new InvalidOperationException("Invalid serial number for shell descriptor");
}
Expand All @@ -98,32 +93,29 @@ public async Task UpdateShellDescriptorAsync(int priorSerialNumber, IEnumerable<
_logger.LogInformation("Updating shell descriptor for tenant '{TenantName}' ...", _shellSettings.Name);
}

if (shellDescriptorRecord == null)
{
shellDescriptorRecord = new ShellDescriptor { SerialNumber = 1 };
}
else
{
shellDescriptorRecord.SerialNumber++;
}

shellDescriptorRecord.Features = _alwaysEnabledFeatures.Union(enabledFeatures).ToList();
shellDescriptorRecord.Installed = shellDescriptorRecord.Installed.Union(shellDescriptorRecord.Features).ToList();
shellDescriptor.SerialNumber++;
shellDescriptor.Features = _alwaysEnabledFeatures.Union(enabledFeatures).ToList();
shellDescriptor.Installed = shellDescriptor.Installed.Union(shellDescriptor.Features).ToList();

if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Shell descriptor updated for tenant '{TenantName}'.", _shellSettings.Name);
}

_session.Save(shellDescriptorRecord);
await _documentStore.UpdateAsync(shellDescriptor, (_) => Task.CompletedTask);

// In the 'ChangedAsync()' event the shell will be released so that, on request, a new one will be built.
// So, we commit the session earlier to prevent a new shell from being built from an outdated descriptor.

await _session.SaveChangesAsync();
await _documentStore.CommitAsync();

await _shellDescriptorManagerEventHandlers.InvokeAsync((handler, shellDescriptorRecord, _shellSettings) =>
handler.ChangedAsync(shellDescriptorRecord, _shellSettings), shellDescriptorRecord, _shellSettings, _logger);
handler.ChangedAsync(shellDescriptorRecord, _shellSettings), shellDescriptor, _shellSettings, _logger);
}

private static Task<ShellDescriptor> ShellDescriptorFactory()
{
return Task.FromResult(new ShellDescriptor { SerialNumber = 0 });
}

private class ConfiguredFeatures
Expand Down

0 comments on commit a4dc194

Please sign in to comment.