jellyfin/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs

325 lines
11 KiB
C#
Raw Normal View History

2014-06-29 17:35:05 +00:00
using MediaBrowser.Common.Configuration;
2013-03-04 05:43:06 +00:00
using MediaBrowser.Common.Events;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
2014-06-29 17:35:05 +00:00
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
2013-03-04 05:43:06 +00:00
using System.Threading;
2015-10-07 21:42:29 +00:00
using CommonIO;
2013-03-04 05:43:06 +00:00
namespace MediaBrowser.Common.Implementations.Configuration
{
/// <summary>
/// Class BaseConfigurationManager
/// </summary>
public abstract class BaseConfigurationManager : IConfigurationManager
{
/// <summary>
/// Gets the type of the configuration.
/// </summary>
/// <value>The type of the configuration.</value>
protected abstract Type ConfigurationType { get; }
/// <summary>
/// Occurs when [configuration updated].
/// </summary>
public event EventHandler<EventArgs> ConfigurationUpdated;
2014-08-10 22:13:17 +00:00
/// <summary>
/// Occurs when [configuration updating].
/// </summary>
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdating;
2014-06-29 17:35:05 +00:00
/// <summary>
/// Occurs when [named configuration updated].
/// </summary>
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
2013-03-04 05:43:06 +00:00
/// <summary>
/// Gets the logger.
/// </summary>
/// <value>The logger.</value>
protected ILogger Logger { get; private set; }
/// <summary>
/// Gets the XML serializer.
/// </summary>
/// <value>The XML serializer.</value>
protected IXmlSerializer XmlSerializer { get; private set; }
/// <summary>
/// Gets or sets the application paths.
/// </summary>
/// <value>The application paths.</value>
public IApplicationPaths CommonApplicationPaths { get; private set; }
2015-10-07 21:42:29 +00:00
public readonly IFileSystem FileSystem;
2013-03-04 05:43:06 +00:00
/// <summary>
/// The _configuration loaded
/// </summary>
private bool _configurationLoaded;
/// <summary>
/// The _configuration sync lock
/// </summary>
private object _configurationSyncLock = new object();
/// <summary>
/// The _configuration
/// </summary>
private BaseApplicationConfiguration _configuration;
/// <summary>
/// Gets the system configuration
/// </summary>
/// <value>The configuration.</value>
public BaseApplicationConfiguration CommonConfiguration
{
get
{
// Lazy load
LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer));
return _configuration;
}
protected set
{
_configuration = value;
_configurationLoaded = value != null;
}
}
2014-06-29 17:35:05 +00:00
private ConfigurationStore[] _configurationStores = {};
2014-09-05 03:48:53 +00:00
private IConfigurationFactory[] _configurationFactories = {};
2014-06-29 17:35:05 +00:00
2013-03-04 05:43:06 +00:00
/// <summary>
/// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="xmlSerializer">The XML serializer.</param>
2015-10-07 21:42:29 +00:00
protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
2013-03-04 05:43:06 +00:00
{
CommonApplicationPaths = applicationPaths;
XmlSerializer = xmlSerializer;
2015-10-07 21:42:29 +00:00
FileSystem = fileSystem;
2013-03-04 05:43:06 +00:00
Logger = logManager.GetLogger(GetType().Name);
2013-12-15 01:17:57 +00:00
UpdateCachePath();
2013-03-04 05:43:06 +00:00
}
2014-12-22 01:02:15 +00:00
public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
2014-06-29 17:35:05 +00:00
{
_configurationFactories = factories.ToArray();
_configurationStores = _configurationFactories
.SelectMany(i => i.GetConfigurations())
.ToArray();
}
2013-03-04 05:43:06 +00:00
/// <summary>
/// Saves the configuration.
/// </summary>
public void SaveConfiguration()
{
2013-12-29 17:07:29 +00:00
var path = CommonApplicationPaths.SystemConfigurationFilePath;
2015-09-13 23:07:54 +00:00
Directory.CreateDirectory(Path.GetDirectoryName(path));
2013-12-29 17:07:29 +00:00
2014-06-29 17:35:05 +00:00
lock (_configurationSyncLock)
2013-03-04 05:43:06 +00:00
{
2013-12-29 17:07:29 +00:00
XmlSerializer.SerializeToFile(CommonConfiguration, path);
2013-04-23 19:17:21 +00:00
}
OnConfigurationUpdated();
}
/// <summary>
/// Called when [configuration updated].
/// </summary>
protected virtual void OnConfigurationUpdated()
{
2013-12-15 01:17:57 +00:00
UpdateCachePath();
2013-03-04 05:43:06 +00:00
EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
}
/// <summary>
/// Replaces the configuration.
/// </summary>
/// <param name="newConfiguration">The new configuration.</param>
/// <exception cref="System.ArgumentNullException">newConfiguration</exception>
2013-04-23 19:17:21 +00:00
public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
2013-03-04 05:43:06 +00:00
{
if (newConfiguration == null)
{
throw new ArgumentNullException("newConfiguration");
}
2013-12-15 01:17:57 +00:00
ValidateCachePath(newConfiguration);
2013-03-04 05:43:06 +00:00
CommonConfiguration = newConfiguration;
SaveConfiguration();
}
2013-12-15 01:17:57 +00:00
/// <summary>
/// Updates the items by name path.
/// </summary>
private void UpdateCachePath()
{
2015-04-24 02:15:29 +00:00
string cachePath;
if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
{
cachePath = null;
}
else if (CommonConfiguration.EnableCustomPathSubFolders)
{
cachePath = Path.Combine(CommonConfiguration.CachePath, "cache");
}
else
{
cachePath = CommonConfiguration.CachePath;
}
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
2013-12-15 01:17:57 +00:00
}
/// <summary>
/// Replaces the cache path.
/// </summary>
/// <param name="newConfig">The new configuration.</param>
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
private void ValidateCachePath(BaseApplicationConfiguration newConfig)
{
var newPath = newConfig.CachePath;
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
{
// Validate
if (!Directory.Exists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
2015-10-07 21:42:29 +00:00
EnsureWriteAccess(newPath);
2013-12-15 01:17:57 +00:00
}
}
2014-06-29 17:35:05 +00:00
2015-10-07 21:42:29 +00:00
protected void EnsureWriteAccess(string path)
{
var file = Path.Combine(path, Guid.NewGuid().ToString());
FileSystem.WriteAllText(file, string.Empty);
FileSystem.DeleteFile(file);
}
2014-06-29 17:35:05 +00:00
private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
private string GetConfigurationFile(string key)
{
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
}
public object GetConfiguration(string key)
{
return _configurations.GetOrAdd(key, k =>
{
var file = GetConfigurationFile(key);
var configurationType = _configurationStores
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
.ConfigurationType;
lock (_configurationSyncLock)
{
2014-12-21 18:58:17 +00:00
return LoadConfiguration(file, configurationType);
2014-06-29 17:35:05 +00:00
}
});
}
2014-12-21 18:58:17 +00:00
private object LoadConfiguration(string path, Type configurationType)
{
try
{
return XmlSerializer.DeserializeFromFile(configurationType, path);
}
catch (FileNotFoundException)
{
return Activator.CreateInstance(configurationType);
}
2014-12-23 03:58:14 +00:00
catch (DirectoryNotFoundException)
{
return Activator.CreateInstance(configurationType);
}
2014-12-21 18:58:17 +00:00
catch (Exception ex)
{
Logger.ErrorException("Error loading configuration file: {0}", ex, path);
return Activator.CreateInstance(configurationType);
}
}
2014-06-29 17:35:05 +00:00
public void SaveConfiguration(string key, object configuration)
{
2014-12-21 19:40:37 +00:00
var configurationStore = GetConfigurationStore(key);
var configurationType = configurationStore.ConfigurationType;
2014-06-29 17:35:05 +00:00
if (configuration.GetType() != configurationType)
{
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
}
2014-12-21 19:40:37 +00:00
var validatingStore = configurationStore as IValidatingConfiguration;
if (validatingStore != null)
{
var currentConfiguration = GetConfiguration(key);
validatingStore.Validate(currentConfiguration, configuration);
}
2014-08-10 22:13:17 +00:00
EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
}, Logger);
2014-06-29 17:35:05 +00:00
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
var path = GetConfigurationFile(key);
2015-09-13 23:07:54 +00:00
Directory.CreateDirectory(Path.GetDirectoryName(path));
2014-06-29 17:35:05 +00:00
lock (_configurationSyncLock)
{
XmlSerializer.SerializeToFile(configuration, path);
}
2014-12-22 01:02:15 +00:00
OnNamedConfigurationUpdated(key, configuration);
}
protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
{
2014-06-29 17:35:05 +00:00
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
}, Logger);
}
public Type GetConfigurationType(string key)
{
2014-12-21 19:40:37 +00:00
return GetConfigurationStore(key)
2014-06-29 17:35:05 +00:00
.ConfigurationType;
}
2014-12-21 19:40:37 +00:00
private ConfigurationStore GetConfigurationStore(string key)
{
return _configurationStores
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
}
2013-03-04 05:43:06 +00:00
}
}