using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; namespace StellaOps.Cli.Plugins; internal sealed class RestartOnlyCliPluginGuard { private readonly ConcurrentDictionary _plugins = new(StringComparer.OrdinalIgnoreCase); private bool _sealed; public IReadOnlyCollection KnownPlugins => _plugins.Keys.ToArray(); public bool IsSealed => Volatile.Read(ref _sealed); public void EnsureRegistrationAllowed(string pluginPath) { ArgumentException.ThrowIfNullOrWhiteSpace(pluginPath); var normalized = Normalize(pluginPath); if (IsSealed && !_plugins.ContainsKey(normalized)) { throw new InvalidOperationException($"Plug-in '{pluginPath}' cannot be registered after startup. Restart required."); } _plugins.TryAdd(normalized, 0); } public void Seal() { Volatile.Write(ref _sealed, true); } private static string Normalize(string path) { var full = Path.GetFullPath(path); return full.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } }