BasePlugin.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #pragma warning disable SA1402
  2. using System;
  3. using System.IO;
  4. using System.Reflection;
  5. using MediaBrowser.Common.Configuration;
  6. using MediaBrowser.Model.Plugins;
  7. using MediaBrowser.Model.Serialization;
  8. using Microsoft.Extensions.DependencyInjection;
  9. namespace MediaBrowser.Common.Plugins
  10. {
  11. /// <summary>
  12. /// Provides a common base class for all plugins.
  13. /// </summary>
  14. public abstract class BasePlugin : IPlugin, IPluginAssembly
  15. {
  16. /// <summary>
  17. /// Gets the name of the plugin.
  18. /// </summary>
  19. /// <value>The name.</value>
  20. public abstract string Name { get; }
  21. /// <summary>
  22. /// Gets the description.
  23. /// </summary>
  24. /// <value>The description.</value>
  25. public virtual string Description => string.Empty;
  26. /// <summary>
  27. /// Gets the unique id.
  28. /// </summary>
  29. /// <value>The unique id.</value>
  30. public virtual Guid Id { get; private set; }
  31. /// <summary>
  32. /// Gets the plugin version.
  33. /// </summary>
  34. /// <value>The version.</value>
  35. public Version Version { get; private set; }
  36. /// <summary>
  37. /// Gets the path to the assembly file.
  38. /// </summary>
  39. /// <value>The assembly file path.</value>
  40. public string AssemblyFilePath { get; private set; }
  41. /// <summary>
  42. /// Gets the full path to the data folder, where the plugin can store any miscellaneous files needed.
  43. /// </summary>
  44. /// <value>The data folder path.</value>
  45. public string DataFolderPath { get; private set; }
  46. /// <summary>
  47. /// Gets a value indicating whether the plugin can be uninstalled.
  48. /// </summary>
  49. public bool CanUninstall => !Path.GetDirectoryName(AssemblyFilePath)
  50. .Equals(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), StringComparison.InvariantCulture);
  51. /// <summary>
  52. /// Gets the plugin info.
  53. /// </summary>
  54. /// <returns>PluginInfo.</returns>
  55. public virtual PluginInfo GetPluginInfo()
  56. {
  57. var info = new PluginInfo
  58. {
  59. Name = Name,
  60. Version = Version.ToString(),
  61. Description = Description,
  62. Id = Id.ToString(),
  63. CanUninstall = CanUninstall
  64. };
  65. return info;
  66. }
  67. /// <summary>
  68. /// Called just before the plugin is uninstalled from the server.
  69. /// </summary>
  70. public virtual void OnUninstalling()
  71. {
  72. }
  73. /// <inheritdoc />
  74. public virtual void RegisterServices(IServiceCollection serviceCollection)
  75. {
  76. }
  77. /// <inheritdoc />
  78. public virtual void UnregisterServices(IServiceCollection serviceCollection)
  79. {
  80. }
  81. /// <inheritdoc />
  82. public void SetAttributes(string assemblyFilePath, string dataFolderPath, Version assemblyVersion)
  83. {
  84. AssemblyFilePath = assemblyFilePath;
  85. DataFolderPath = dataFolderPath;
  86. Version = assemblyVersion;
  87. }
  88. /// <inheritdoc />
  89. public void SetId(Guid assemblyId)
  90. {
  91. Id = assemblyId;
  92. }
  93. }
  94. /// <summary>
  95. /// Provides a common base class for all plugins.
  96. /// </summary>
  97. /// <typeparam name="TConfigurationType">The type of the T configuration type.</typeparam>
  98. public abstract class BasePlugin<TConfigurationType> : BasePlugin, IHasPluginConfiguration
  99. where TConfigurationType : BasePluginConfiguration
  100. {
  101. /// <summary>
  102. /// The configuration sync lock.
  103. /// </summary>
  104. private readonly object _configurationSyncLock = new object();
  105. /// <summary>
  106. /// The configuration save lock.
  107. /// </summary>
  108. private readonly object _configurationSaveLock = new object();
  109. private Action<string> _directoryCreateFn;
  110. /// <summary>
  111. /// The configuration.
  112. /// </summary>
  113. private TConfigurationType _configuration;
  114. /// <summary>
  115. /// Initializes a new instance of the <see cref="BasePlugin{TConfigurationType}" /> class.
  116. /// </summary>
  117. /// <param name="applicationPaths">The application paths.</param>
  118. /// <param name="xmlSerializer">The XML serializer.</param>
  119. protected BasePlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
  120. {
  121. ApplicationPaths = applicationPaths;
  122. XmlSerializer = xmlSerializer;
  123. }
  124. /// <summary>
  125. /// Gets the application paths.
  126. /// </summary>
  127. /// <value>The application paths.</value>
  128. protected IApplicationPaths ApplicationPaths { get; private set; }
  129. /// <summary>
  130. /// Gets the XML serializer.
  131. /// </summary>
  132. /// <value>The XML serializer.</value>
  133. protected IXmlSerializer XmlSerializer { get; private set; }
  134. /// <summary>
  135. /// Gets the type of configuration this plugin uses.
  136. /// </summary>
  137. /// <value>The type of the configuration.</value>
  138. public Type ConfigurationType => typeof(TConfigurationType);
  139. /// <summary>
  140. /// Gets the name the assembly file.
  141. /// </summary>
  142. /// <value>The name of the assembly file.</value>
  143. protected string AssemblyFileName => Path.GetFileName(AssemblyFilePath);
  144. /// <summary>
  145. /// Gets or sets the plugin configuration.
  146. /// </summary>
  147. /// <value>The configuration.</value>
  148. public TConfigurationType Configuration
  149. {
  150. get
  151. {
  152. // Lazy load
  153. if (_configuration == null)
  154. {
  155. lock (_configurationSyncLock)
  156. {
  157. if (_configuration == null)
  158. {
  159. _configuration = LoadConfiguration();
  160. }
  161. }
  162. }
  163. return _configuration;
  164. }
  165. protected set => _configuration = value;
  166. }
  167. /// <summary>
  168. /// Gets the name of the configuration file. Subclasses should override.
  169. /// </summary>
  170. /// <value>The name of the configuration file.</value>
  171. public virtual string ConfigurationFileName => Path.ChangeExtension(AssemblyFileName, ".xml");
  172. /// <summary>
  173. /// Gets the full path to the configuration file.
  174. /// </summary>
  175. /// <value>The configuration file path.</value>
  176. public string ConfigurationFilePath => Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName);
  177. /// <summary>
  178. /// Gets the plugin configuration.
  179. /// </summary>
  180. /// <value>The configuration.</value>
  181. BasePluginConfiguration IHasPluginConfiguration.Configuration => Configuration;
  182. /// <inheritdoc />
  183. public void SetStartupInfo(Action<string> directoryCreateFn)
  184. {
  185. // hack alert, until the .net core transition is complete
  186. _directoryCreateFn = directoryCreateFn;
  187. }
  188. private TConfigurationType LoadConfiguration()
  189. {
  190. var path = ConfigurationFilePath;
  191. try
  192. {
  193. return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path);
  194. }
  195. catch
  196. {
  197. return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
  198. }
  199. }
  200. /// <summary>
  201. /// Saves the current configuration to the file system.
  202. /// </summary>
  203. public virtual void SaveConfiguration()
  204. {
  205. lock (_configurationSaveLock)
  206. {
  207. _directoryCreateFn(Path.GetDirectoryName(ConfigurationFilePath));
  208. XmlSerializer.SerializeToFile(Configuration, ConfigurationFilePath);
  209. }
  210. }
  211. /// <inheritdoc />
  212. public virtual void UpdateConfiguration(BasePluginConfiguration configuration)
  213. {
  214. if (configuration == null)
  215. {
  216. throw new ArgumentNullException(nameof(configuration));
  217. }
  218. Configuration = (TConfigurationType)configuration;
  219. SaveConfiguration();
  220. }
  221. /// <inheritdoc />
  222. public override PluginInfo GetPluginInfo()
  223. {
  224. var info = base.GetPluginInfo();
  225. info.ConfigurationFileName = ConfigurationFileName;
  226. return info;
  227. }
  228. }
  229. }