using System;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Configuration
{
///
/// Applies the configuration invalidations published by the other instances sharing this
/// configuration directory, dropping the local cache entry so the next read comes off the shared file.
///
public sealed class ConfigurationInvalidationSubscriber : IHostedService
{
private readonly IConfigurationInvalidationBus _bus;
private readonly IConfigurationManager _configurationManager;
private readonly ILogger _logger;
///
/// Initializes a new instance of the class.
///
/// The invalidation bus.
/// The configuration manager holding the cached configuration.
/// The logger.
public ConfigurationInvalidationSubscriber(
IConfigurationInvalidationBus bus,
IConfigurationManager configurationManager,
ILogger logger)
{
_bus = bus;
_configurationManager = configurationManager;
_logger = logger;
}
///
public Task StartAsync(CancellationToken cancellationToken)
{
_bus.Subscribe(Apply);
return Task.CompletedTask;
}
///
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
private void Apply(ConfigurationInvalidation invalidation)
{
try
{
// Applying re-raises the same update events a local save raises, so the in-process
// consumers re-read. The scope tells those consumers that the write was somebody else's,
// so the ones that answer an update by writing neither repeat it nor publish it back.
using var scope = ConfigurationInvalidationContext.BeginApply();
switch (invalidation.Scope)
{
case ConfigurationInvalidationScope.SystemConfiguration:
_configurationManager.InvalidateCachedConfiguration(null);
break;
case ConfigurationInvalidationScope.NamedConfiguration when !string.IsNullOrEmpty(invalidation.Target):
_configurationManager.InvalidateCachedConfiguration(invalidation.Target);
break;
case ConfigurationInvalidationScope.LibraryOptions when !string.IsNullOrEmpty(invalidation.Target):
CollectionFolder.InvalidateLibraryOptions(invalidation.Target);
break;
case ConfigurationInvalidationScope.AllLibraryOptions:
CollectionFolder.InvalidateAllLibraryOptions();
break;
default:
return;
}
_logger.LogDebug("Applied {Scope} invalidation for {Target} from {OriginId}.", invalidation.Scope, invalidation.Target, invalidation.OriginId);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to apply a {Scope} invalidation for {Target}.", invalidation.Scope, invalidation.Target);
}
}
}
}