< Summary - Combined Code Coverage

Information
Class: NLightning.Daemon.Services.PluginLoaderService
Assembly: NLightning.Daemon
File(s): /home/runner/work/NLightning/NLightning/src/NLightning.Daemon/Services/PluginLoaderService.cs
Tag: 57_24045730253
Line coverage
0%
Covered lines: 0
Uncovered lines: 36
Coverable lines: 36
Total lines: 72
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
StartAsync()0%4260%
StopAsync()0%620%

File(s)

/home/runner/work/NLightning/NLightning/src/NLightning.Daemon/Services/PluginLoaderService.cs

#LineLine coverage
 1using System.Runtime.Loader;
 2using Microsoft.Extensions.Configuration;
 3using Microsoft.Extensions.DependencyInjection;
 4using Microsoft.Extensions.Hosting;
 5using Microsoft.Extensions.Logging;
 6
 7namespace NLightning.Daemon.Services;
 8
 9using Models;
 10using Plugins;
 11
 12public class PluginLoaderService : IHostedService
 13{
 14    private readonly IServiceProvider _services;
 15    private readonly IConfiguration _config;
 16    private readonly ILogger<PluginLoaderService> _logger;
 017    private readonly List<(IDaemonPlugin Plugin, AssemblyLoadContext Alc)> _plugins = new();
 18
 019    public PluginLoaderService(IServiceProvider services, IConfiguration config, ILogger<PluginLoaderService> logger)
 20    {
 021        _services = services;
 022        _config = config;
 023        _logger = logger;
 024    }
 25
 26    public async Task StartAsync(CancellationToken cancellationToken)
 27    {
 028        var entries = _config.GetSection("Plugins").Get<List<PluginEntry>>() ?? [];
 029        foreach (var entry in entries)
 30        {
 31            try
 32            {
 033                var alc = new AssemblyLoadContext(Path.GetFileNameWithoutExtension(entry.AssemblyPath),
 034                                                  isCollectible: true);
 035                await using var stream = File.OpenRead(entry.AssemblyPath);
 036                var asm = alc.LoadFromStream(stream);
 37
 038                var pluginType = string.IsNullOrWhiteSpace(entry.TypeName)
 039                                     ? asm.ExportedTypes.First(t => typeof(IDaemonPlugin).IsAssignableFrom(t) &&
 040                                                                    !t.IsAbstract)
 041                                     : asm.GetType(entry.TypeName!, throwOnError: true)!;
 42
 043                var plugin = (IDaemonPlugin)ActivatorUtilities.CreateInstance(
 044                    _services, pluginType);
 45
 046                var context = _services.GetRequiredService<IDaemonContext>();
 047                await plugin.StartAsync(context, cancellationToken);
 48
 049                _plugins.Add((plugin, alc));
 050                _logger.LogInformation("Loaded plugin {Plugin}", pluginType.FullName);
 051            }
 052            catch (Exception ex)
 53            {
 054                _logger.LogError(ex, "Failed to load plugin from {Path}", entry.AssemblyPath);
 055            }
 056        }
 057    }
 58
 59    public async Task StopAsync(CancellationToken cancellationToken)
 60    {
 061        foreach (var (plugin, alc) in _plugins)
 62        {
 063            try { await plugin.StopAsync(cancellationToken); }
 064            catch (Exception ex) { _logger.LogWarning(ex, "Error stopping plugin {Name}", plugin.Name); }
 65
 066            await plugin.DisposeAsync();
 067            alc.Unload();
 068        }
 69
 070        _plugins.Clear();
 071    }
 72}