using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenNest
{
///
/// Discovers post processors in the desktop's Posts/ directory and registers the
/// materials they provide. Each DLL loads in isolation: one that fails is reported in
/// instead of stopping the others or startup.
///
public static class PostProcessorLoader
{
public sealed record Result(IReadOnlyList PostProcessors, IReadOnlyList Failures);
public static string DefaultDirectory =>
Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Posts");
public static Result Load(string directory)
{
var postProcessors = new List();
var failures = new List();
if (!Directory.Exists(directory))
return new Result(postProcessors, failures);
foreach (var file in Directory.GetFiles(directory, "*.dll"))
{
try
{
// Instantiate the whole DLL before registering any of it.
var loaded = Assembly.LoadFile(file).GetTypes()
.Where(type => type.GetInterfaces().Contains(typeof(IPostProcessor)))
.Select(type => (IPostProcessor)Activator.CreateInstance(type))
.ToList();
foreach (var postProcessor in loaded)
{
postProcessors.Add(postProcessor);
if (postProcessor is IMaterialProvidingPostProcessor materialProvider)
PostProcessorMaterials.AddFrom(materialProvider);
}
}
catch (Exception ex)
{
var reason = ex is TargetInvocationException { InnerException: { } inner } ? inner : ex;
failures.Add($"{Path.GetFileName(file)}: {reason.Message}");
}
}
return new Result(postProcessors, failures);
}
}
}