package sources import ( "fmt" "strings" "gitea.maximumdirect.net/ejr/feedkit/config" ) // Factory constructs a configured Source instance from config. // // This is how concrete daemons (weatherfeeder/newsfeeder/...) register their // domain-specific source drivers (Open-Meteo, NWS, RSS, etc.) while feedkit // remains domain-agnostic. type Factory func(cfg config.SourceConfig) (Source, error) type Registry struct { byDriver map[string]Factory } func NewRegistry() *Registry { return &Registry{byDriver: map[string]Factory{}} } // Register associates a driver name (e.g. "openmeteo_observation") with a factory. // // The driver string is the "lookup key" used by config.sources[].driver. func (r *Registry) Register(driver string, f Factory) { driver = strings.TrimSpace(driver) if driver == "" { // Panic is appropriate here: registering an empty driver is always a programmer error, // and it will lead to extremely confusing runtime behavior if allowed. panic("sources.Registry.Register: driver cannot be empty") } if f == nil { panic(fmt.Sprintf("sources.Registry.Register: factory cannot be nil (driver=%q)", driver)) } r.byDriver[driver] = f } // Build constructs a Source from a SourceConfig by looking up cfg.Driver. func (r *Registry) Build(cfg config.SourceConfig) (Source, error) { f, ok := r.byDriver[cfg.Driver] if !ok { return nil, fmt.Errorf("unknown source driver: %q", cfg.Driver) } return f(cfg) }