105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
// Copyright © 2023 Roberto Hidalgo <event-gateway@un.rob.mx>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package config
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.rob.mx/nidito/event-gateway/internal/sink"
|
|
"git.rob.mx/nidito/event-gateway/internal/sink/types"
|
|
source "git.rob.mx/nidito/event-gateway/internal/source/types"
|
|
)
|
|
|
|
// RawSource is an intermediate source representation.
|
|
type RawSource struct {
|
|
Kind source.Kind `json:"kind"`
|
|
Config json.RawMessage
|
|
}
|
|
|
|
func (s *RawSource) UnmarshalJSON(raw []byte) error {
|
|
s.Config = raw
|
|
inner := &struct {
|
|
Kind source.Kind `json:"kind"`
|
|
}{}
|
|
|
|
if err := json.Unmarshal(raw, &inner); err != nil {
|
|
return fmt.Errorf("unable to decode source: %s: %s", raw, err)
|
|
}
|
|
|
|
s.Kind = inner.Kind
|
|
return nil
|
|
}
|
|
|
|
// Source is an interface concrete.
|
|
type Source interface {
|
|
Initialize()
|
|
Kind() source.Kind
|
|
Register(listener *Listener) error
|
|
Deregister(ID string)
|
|
}
|
|
|
|
// Listener is the configuration for a source.
|
|
type Listener struct {
|
|
ID string
|
|
Source *RawSource
|
|
Event types.Event `json:"sink"`
|
|
Hash string
|
|
}
|
|
|
|
func (l *Listener) UnmarshalJSON(raw []byte) error {
|
|
cfg := &struct {
|
|
Event json.RawMessage `json:"sink"`
|
|
Source *RawSource `json:"source"`
|
|
}{}
|
|
|
|
if err := json.Unmarshal(raw, &cfg); err != nil {
|
|
return fmt.Errorf("unable to decode %s: %s", raw, err)
|
|
}
|
|
|
|
l.Source = cfg.Source
|
|
|
|
if cfg.Event == nil {
|
|
return fmt.Errorf("sink configuration not provided: %s", raw)
|
|
}
|
|
|
|
sink, err := sink.Parse(cfg.Event)
|
|
if err != nil {
|
|
return fmt.Errorf("sink configuration for %s is invalid: %+v", raw, err)
|
|
}
|
|
l.Event = sink
|
|
|
|
hasher := sha256.New()
|
|
hasher.Write(raw)
|
|
l.Hash = base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
|
|
|
return nil
|
|
}
|
|
|
|
// Loader represents a configurator interface.
|
|
type Loader interface {
|
|
Load() ([]*Listener, error)
|
|
String() string
|
|
Watch(chan []*Listener)
|
|
}
|
|
|
|
// FromURN returns a Loader given a :// path.
|
|
func FromURN(urn string) (Loader, error) {
|
|
URLparts := strings.SplitN(urn, "://", 2)
|
|
if len(URLparts) == 1 {
|
|
URLparts = []string{"file", URLparts[0]}
|
|
}
|
|
scheme := URLparts[0]
|
|
configAddr := URLparts[1]
|
|
switch scheme {
|
|
case "file":
|
|
return &File{Path: configAddr}, nil
|
|
case "consul":
|
|
return NewConsul(configAddr)
|
|
}
|
|
return nil, fmt.Errorf("unknown config address: %s", urn)
|
|
}
|