// Package output defines the pluggable destination interface and its // implementations (currently Discord webhook). package output import ( "context" "fmt" "github.com/ytshih/stonks/internal/config" "github.com/ytshih/stonks/internal/report" ) // Output delivers the final report somewhere (Discord, Slack, email, ...). // Implementations decide how to render report.Text and the optional // report.Recommendations (e.g. Discord sends the text as chunked messages // followed by a short recommendations embed). type Output interface { Name() string Send(ctx context.Context, rep report.Report) error } // Constructor builds an Output from its PluginConfig (name + params). type Constructor func(cfg config.PluginConfig) (Output, error) var registry = map[string]Constructor{} // Register makes an output constructor available under name. Called from // each output implementation's init(). func Register(name string, ctor Constructor) { if _, exists := registry[name]; exists { panic(fmt.Sprintf("output: constructor already registered for %q", name)) } registry[name] = ctor } // Build looks up the constructor for cfg.Name and invokes it. func Build(cfg config.PluginConfig) (Output, error) { ctor, ok := registry[cfg.Name] if !ok { return nil, fmt.Errorf("output: no output registered for %q", cfg.Name) } return ctor(cfg) }