125 lines
3.9 KiB
C#
125 lines
3.9 KiB
C#
using System.Reflection;
|
|
using Autofac;
|
|
|
|
namespace e_suite.DependencyInjection;
|
|
|
|
public class ModuleDiscovery : IModuleDiscovery
|
|
{
|
|
private readonly IFileSystem _fileSystem;
|
|
private readonly IAssemblyLoader _assemblyLoader;
|
|
private readonly IAssemblyIdentity _assemblyIdentity;
|
|
|
|
public ModuleDiscovery(IFileSystem fileSystem, IAssemblyLoader assemblyLoader, IAssemblyIdentity assemblyIdentity)
|
|
{
|
|
_fileSystem = fileSystem;
|
|
_assemblyLoader = assemblyLoader;
|
|
_assemblyIdentity = assemblyIdentity;
|
|
}
|
|
|
|
public void RegisterAllModuleIocRegistrations(ContainerBuilder builder)
|
|
{
|
|
var cacheDirectory = Path.Combine(AppContext.BaseDirectory, ".cache");
|
|
_fileSystem.CreateDirectory(cacheDirectory);
|
|
|
|
var cachePath = Path.Combine(cacheDirectory, "module-cache.json");
|
|
|
|
var cache = LoadOrCreateModuleCache(cachePath);
|
|
|
|
var basePath = AppContext.BaseDirectory;
|
|
var assemblies = new List<Assembly>();
|
|
|
|
foreach (var module in cache.Modules)
|
|
{
|
|
var fullPath = Path.Combine(basePath, module);
|
|
|
|
if (!_fileSystem.FileExists(fullPath))
|
|
throw new FileNotFoundException($"Cached module not found: {fullPath}");
|
|
|
|
assemblies.Add(_assemblyLoader.LoadFrom(fullPath));
|
|
}
|
|
|
|
var registrationTypes = assemblies
|
|
.SelectMany(a => a.GetTypes())
|
|
.Where(t => typeof(IIocRegistration).IsAssignableFrom(t)
|
|
&& t is { IsAbstract: false, IsInterface: false })
|
|
.ToList();
|
|
|
|
foreach (var type in registrationTypes)
|
|
{
|
|
var instance = (IIocRegistration)Activator.CreateInstance(type)!;
|
|
instance.RegisterTypes(builder);
|
|
}
|
|
}
|
|
|
|
private ModuleCache LoadOrCreateModuleCache(string cachePath)
|
|
{
|
|
var currentHash = ComputeAssemblyHash();
|
|
|
|
if (_fileSystem.FileExists(cachePath))
|
|
{
|
|
var json = _fileSystem.ReadAllText(cachePath);
|
|
var cache = System.Text.Json.JsonSerializer.Deserialize<ModuleCache>(json);
|
|
|
|
if (cache is not null && cache.AssemblyHash == currentHash)
|
|
return cache;
|
|
}
|
|
|
|
// Cache missing or invalid → regenerate
|
|
var regenerated = RegenerateModuleCache(currentHash);
|
|
|
|
var output = System.Text.Json.JsonSerializer.Serialize(regenerated, new System.Text.Json.JsonSerializerOptions
|
|
{
|
|
WriteIndented = true
|
|
});
|
|
|
|
_fileSystem.WriteAllText(cachePath, output);
|
|
|
|
return regenerated;
|
|
}
|
|
|
|
private ModuleCache RegenerateModuleCache(string assemblyHash)
|
|
{
|
|
var basePath = AppContext.BaseDirectory;
|
|
var dlls = _fileSystem.GetFiles(basePath, "*.dll");
|
|
|
|
var modules = new List<string>();
|
|
|
|
foreach (var dll in dlls)
|
|
{
|
|
try
|
|
{
|
|
var asm = _assemblyLoader.LoadFrom(dll);
|
|
|
|
var hasRegistration = asm.GetTypes().Any(t =>
|
|
typeof(IIocRegistration).IsAssignableFrom(t) &&
|
|
!t.IsAbstract &&
|
|
!t.IsInterface);
|
|
|
|
if (hasRegistration)
|
|
modules.Add(Path.GetFileName(dll));
|
|
}
|
|
catch
|
|
{
|
|
// Ignore non-.NET DLLs or load failures
|
|
}
|
|
}
|
|
|
|
return new ModuleCache
|
|
{
|
|
AssemblyHash = assemblyHash,
|
|
Modules = modules
|
|
};
|
|
}
|
|
|
|
private string ComputeAssemblyHash()
|
|
{
|
|
var mainAssembly = _assemblyIdentity.GetAssemblyForHashing();
|
|
var path = mainAssembly.Location;
|
|
|
|
using var stream = _fileSystem.OpenRead(path);
|
|
using var sha = System.Security.Cryptography.SHA256.Create();
|
|
|
|
var hash = sha.ComputeHash(stream);
|
|
return Convert.ToHexString(hash);
|
|
}
|
|
} |