84 lines
2.3 KiB
Go
84 lines
2.3 KiB
Go
|
|
package dispatch
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"gitea.maximumdirect.net/ejr/feedkit/config"
|
||
|
|
"gitea.maximumdirect.net/ejr/feedkit/event"
|
||
|
|
)
|
||
|
|
|
||
|
|
// CompileRoutes converts config.Config routes into dispatch.Route rules.
|
||
|
|
//
|
||
|
|
// Behavior:
|
||
|
|
// - If cfg.Routes is empty, we default to "all sinks receive all kinds".
|
||
|
|
// (Implemented as one Route per sink with Kinds == nil.)
|
||
|
|
// - Kind strings are normalized via event.ParseKind (lowercase + trim).
|
||
|
|
//
|
||
|
|
// Note: config.Validate() already ensures route.sink references a known sink and
|
||
|
|
// route.kinds are non-empty strings. We re-check a few invariants here anyway so
|
||
|
|
// CompileRoutes is safe to call even if a daemon chooses not to call Validate().
|
||
|
|
func CompileRoutes(cfg *config.Config) ([]Route, error) {
|
||
|
|
if cfg == nil {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: cfg is nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(cfg.Sinks) == 0 {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: cfg has no sinks")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Build a quick lookup of sink names.
|
||
|
|
sinkNames := make(map[string]bool, len(cfg.Sinks))
|
||
|
|
for i, s := range cfg.Sinks {
|
||
|
|
name := strings.TrimSpace(s.Name)
|
||
|
|
if name == "" {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: sinks[%d].name is empty", i)
|
||
|
|
}
|
||
|
|
sinkNames[name] = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// Default routing: everything to every sink.
|
||
|
|
if len(cfg.Routes) == 0 {
|
||
|
|
out := make([]Route, 0, len(cfg.Sinks))
|
||
|
|
for _, s := range cfg.Sinks {
|
||
|
|
out = append(out, Route{
|
||
|
|
SinkName: s.Name,
|
||
|
|
Kinds: nil, // nil/empty map means "all kinds"
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return out, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
out := make([]Route, 0, len(cfg.Routes))
|
||
|
|
|
||
|
|
for i, r := range cfg.Routes {
|
||
|
|
sink := strings.TrimSpace(r.Sink)
|
||
|
|
if sink == "" {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: routes[%d].sink is required", i)
|
||
|
|
}
|
||
|
|
if !sinkNames[sink] {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: routes[%d].sink references unknown sink %q", i, sink)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(r.Kinds) == 0 {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: routes[%d].kinds must contain at least one kind", i)
|
||
|
|
}
|
||
|
|
|
||
|
|
kinds := make(map[event.Kind]bool, len(r.Kinds))
|
||
|
|
for j, raw := range r.Kinds {
|
||
|
|
k, err := event.ParseKind(raw)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("dispatch.CompileRoutes: routes[%d].kinds[%d]: %w", i, j, err)
|
||
|
|
}
|
||
|
|
kinds[k] = true
|
||
|
|
}
|
||
|
|
|
||
|
|
out = append(out, Route{
|
||
|
|
SinkName: sink,
|
||
|
|
Kinds: kinds,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
return out, nil
|
||
|
|
}
|