feat: introduce plugin host and DI infrastructure

This commit is contained in:
Vladimir Moushkov
2025-10-03 19:37:10 +03:00
parent 3abec27cf4
commit 192b0add77
86 changed files with 922 additions and 163 deletions

View File

@@ -680,3 +680,39 @@ If you want me to produce **starter EF models + migrations** and a **full `feeds
---
The sections above convert the role taxonomy from IMPLEMENTATION.md into actionable playbooks while keeping the authoritative architecture and data contracts inline with this guide. Use them to bootstrap work, then dive into ARCHITECTURE.md and IMPLEMENTATION.md for exhaustive references and sprint-by-sprint sequencing.
### Dependency Injection Registration Baseline
- Every product or library that needs DI registration must expose a `<ProductNamespace>.DependencyInjection` namespace/folder containing one or more implementations of `StellaOps.DependencyInjection.IDependencyInjectionRoutine`.
- When distributing only a subset of connectors/exporters, create a dedicated solution that references just the desired plugin projects; the shared build rules always emit every `StellaOps.Feedser.Source.*` and `StellaOps.Feedser.Exporter.*` assembly into `PluginBinaries` by default.
- The `IDependencyInjectionRoutine` interface lives in `src/__Libraries/StellaOps.DependencyInjection` and enables both static opt-in registration and reflection-driven root composition.
- Each library should provide static helpers that wrap its DI registrations and a thin routine class that forwards to those helpers, for example:
```csharp
public interface IDependencyInjectionRoutine
{
IServiceCollection Register(
IServiceCollection services,
IConfiguration configuration);
}
public static class NamespaceLibrary
{
public static IServiceCollection RegisterNamespaceLibrary(
IServiceCollection services,
IConfiguration configuration)
{
// ...
return services;
}
}
public sealed class DependencyInjectionRoutine : IDependencyInjectionRoutine
{
public IServiceCollection Register(
IServiceCollection services,
IConfiguration configuration)
{
return NamespaceLibrary.RegisterNamespaceLibrary(services, configuration);
}
}
```

View File

@@ -0,0 +1,14 @@
<Project>
<PropertyGroup>
<FeedserPluginOutputRoot Condition="'$(FeedserPluginOutputRoot)' == ''">$(SolutionDir)PluginBinaries</FeedserPluginOutputRoot>
<IsFeedserPlugin Condition="'$(IsFeedserPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Feedser.Source.'))">true</IsFeedserPlugin>
<IsFeedserPlugin Condition="'$(IsFeedserPlugin)' == '' and $([System.String]::Copy('$(MSBuildProjectName)').StartsWith('StellaOps.Feedser.Exporter.'))">true</IsFeedserPlugin>
</PropertyGroup>
<ItemGroup>
<ProjectReference Update="..\..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,17 @@
<Project>
<Target Name="FeedserCopyPluginArtifacts" AfterTargets="Build" Condition="'$(IsFeedserPlugin)' == 'true'">
<PropertyGroup>
<FeedserPluginOutputDirectory>$(FeedserPluginOutputRoot)\$(MSBuildProjectName)</FeedserPluginOutputDirectory>
</PropertyGroup>
<MakeDir Directories="$(FeedserPluginOutputDirectory)" />
<ItemGroup>
<FeedserPluginArtifacts Include="$(TargetPath)" />
<FeedserPluginArtifacts Include="$(TargetPath).deps.json" Condition="Exists('$(TargetPath).deps.json')" />
<FeedserPluginArtifacts Include="$(TargetDir)$(TargetName).pdb" Condition="Exists('$(TargetDir)$(TargetName).pdb')" />
</ItemGroup>
<Copy SourceFiles="@(FeedserPluginArtifacts)" DestinationFolder="$(FeedserPluginOutputDirectory)" SkipUnchangedFiles="true" />
</Target>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Core;
@@ -58,3 +58,4 @@ public static class PluginBootstrapper
public object? GetService(Type serviceType) => null;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -13,6 +13,7 @@
<ProjectReference Include="../StellaOps.Feedser.Merge/StellaOps.Feedser.Merge.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Exporter.Json/StellaOps.Feedser.Exporter.Json.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Exporter.TrivyDb/StellaOps.Feedser.Exporter.TrivyDb.csproj" />
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Exporter.Json;
@@ -22,3 +22,4 @@ public sealed class JsonExporterPlugin : IExporterPlugin
public Task ExportAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,7 +7,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Exporter.TrivyDb;
@@ -22,3 +22,4 @@ public sealed class TrivyDbExporterPlugin : IExporterPlugin
public Task ExportAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,7 +7,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Acsc;
@@ -26,3 +26,4 @@ public sealed class AcscConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Cccs;
@@ -26,3 +26,4 @@ public sealed class CccsConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.CertBund;
@@ -26,3 +26,4 @@ public sealed class CertBundConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.CertCc;
@@ -26,3 +26,4 @@ public sealed class CertCcConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.CertFr;
@@ -26,3 +26,4 @@ public sealed class CertFrConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.CertIn;
@@ -26,3 +26,4 @@ public sealed class CertInConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,8 +7,9 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Cve;
@@ -26,3 +26,4 @@ public sealed class CveConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Distro.Debian;
@@ -26,3 +26,4 @@ public sealed class DistroDebianConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Distro.RedHat;
@@ -26,3 +26,4 @@ public sealed class DistroRedHatConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Distro.Suse;
@@ -26,3 +26,4 @@ public sealed class DistroSuseConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Distro.Ubuntu;
@@ -26,3 +26,4 @@ public sealed class DistroUbuntuConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Ghsa;
@@ -26,3 +26,4 @@ public sealed class GhsaConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Ics.Cisa;
@@ -26,3 +26,4 @@ public sealed class IcsCisaConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Ics.Kaspersky;
@@ -26,3 +26,4 @@ public sealed class IcsKasperskyConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Jvn;
@@ -26,3 +26,4 @@ public sealed class JvnConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Kev;
@@ -26,3 +26,4 @@ public sealed class KevConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Kisa;
@@ -26,3 +26,4 @@ public sealed class KisaConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Nvd;
@@ -26,3 +26,4 @@ public sealed class NvdConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Osv;
@@ -26,3 +26,4 @@ public sealed class OsvConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Ru.Bdu;
@@ -26,3 +26,4 @@ public sealed class RuBduConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Ru.Nkcki;
@@ -26,3 +26,4 @@ public sealed class RuNkckiConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Adobe;
@@ -26,3 +26,4 @@ public sealed class VndrAdobeConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Apple;
@@ -26,3 +26,4 @@ public sealed class VndrAppleConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Chromium;
@@ -26,3 +26,4 @@ public sealed class VndrChromiumConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Cisco;
@@ -26,3 +26,4 @@ public sealed class VndrCiscoConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Msrc;
@@ -26,3 +26,4 @@ public sealed class VndrMsrcConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Oracle;
@@ -26,3 +26,4 @@ public sealed class VndrOracleConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Source.Vndr.Vmware;
@@ -26,3 +26,4 @@ public sealed class VndrVmwareConnectorPlugin : IConnectorPlugin
public Task MapAsync(IServiceProvider services, CancellationToken cancellationToken) => Task.CompletedTask;
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellOps.AddOn/StellOps.AddOn.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Models/StellaOps.Feedser.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,5 @@
using StellaOps.Feedser.Core;
using StellOps.AddOn;
using StellaOps.Plugin;
namespace StellaOps.Feedser.Tests;
@@ -28,3 +28,4 @@ public class PluginLoaderTests
Assert.Contains(plugins, p => p.Name == "json");
}
}

View File

@@ -1,6 +1,36 @@
using System.IO;
using StellaOps.Plugin.DependencyInjection;
using StellaOps.Plugin.Hosting;
var builder = WebApplication.CreateBuilder(args);
var pluginHostOptions = builder.Configuration
.GetSection("PluginHost")
.Get<PluginHostOptions>() ?? new PluginHostOptions();
var solutionRoot = Path.GetFullPath(Path.Combine(builder.Environment.ContentRootPath, ".."));
if (string.IsNullOrWhiteSpace(pluginHostOptions.BaseDirectory))
{
pluginHostOptions.BaseDirectory = solutionRoot;
}
if (string.IsNullOrWhiteSpace(pluginHostOptions.PluginsDirectory))
{
pluginHostOptions.PluginsDirectory = "PluginBinaries";
}
if (pluginHostOptions.SearchPatterns.Count == 0)
{
pluginHostOptions.SearchPatterns.Add("StellaOps.Feedser.Plugin.*.dll");
}
pluginHostOptions.EnsureDirectoryExists = true;
builder.Services.RegisterPluginRoutines(builder.Configuration, pluginHostOptions);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
app.Run();

View File

@@ -7,39 +7,41 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../StellaOps.Feedser.Core/StellaOps.Feedser.Core.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Core\StellaOps.Feedser.Core.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../StellaOps.Feedser.Source.Acsc/StellaOps.Feedser.Source.Acsc.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Cccs/StellaOps.Feedser.Source.Cccs.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.CertBund/StellaOps.Feedser.Source.CertBund.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.CertCc/StellaOps.Feedser.Source.CertCc.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.CertFr/StellaOps.Feedser.Source.CertFr.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.CertIn/StellaOps.Feedser.Source.CertIn.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Common/StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Cve/StellaOps.Feedser.Source.Cve.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Distro.Debian/StellaOps.Feedser.Source.Distro.Debian.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Distro.RedHat/StellaOps.Feedser.Source.Distro.RedHat.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Distro.Suse/StellaOps.Feedser.Source.Distro.Suse.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Distro.Ubuntu/StellaOps.Feedser.Source.Distro.Ubuntu.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Ghsa/StellaOps.Feedser.Source.Ghsa.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Ics.Cisa/StellaOps.Feedser.Source.Ics.Cisa.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Ics.Kaspersky/StellaOps.Feedser.Source.Ics.Kaspersky.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Jvn/StellaOps.Feedser.Source.Jvn.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Kev/StellaOps.Feedser.Source.Kev.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Kisa/StellaOps.Feedser.Source.Kisa.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Nvd/StellaOps.Feedser.Source.Nvd.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Osv/StellaOps.Feedser.Source.Osv.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Ru.Bdu/StellaOps.Feedser.Source.Ru.Bdu.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Ru.Nkcki/StellaOps.Feedser.Source.Ru.Nkcki.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Adobe/StellaOps.Feedser.Source.Vndr.Adobe.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Apple/StellaOps.Feedser.Source.Vndr.Apple.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Chromium/StellaOps.Feedser.Source.Vndr.Chromium.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Cisco/StellaOps.Feedser.Source.Vndr.Cisco.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Msrc/StellaOps.Feedser.Source.Vndr.Msrc.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Oracle/StellaOps.Feedser.Source.Vndr.Oracle.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Source.Vndr.Vmware/StellaOps.Feedser.Source.Vndr.Vmware.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Exporter.Json/StellaOps.Feedser.Exporter.Json.csproj" />
<ProjectReference Include="../StellaOps.Feedser.Exporter.TrivyDb/StellaOps.Feedser.Exporter.TrivyDb.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Acsc\StellaOps.Feedser.Source.Acsc.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Cccs\StellaOps.Feedser.Source.Cccs.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.CertBund\StellaOps.Feedser.Source.CertBund.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.CertCc\StellaOps.Feedser.Source.CertCc.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.CertFr\StellaOps.Feedser.Source.CertFr.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.CertIn\StellaOps.Feedser.Source.CertIn.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Common\StellaOps.Feedser.Source.Common.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Cve\StellaOps.Feedser.Source.Cve.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Distro.Debian\StellaOps.Feedser.Source.Distro.Debian.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Distro.RedHat\StellaOps.Feedser.Source.Distro.RedHat.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Distro.Suse\StellaOps.Feedser.Source.Distro.Suse.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Distro.Ubuntu\StellaOps.Feedser.Source.Distro.Ubuntu.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Ghsa\StellaOps.Feedser.Source.Ghsa.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Ics.Cisa\StellaOps.Feedser.Source.Ics.Cisa.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Ics.Kaspersky\StellaOps.Feedser.Source.Ics.Kaspersky.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Jvn\StellaOps.Feedser.Source.Jvn.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Kev\StellaOps.Feedser.Source.Kev.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Kisa\StellaOps.Feedser.Source.Kisa.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Nvd\StellaOps.Feedser.Source.Nvd.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Osv\StellaOps.Feedser.Source.Osv.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Ru.Bdu\StellaOps.Feedser.Source.Ru.Bdu.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Ru.Nkcki\StellaOps.Feedser.Source.Ru.Nkcki.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Adobe\StellaOps.Feedser.Source.Vndr.Adobe.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Apple\StellaOps.Feedser.Source.Vndr.Apple.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Chromium\StellaOps.Feedser.Source.Vndr.Chromium.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Cisco\StellaOps.Feedser.Source.Vndr.Cisco.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Msrc\StellaOps.Feedser.Source.Vndr.Msrc.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Oracle\StellaOps.Feedser.Source.Vndr.Oracle.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Source.Vndr.Vmware\StellaOps.Feedser.Source.Vndr.Vmware.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Exporter.Json\StellaOps.Feedser.Exporter.Json.csproj" />
<ProjectReference Include="..\StellaOps.Feedser.Exporter.TrivyDb\StellaOps.Feedser.Exporter.TrivyDb.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,9 +1,16 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"PluginHost": {
"PluginsDirectory": "PluginBinaries",
"PrimaryPrefix": "StellaOps.Feedser",
"SearchPatterns": [
"StellaOps.Feedser.Plugin.*.dll"
]
}
}

View File

@@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
@@ -25,7 +25,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Exporter.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Exporter.TrivyDb", "StellaOps.Feedser.Exporter.TrivyDb\StellaOps.Feedser.Exporter.TrivyDb.csproj", "{4D936BC4-5520-4642-A237-4106E97BC7A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellOps.AddOn", "..\__Libraries\StellOps.AddOn\StellOps.AddOn.csproj", "{B85C1C0E-B245-44FB-877E-C112DE29041A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Plugin", "..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj", "{B85C1C0E-B245-44FB-877E-C112DE29041A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.WebService", "StellaOps.Feedser.WebService\StellaOps.Feedser.WebService.csproj", "{2C970A0F-FE3D-425B-B1B3-A008B194F5C2}"
EndProject
@@ -81,6 +81,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Source.Gh
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Feedser.Source.Distro.RedHat", "StellaOps.Feedser.Source.Distro.RedHat\StellaOps.Feedser.Source.Distro.RedHat.csproj", "{A4DBF88F-34D0-4A05-ACCE-DE080F912FDB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.DependencyInjection", "..\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj", "{F622D38D-DA49-473E-B724-E706F8113CF2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -559,6 +561,18 @@ Global
{A4DBF88F-34D0-4A05-ACCE-DE080F912FDB}.Release|x64.Build.0 = Release|Any CPU
{A4DBF88F-34D0-4A05-ACCE-DE080F912FDB}.Release|x86.ActiveCfg = Release|Any CPU
{A4DBF88F-34D0-4A05-ACCE-DE080F912FDB}.Release|x86.Build.0 = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|x64.ActiveCfg = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|x64.Build.0 = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|x86.ActiveCfg = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Debug|x86.Build.0 = Debug|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|Any CPU.Build.0 = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|x64.ActiveCfg = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|x64.Build.0 = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|x86.ActiveCfg = Release|Any CPU
{F622D38D-DA49-473E-B724-E706F8113CF2}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,11 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace StellaOps.DependencyInjection;
public interface IDependencyInjectionRoutine
{
IServiceCollection Register(
IServiceCollection services,
IConfiguration configuration);
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,91 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StellaOps.DependencyInjection;
using StellaOps.Plugin.Hosting;
using StellaOps.Plugin.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
namespace StellaOps.Plugin.DependencyInjection;
public static class PluginDependencyInjectionExtensions
{
public static IServiceCollection RegisterPluginRoutines(
this IServiceCollection services,
IConfiguration configuration,
PluginHostOptions options,
ILogger? logger = null)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
var loadResult = PluginHost.LoadPlugins(options, logger);
foreach (var plugin in loadResult.Plugins)
{
foreach (var routine in CreateRoutines(plugin.Assembly))
{
logger?.LogDebug(
"Registering DI routine '{RoutineType}' from plugin '{PluginAssembly}'.",
routine.GetType().FullName,
plugin.Assembly.FullName);
routine.Register(services, configuration);
}
}
if (loadResult.MissingOrderedPlugins.Count > 0)
{
logger?.LogWarning(
"Some ordered plugins were not found: {Missing}",
string.Join(", ", loadResult.MissingOrderedPlugins));
}
return services;
}
private static IEnumerable<IDependencyInjectionRoutine> CreateRoutines(System.Reflection.Assembly assembly)
{
foreach (var type in assembly.GetLoadableTypes())
{
if (type is null || type.IsAbstract || type.IsInterface)
{
continue;
}
if (!typeof(IDependencyInjectionRoutine).IsAssignableFrom(type))
{
continue;
}
object? instance;
try
{
instance = Activator.CreateInstance(type);
}
catch
{
continue;
}
if (instance is IDependencyInjectionRoutine routine)
{
yield return routine;
}
}
}
}

View File

@@ -0,0 +1,26 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.DependencyInjection;
namespace StellaOps.Plugin.DependencyInjection;
public static class StellaOpsPluginRegistration
{
public static IServiceCollection RegisterStellaOpsPlugin(
this IServiceCollection services,
IConfiguration configuration)
{
// No-op today but reserved for future plugin infrastructure services.
return services;
}
}
public sealed class DependencyInjectionRoutine : IDependencyInjectionRoutine
{
public IServiceCollection Register(
IServiceCollection services,
IConfiguration configuration)
{
return services.RegisterStellaOpsPlugin(configuration);
}
}

View File

@@ -0,0 +1,21 @@
using System.Reflection;
namespace StellaOps.Plugin.Hosting;
public sealed class PluginAssembly
{
internal PluginAssembly(string assemblyPath, Assembly assembly, PluginLoadContext loadContext)
{
AssemblyPath = assemblyPath;
Assembly = assembly;
LoadContext = loadContext;
}
public string AssemblyPath { get; }
public Assembly Assembly { get; }
internal PluginLoadContext LoadContext { get; }
public override string ToString() => Assembly.FullName ?? AssemblyPath;
}

View File

@@ -0,0 +1,216 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
namespace StellaOps.Plugin.Hosting;
public static class PluginHost
{
private static readonly object Sync = new();
private static readonly Dictionary<string, PluginAssembly> LoadedPlugins = new(StringComparer.OrdinalIgnoreCase);
public static PluginHostResult LoadPlugins(PluginHostOptions options, ILogger? logger = null)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
var baseDirectory = options.ResolveBaseDirectory();
var pluginDirectory = ResolvePluginDirectory(options, baseDirectory);
if (options.EnsureDirectoryExists && !Directory.Exists(pluginDirectory))
{
Directory.CreateDirectory(pluginDirectory);
}
if (!Directory.Exists(pluginDirectory))
{
logger?.LogWarning("Plugin directory '{PluginDirectory}' does not exist; no plugins will be loaded.", pluginDirectory);
return new PluginHostResult(pluginDirectory, Array.Empty<string>(), Array.Empty<PluginAssembly>(), Array.Empty<string>());
}
var searchPatterns = BuildSearchPatterns(options, pluginDirectory);
var discovered = DiscoverPluginFiles(pluginDirectory, searchPatterns, options.RecursiveSearch, logger);
var orderedFiles = ApplyExplicitOrdering(discovered, options.PluginOrder, out var missingOrderedNames);
var loaded = new List<PluginAssembly>(orderedFiles.Count);
lock (Sync)
{
foreach (var file in orderedFiles)
{
if (LoadedPlugins.TryGetValue(file, out var existing))
{
loaded.Add(existing);
continue;
}
try
{
var loadContext = new PluginLoadContext(file);
var assembly = loadContext.LoadFromAssemblyPath(file);
var descriptor = new PluginAssembly(file, assembly, loadContext);
LoadedPlugins[file] = descriptor;
loaded.Add(descriptor);
logger?.LogInformation("Loaded plugin assembly '{Assembly}' from '{Path}'.", assembly.FullName, file);
}
catch (Exception ex)
{
logger?.LogError(ex, "Failed to load plugin assembly from '{Path}'.", file);
}
}
}
var missingOrdered = new ReadOnlyCollection<string>(missingOrderedNames);
return new PluginHostResult(pluginDirectory, searchPatterns, new ReadOnlyCollection<PluginAssembly>(loaded), missingOrdered);
}
private static string ResolvePluginDirectory(PluginHostOptions options, string baseDirectory)
{
if (string.IsNullOrWhiteSpace(options.PluginsDirectory))
{
return Path.Combine(baseDirectory, "PluginBinaries");
}
if (Path.IsPathRooted(options.PluginsDirectory))
{
return options.PluginsDirectory;
}
return Path.Combine(baseDirectory, options.PluginsDirectory);
}
private static IReadOnlyList<string> BuildSearchPatterns(PluginHostOptions options, string pluginDirectory)
{
var patterns = new List<string>();
if (options.SearchPatterns.Count > 0)
{
patterns.AddRange(options.SearchPatterns);
}
else
{
var prefixes = new List<string>();
if (!string.IsNullOrWhiteSpace(options.PrimaryPrefix))
{
prefixes.Add(options.PrimaryPrefix);
}
else if (System.Reflection.Assembly.GetEntryAssembly()?.GetName().Name is { } entryName)
{
prefixes.Add(entryName);
}
prefixes.AddRange(options.AdditionalPrefixes);
if (prefixes.Count == 0)
{
// Fallback to directory name
prefixes.Add(Path.GetFileName(pluginDirectory));
}
foreach (var prefix in prefixes.Where(p => !string.IsNullOrWhiteSpace(p)))
{
patterns.Add($"{prefix}.Plugin.*.dll");
}
}
return new ReadOnlyCollection<string>(patterns.Distinct(StringComparer.OrdinalIgnoreCase).ToList());
}
private static List<string> DiscoverPluginFiles(
string pluginDirectory,
IReadOnlyList<string> searchPatterns,
bool recurse,
ILogger? logger)
{
var files = new List<string>();
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var searchOption = recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
foreach (var pattern in searchPatterns)
{
try
{
foreach (var file in Directory.EnumerateFiles(pluginDirectory, pattern, searchOption))
{
if (IsHiddenPath(file))
{
continue;
}
if (seen.Add(file))
{
files.Add(file);
}
}
}
catch (DirectoryNotFoundException)
{
// Directory could be removed between the existence check and enumeration.
logger?.LogDebug("Plugin directory '{PluginDirectory}' disappeared before enumeration.", pluginDirectory);
}
}
return files;
}
private static List<string> ApplyExplicitOrdering(
List<string> discoveredFiles,
IList<string> pluginOrder,
out List<string> missingNames)
{
if (pluginOrder.Count == 0 || discoveredFiles.Count == 0)
{
missingNames = new List<string>();
discoveredFiles.Sort(StringComparer.OrdinalIgnoreCase);
return discoveredFiles;
}
var configuredSet = new HashSet<string>(pluginOrder, StringComparer.OrdinalIgnoreCase);
var fileLookup = discoveredFiles.ToDictionary(
k => Path.GetFileNameWithoutExtension(k),
StringComparer.OrdinalIgnoreCase);
var specified = new List<string>();
foreach (var name in pluginOrder)
{
if (fileLookup.TryGetValue(name, out var file))
{
specified.Add(file);
}
}
var unspecified = discoveredFiles
.Where(f => !configuredSet.Contains(Path.GetFileNameWithoutExtension(f)))
.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
.ToList();
missingNames = pluginOrder
.Where(name => !fileLookup.ContainsKey(name))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
specified.AddRange(unspecified);
return specified;
}
private static bool IsHiddenPath(string filePath)
{
var directory = Path.GetDirectoryName(filePath);
while (!string.IsNullOrEmpty(directory))
{
var name = Path.GetFileName(directory);
if (name.StartsWith(".", StringComparison.Ordinal))
{
return true;
}
directory = Path.GetDirectoryName(directory);
}
return false;
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace StellaOps.Plugin.Hosting;
public sealed class PluginHostOptions
{
private readonly List<string> additionalPrefixes = new();
private readonly List<string> pluginOrder = new();
private readonly List<string> searchPatterns = new();
/// <summary>
/// Optional base directory used for resolving relative plugin paths. Defaults to <see cref="AppContext.BaseDirectory" />.
/// </summary>
public string? BaseDirectory { get; set; }
/// <summary>
/// Directory that contains plugin assemblies. Relative values are resolved against <see cref="BaseDirectory" />.
/// Defaults to <c>PluginBinaries</c> under the base directory.
/// </summary>
public string? PluginsDirectory { get; set; }
/// <summary>
/// Primary prefix used to discover plugin assemblies. If not supplied, the entry assembly name is used.
/// </summary>
public string? PrimaryPrefix { get; set; }
/// <summary>
/// Additional prefixes that should be considered when building search patterns.
/// </summary>
public IList<string> AdditionalPrefixes => additionalPrefixes;
/// <summary>
/// Explicit plugin ordering expressed as assembly names without extension.
/// Entries that are not discovered will be reported in <see cref="PluginHostResult.MissingOrderedPlugins" />.
/// </summary>
public IList<string> PluginOrder => pluginOrder;
/// <summary>
/// Optional explicit search patterns. When empty, they are derived from prefix settings.
/// </summary>
public IList<string> SearchPatterns => searchPatterns;
/// <summary>
/// When true (default) the plugin directory will be created if it does not exist.
/// </summary>
public bool EnsureDirectoryExists { get; set; } = true;
/// <summary>
/// Controls whether sub-directories should be scanned. Defaults to true.
/// </summary>
public bool RecursiveSearch { get; set; } = true;
internal string ResolveBaseDirectory()
=> string.IsNullOrWhiteSpace(BaseDirectory)
? AppContext.BaseDirectory
: Path.GetFullPath(BaseDirectory);
}

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
namespace StellaOps.Plugin.Hosting;
public sealed class PluginHostResult
{
internal PluginHostResult(
string pluginDirectory,
IReadOnlyList<string> searchPatterns,
IReadOnlyList<PluginAssembly> plugins,
IReadOnlyList<string> missingOrderedPlugins)
{
PluginDirectory = pluginDirectory;
SearchPatterns = searchPatterns;
Plugins = plugins;
MissingOrderedPlugins = missingOrderedPlugins;
}
public string PluginDirectory { get; }
public IReadOnlyList<string> SearchPatterns { get; }
public IReadOnlyList<PluginAssembly> Plugins { get; }
public IReadOnlyList<string> MissingOrderedPlugins { get; }
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
namespace StellaOps.Plugin.Hosting;
internal sealed class PluginLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver resolver;
private readonly IEnumerable<Assembly> hostAssemblies;
public PluginLoadContext(string pluginPath)
: base(isCollectible: false)
{
resolver = new AssemblyDependencyResolver(pluginPath);
hostAssemblies = AssemblyLoadContext.Default.Assemblies;
}
protected override Assembly? Load(AssemblyName assemblyName)
{
// Attempt to reuse assemblies that already exist in the default context when versions are compatible.
var existing = hostAssemblies.FirstOrDefault(a => string.Equals(
a.GetName().Name,
assemblyName.Name,
StringComparison.OrdinalIgnoreCase));
if (existing != null && IsCompatible(existing.GetName(), assemblyName))
{
return existing;
}
var assemblyPath = resolver.ResolveAssemblyToPath(assemblyName);
if (!string.IsNullOrEmpty(assemblyPath))
{
return LoadFromAssemblyPath(assemblyPath);
}
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
var libraryPath = resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (!string.IsNullOrEmpty(libraryPath))
{
return LoadUnmanagedDllFromPath(libraryPath);
}
return IntPtr.Zero;
}
private static bool IsCompatible(AssemblyName hostAssembly, AssemblyName pluginAssembly)
{
if (hostAssembly.Version == pluginAssembly.Version)
{
return true;
}
if (hostAssembly.Version is null || pluginAssembly.Version is null)
{
return false;
}
if (hostAssembly.Version.Major == pluginAssembly.Version.Major &&
hostAssembly.Version.Minor >= pluginAssembly.Version.Minor)
{
return true;
}
if (hostAssembly.Version.Major >= pluginAssembly.Version.Major)
{
return true;
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace StellaOps.Plugin.Internal;
internal static class ReflectionExtensions
{
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
return ex.Types.Where(static t => t is not null)!;
}
}
}

View File

@@ -1,13 +1,13 @@
using StellaOps.Plugin.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading;
using System.Linq;
using System.Threading.Tasks;
namespace StellOps.AddOn;
namespace StellaOps.Plugin;
public interface IAvailabilityPlugin
{
@@ -63,21 +63,21 @@ public sealed class PluginCatalog
public PluginCatalog AddFromDirectory(string directory, string searchPattern = "StellaOps.Feedser.*.dll")
{
if (string.IsNullOrWhiteSpace(directory)) throw new ArgumentException("Directory is required", nameof(directory));
if (!Directory.Exists(directory))
{
return this;
}
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, SearchOption.TopDirectoryOnly))
var fullDirectory = Path.GetFullPath(directory);
var options = new PluginHostOptions
{
var fullPath = Path.GetFullPath(file);
if (_assemblyLocations.Contains(fullPath))
{
continue;
}
PluginsDirectory = fullDirectory,
EnsureDirectoryExists = false,
RecursiveSearch = false,
};
options.SearchPatterns.Add(searchPattern);
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(fullPath);
AddAssembly(assembly);
var result = PluginHost.LoadPlugins(options);
foreach (var plugin in result.Plugins)
{
AddAssembly(plugin.Assembly);
}
return this;
@@ -169,3 +169,4 @@ public static class PluginLoader
}
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\\StellaOps.DependencyInjection\\StellaOps.DependencyInjection.csproj" />
</ItemGroup>
</Project>