using SQLLinter.Common; using SQLLinter.Common.Helpers; using SQLLinter.Core.Interfaces; using SQLLinter.Infrastructure.Parser; namespace SQLLinter.Infrastructure.Plugins { public class PluginHandler : IPluginHandler { private readonly IConfig _config; private readonly IAssemblyWrapper _assemblyWrapper; private readonly IReporter _reporter; private readonly IFileversionWrapper _versionWrapper; private List _ruleTypes = new(); private Dictionary _rules = new(); public IList Rules => _rules.Values.ToList(); public IDictionary RuleWithNames => _rules; public PluginHandler(IReporter reporter, IConfig config) : this(reporter, new AssemblyWrapper(), new VersionInfoWrapper(), config) { } public PluginHandler( IReporter reporter, IAssemblyWrapper assemblyWrapper, IFileversionWrapper versionWrapper, IConfig config ) { this._reporter = reporter; this._assemblyWrapper = assemblyWrapper; this._versionWrapper = versionWrapper; this._config = config; LoadDefaultRules(); LoadPlugins(); } private void ActivatePlugin(Type type) { var instance = (IRule?)Activator.CreateInstance(type); if (instance == null) { _reporter.Report($"Ошибка создания экземпляра правила '{type.FullName}'"); return; } var ruleName = instance.Name; if (_config.Rules.TryGetValue(ruleName, out var severity)) { instance.Severity = severity; } if (instance.Severity == RuleViolationSeverity.Off) { _reporter.Report($"Правило '{ruleName}' выключено"); return; } if (_rules.ContainsKey(ruleName)) { _reporter.Report($"Ошибка добавления правила '{type.FullName}': правило '{ruleName}' уже создано"); return; } _rules.Add(ruleName, instance); _reporter.Report($"Правило '{ruleName}' ({instance.Severity}) добавлено с типом '{type.FullName}'"); } private void LoadDefaultRules() { //Загрузка дефолтных правил var defaultRuleTypes = RuleVisitorFriendlyNameTypeMap.DefaultRuleTypes; defaultRuleTypes.ForEach(AddRuleType); } private void AddRuleType(Type ruleType) { if (_ruleTypes.Contains(ruleType)) { _reporter.Report($"Уже загружено правило '{ruleType.FullName}'"); return; } _ruleTypes.Add(ruleType); _reporter.Report($"Добавлено правило '{ruleType.FullName}'"); ActivatePlugin(ruleType); } private void LoadPlugins() { var paths = FileHelpers.FindFilesWithMask(_config.Plugins); //Загрузка плагинов foreach (var path in paths) { if (!File.Exists(path)) { _reporter.Report($"Ошибка загрузки плагина '{path}': Файл не найден."); } else if (Path.GetExtension(path)?.ToLower() != "dll") { _reporter.Report($"Ошибка загрузки плагина '{path}': Неподдерживаемый формат файла. Ожидается файл с расширением .dll."); } else { LoadPlugin(path); } } } private void LoadPlugin(string path) { var dll = _assemblyWrapper.LoadFrom(path); var version = _versionWrapper.GetVersion(dll); foreach (var type in _assemblyWrapper.GetExportedTypes(dll)) { var rules = RuleVisitorFriendlyNameTypeMap.GetRuleTypes(dll); rules.ForEach(AddRuleType); } } } }