#nullable disable #pragma warning disable SA1649 // File name should match first type name using System; using System.IO; using System.Runtime.InteropServices; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Common.Plugins { /// /// Provides a common base class for all plugins. /// /// The type of the T configuration type. public abstract class BasePlugin : BasePlugin, IHasPluginConfiguration where TConfigurationType : BasePluginConfiguration { /// /// The configuration sync lock. /// private readonly object _configurationSyncLock = new object(); /// /// The configuration save lock. /// private readonly object _configurationSaveLock = new object(); /// /// The configuration. /// private TConfigurationType _configuration; /// /// Initializes a new instance of the class. /// /// The application paths. /// The XML serializer. protected BasePlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) { ApplicationPaths = applicationPaths; XmlSerializer = xmlSerializer; var assembly = GetType().Assembly; var assemblyName = assembly.GetName(); var assemblyFilePath = assembly.Location; var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath)); if (Version is not null && !Directory.Exists(dataFolderPath)) { // Try again with the version number appended to the folder name. dataFolderPath += "_" + Version.ToString(); } SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version); var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true); if (idAttributes.Length > 0) { var attribute = (GuidAttribute)idAttributes[0]; var assemblyId = new Guid(attribute.Value); SetId(assemblyId); } } /// /// Gets the application paths. /// /// The application paths. protected IApplicationPaths ApplicationPaths { get; private set; } /// /// Gets the XML serializer. /// /// The XML serializer. protected IXmlSerializer XmlSerializer { get; private set; } /// /// Gets the type of configuration this plugin uses. /// /// The type of the configuration. public Type ConfigurationType => typeof(TConfigurationType); /// /// Gets or sets the event handler that is triggered when this configuration changes. /// public EventHandler ConfigurationChanged { get; set; } /// /// Gets the name the assembly file. /// /// The name of the assembly file. protected string AssemblyFileName => Path.GetFileName(AssemblyFilePath); /// /// Gets or sets the plugin configuration. /// /// The configuration. public TConfigurationType Configuration { get { // Lazy load if (_configuration is null) { lock (_configurationSyncLock) { _configuration ??= LoadConfiguration(); } } return _configuration; } protected set => _configuration = value; } /// /// Gets the name of the configuration file. Subclasses should override. /// /// The name of the configuration file. public virtual string ConfigurationFileName => Path.ChangeExtension(AssemblyFileName, ".xml"); /// /// Gets the full path to the configuration file. /// /// The configuration file path. public string ConfigurationFilePath => Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName); /// /// Gets the plugin configuration. /// /// The configuration. BasePluginConfiguration IHasPluginConfiguration.Configuration => Configuration; /// /// Saves the current configuration to the file system. /// /// Configuration to save. public virtual void SaveConfiguration(TConfigurationType config) { lock (_configurationSaveLock) { var folder = Path.GetDirectoryName(ConfigurationFilePath); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } XmlSerializer.SerializeToFile(config, ConfigurationFilePath); } } /// /// Saves the current configuration to the file system. /// public virtual void SaveConfiguration() { SaveConfiguration(Configuration); } /// public virtual void UpdateConfiguration(BasePluginConfiguration configuration) { ArgumentNullException.ThrowIfNull(configuration); Configuration = (TConfigurationType)configuration; SaveConfiguration(Configuration); ConfigurationChanged?.Invoke(this, configuration); } /// public override PluginInfo GetPluginInfo() { var info = base.GetPluginInfo(); info.ConfigurationFileName = ConfigurationFileName; return info; } private TConfigurationType LoadConfiguration() { var path = ConfigurationFilePath; try { return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path); } catch { var config = (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); SaveConfiguration(config); return config; } } } }