using Microsoft.Extensions.Logging; using StellaOps.Scanner.Surface.Models; namespace StellaOps.Scanner.Surface.Discovery; /// /// Registry for surface entry and entry point collectors. /// public interface ISurfaceEntryRegistry { /// Registers a surface entry collector. void RegisterCollector(ISurfaceEntryCollector collector); /// Registers an entry point collector. void RegisterEntryPointCollector(IEntryPointCollector collector); /// Gets all registered surface entry collectors. IReadOnlyList GetCollectors(); /// Gets all registered entry point collectors. IReadOnlyList GetEntryPointCollectors(); /// Gets collectors that support the specified surface type. IReadOnlyList GetCollectorsForType(SurfaceType type); /// Gets entry point collectors that support the specified language. IReadOnlyList GetEntryPointCollectorsForLanguage(string language); } /// /// Default implementation of surface entry registry. /// public sealed class SurfaceEntryRegistry : ISurfaceEntryRegistry { private readonly List _collectors = []; private readonly List _entryPointCollectors = []; private readonly ILogger _logger; private readonly object _lock = new(); public SurfaceEntryRegistry(ILogger logger) { _logger = logger; } public void RegisterCollector(ISurfaceEntryCollector collector) { ArgumentNullException.ThrowIfNull(collector); lock (_lock) { if (_collectors.Any(c => c.CollectorId == collector.CollectorId)) { _logger.LogWarning("Collector {CollectorId} already registered, skipping", collector.CollectorId); return; } _collectors.Add(collector); _logger.LogDebug("Registered surface collector: {CollectorId}", collector.CollectorId); } } public void RegisterEntryPointCollector(IEntryPointCollector collector) { ArgumentNullException.ThrowIfNull(collector); lock (_lock) { if (_entryPointCollectors.Any(c => c.CollectorId == collector.CollectorId)) { _logger.LogWarning("Entry point collector {CollectorId} already registered, skipping", collector.CollectorId); return; } _entryPointCollectors.Add(collector); _logger.LogDebug("Registered entry point collector: {CollectorId}", collector.CollectorId); } } public IReadOnlyList GetCollectors() { lock (_lock) return [.. _collectors]; } public IReadOnlyList GetEntryPointCollectors() { lock (_lock) return [.. _entryPointCollectors]; } public IReadOnlyList GetCollectorsForType(SurfaceType type) { lock (_lock) { return [.. _collectors.Where(c => c.SupportedTypes.Contains(type))]; } } public IReadOnlyList GetEntryPointCollectorsForLanguage(string language) { ArgumentException.ThrowIfNullOrWhiteSpace(language); lock (_lock) { return [.. _entryPointCollectors.Where(c => c.SupportedLanguages.Contains(language, StringComparer.OrdinalIgnoreCase))]; } } }