#region License Information /* HeuristicLab * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Web; using System.Web.Http; namespace HeuristicLab.Services.WebApp { public class PluginManager { private static PluginManager instance; public static PluginManager Instance { get { return instance ?? (instance = new PluginManager()); } } private readonly IDictionary plugins; public HttpConfiguration Configuration { get; set; } public IEnumerable Plugins { get { return plugins.Values; } } public static string PluginsDirectory { get { return Path.Combine(HttpRuntime.AppDomainAppPath, "WebApp", "plugins"); } } public PluginManager() { plugins = new ConcurrentDictionary(); var fileWatcher = new FileSystemWatcher(PluginsDirectory, "*") { IncludeSubdirectories = true, EnableRaisingEvents = true }; fileWatcher.Created += OnFilesChanged; fileWatcher.Changed += OnFilesChanged; fileWatcher.Deleted += OnFilesChanged; fileWatcher.Renamed += OnFilesChanged; } private void OnFilesChanged(object sender, FileSystemEventArgs args) { string path = args.FullPath.Remove(0, PluginsDirectory.Length + 1); var pathParts = path.Split(Path.DirectorySeparatorChar); string pluginName = pathParts[0]; if (pathParts.Length <= 2) { switch (args.ChangeType) { case WatcherChangeTypes.Created: GetPlugin(pluginName); break; case WatcherChangeTypes.Deleted: plugins.Remove(pluginName); break; case WatcherChangeTypes.Renamed: RenamedEventArgs renamedArgs = (RenamedEventArgs)args; string oldPath = renamedArgs.OldFullPath.Remove(0, PluginsDirectory.Length + 1); var oldPathParts = oldPath.Split(Path.DirectorySeparatorChar); string oldPluginName = oldPathParts[0]; plugins.Remove(oldPluginName); GetPlugin(pluginName); break; case WatcherChangeTypes.Changed: Plugin plugin = LookupPlugin(pluginName); if (plugin != null) { plugin.ReloadControllers(); } break; } } } public Plugin GetPlugin(string name) { Plugin plugin = LookupPlugin(name); if (plugin == null) { string directory = Path.Combine(PluginsDirectory, name); if (Directory.Exists(directory)) { plugin = new Plugin(name, directory, Configuration); plugins.Add(name, plugin); } } return plugin; } public IEnumerable GetPlugins() { return plugins.Values; } public void DiscoverPlugins() { var pluginDirectories = Directory.GetDirectories(PluginsDirectory); foreach (var directory in pluginDirectories) { string pluginName = Path.GetFileName(directory); Plugin plugin = LookupPlugin(pluginName); if (plugin == null) { plugin = new Plugin(pluginName, directory, Configuration); plugins.Add(pluginName, plugin); } } } private Plugin LookupPlugin(string name) { Plugin plugin; plugins.TryGetValue(name, out plugin); return plugin; } } }