using AcDream.Core.Plugins; using AcDream.Platform; using AcDream.Plugin.Abstractions; using AcDream.Runtime.Session; namespace AcDream.App.Plugins; /// /// Graphical-host composition for one plugin set. The shared /// owns discovery and collectible lifetimes; this /// adapter supplies the graphical roots and translates outcomes into the /// launcher status stream. /// internal sealed class GraphicalPluginSession : IDisposable { private readonly PluginSession _plugins; private readonly string[] _roots; private readonly IReadOnlyList? _allowList; private readonly string _sessionId; private readonly SessionStatusWriter _statusWriter; private bool _started; private GraphicalPluginSession( PluginSession plugins, string[] roots, IReadOnlyList? allowList, string sessionId, SessionStatusWriter statusWriter) { _plugins = plugins; _roots = roots; _allowList = allowList; _sessionId = sessionId; _statusWriter = statusWriter; } internal int LoadedCount => _plugins.LoadedCount; internal IReadOnlyList CaptureLoadContextWeakReferences() => _plugins.CaptureLoadContextWeakReferences(); internal static GraphicalPluginSession Create( ApplicationPathSet paths, IReadOnlyList? allowList, string sessionId, IPluginHost host, SessionStatusWriter statusWriter) { ArgumentNullException.ThrowIfNull(paths); ArgumentException.ThrowIfNullOrWhiteSpace(sessionId); ArgumentNullException.ThrowIfNull(host); ArgumentNullException.ThrowIfNull(statusWriter); var plugins = new PluginSession( host, status => Report(statusWriter, sessionId, status)); return new GraphicalPluginSession( plugins, [ Path.Combine(AppContext.BaseDirectory, "plugins"), paths.PluginsDirectory, ], allowList, sessionId, statusWriter); } internal void Start() { if (_started) throw new InvalidOperationException( "The graphical plugin session has already started."); _started = true; // Both real hosts publish the same startup prefix: started first, // then one outcome for each configured plugin, then connection work. _statusWriter.Started(_sessionId); _plugins.Start(_roots, _allowList); } public void Dispose() => _plugins.Dispose(); private static void Report( SessionStatusWriter writer, string sessionId, PluginSessionStatus status) { if (status.Kind == PluginSessionStatusKind.Loaded) { writer.PluginLoaded(sessionId, status.Plugin); return; } writer.PluginFailed( sessionId, status.Plugin, status.Error ?? "plugin failed"); } }