online mapping configuration
This commit is contained in:
parent
05b8981cea
commit
5a486ea48e
103
config/config.go
103
config/config.go
|
@ -1,6 +1,8 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -9,6 +11,8 @@ import (
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"code.chrissexton.org/cws/lameralert/mapping"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -24,10 +28,29 @@ func (value configValue) getBytes() ([]byte, error) {
|
||||||
return json.Marshal(value)
|
return json.Marshal(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeConfig(in []byte) (configValue, error) {
|
func decodeConfig(in []byte, target *configValue) error {
|
||||||
var out configValue
|
err := json.Unmarshal(in, target)
|
||||||
err := json.Unmarshal(in, &out)
|
return err
|
||||||
return out, err
|
}
|
||||||
|
|
||||||
|
func encodeMapping(in mapping.Mapping) ([]byte, error) {
|
||||||
|
var out []byte
|
||||||
|
buf := bytes.NewBuffer(out)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(in)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeMapping(in []byte) (mapping.Mapping, error) {
|
||||||
|
var target mapping.Mapping
|
||||||
|
dec := gob.NewDecoder(bytes.NewBuffer(in))
|
||||||
|
err := dec.Decode(&target)
|
||||||
|
log.Debug().
|
||||||
|
Interface("err", err).
|
||||||
|
Str("in", string(in)).
|
||||||
|
Interface("target", target).
|
||||||
|
Msg("decodeMapping")
|
||||||
|
return target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -65,7 +88,8 @@ func (c *Config) getAll() (map[string]configValue, error) {
|
||||||
err := db.View(func(tx *bolt.Tx) error {
|
err := db.View(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket(bucket)
|
b := tx.Bucket(bucket)
|
||||||
err := b.ForEach(func(k, v []byte) error {
|
err := b.ForEach(func(k, v []byte) error {
|
||||||
value, err := decodeConfig(v)
|
var value configValue
|
||||||
|
err := decodeConfig(v, &value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not convert value: %w", err)
|
return fmt.Errorf("could not convert value: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -80,6 +104,31 @@ func (c *Config) getAll() (map[string]configValue, error) {
|
||||||
return vals, err
|
return vals, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) getMapping(key string) (mapping.Mapping, error) {
|
||||||
|
log.Debug().Msgf("getMapping(%s)", key)
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
db := c.db()
|
||||||
|
defer db.Close()
|
||||||
|
var err error
|
||||||
|
var out mapping.Mapping
|
||||||
|
err = db.View(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket(bucket)
|
||||||
|
out, err = decodeMapping(b.Get([]byte(key)))
|
||||||
|
log.Debug().AnErr("err", err).Interface("out", out).Msgf("decode %s", key)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Msgf("Error decoding: %w", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Msgf("Error getting: %w", err)
|
||||||
|
return mapping.Mapping{}, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) get(key string) (configValue, error) {
|
func (c *Config) get(key string) (configValue, error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
@ -88,11 +137,10 @@ func (c *Config) get(key string) (configValue, error) {
|
||||||
var out configValue
|
var out configValue
|
||||||
err := db.View(func(tx *bolt.Tx) error {
|
err := db.View(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket(bucket)
|
b := tx.Bucket(bucket)
|
||||||
value, err := decodeConfig(b.Get([]byte(key)))
|
err := decodeConfig(b.Get([]byte(key)), &out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out = value
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -101,6 +149,26 @@ func (c *Config) get(key string) (configValue, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) setMapping(key string, value mapping.Mapping) error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
db := c.db()
|
||||||
|
defer db.Close()
|
||||||
|
err := db.Update(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket(bucket)
|
||||||
|
v, err := encodeMapping(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.Put([]byte(key), v)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Msgf("Error setting key: %s", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) set(key string, value configValue) error {
|
func (c *Config) set(key string, value configValue) error {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
@ -192,6 +260,27 @@ func (c *Config) GetString(key, defaultValue string) string {
|
||||||
return v.Value.(string)
|
return v.Value.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetMapping(key string, defaultValue mapping.Mapping) mapping.Mapping {
|
||||||
|
m, err := c.getMapping(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Msgf("Error: %w", err)
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetGeneric(key string, defaultValue interface{}) interface{} {
|
||||||
|
v, err := c.get(key)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) SetMapping(key string, value mapping.Mapping) error {
|
||||||
|
return c.setMapping(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) Set(key string, value interface{}) error {
|
func (c *Config) Set(key string, value interface{}) error {
|
||||||
return c.set(key, configValue{key, value})
|
return c.set(key, configValue{key, value})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"code.chrissexton.org/cws/lameralert/config"
|
"code.chrissexton.org/cws/lameralert/config"
|
||||||
"code.chrissexton.org/cws/lameralert/event"
|
"code.chrissexton.org/cws/lameralert/mapping"
|
||||||
"code.chrissexton.org/cws/lameralert/sinks"
|
"code.chrissexton.org/cws/lameralert/sinks"
|
||||||
"code.chrissexton.org/cws/lameralert/sources"
|
"code.chrissexton.org/cws/lameralert/sources"
|
||||||
)
|
)
|
||||||
|
@ -28,8 +28,6 @@ func NewConnection(from sources.Source, to sinks.Sink) Connection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapping = map[chan event.Event][]chan event.Event{}
|
|
||||||
|
|
||||||
func logger(next http.Handler) http.Handler {
|
func logger(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Do stuff here
|
// Do stuff here
|
||||||
|
@ -38,22 +36,55 @@ func logger(next http.Handler) http.Handler {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setup() chan bool {
|
func Setup() chan bool {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Use(logger)
|
r.Use(logger)
|
||||||
c := config.New(r.PathPrefix("/config").Subrouter())
|
c := config.New(r.PathPrefix("/config").Subrouter())
|
||||||
ch := make(chan bool)
|
ch := make(chan bool)
|
||||||
|
|
||||||
h := sources.NewGenericRest(r.PathPrefix("/rest").Subrouter())
|
mappings := c.GetMapping("mappings", mapping.Example())
|
||||||
NewConnection(h, sinks.NewConsoleID(c, "00"))
|
|
||||||
NewConnection(h, sinks.NewConsoleID(c, "01"))
|
|
||||||
|
|
||||||
rss := sources.NewRSS(c, r.PathPrefix("/rss/webshit").Subrouter(), "webshit", "http://n-gate.com/hackernews/index.rss")
|
//mappings := mapping.Example()
|
||||||
NewConnection(rss, sinks.NewConsoleID(c, "webshit-sink"))
|
//c.SetMapping("mappings", mappings)
|
||||||
if push, err := sinks.NewPushover(c, "webshit-push"); err != nil {
|
|
||||||
log.Fatal().Msgf("error: %s", err)
|
srcs := map[string]sources.Source{}
|
||||||
} else {
|
snks := map[string]sinks.Sink{}
|
||||||
NewConnection(rss, push)
|
for _, source := range mappings.Sources {
|
||||||
|
var src sources.Source
|
||||||
|
// TODO: Move this logic out to the sources package
|
||||||
|
switch source.Type {
|
||||||
|
case "GenericRest":
|
||||||
|
path := source.Config["prefix"]
|
||||||
|
src = sources.NewGenericRest(r.PathPrefix(path).Subrouter())
|
||||||
|
case "RSS":
|
||||||
|
path := source.Config["prefix"]
|
||||||
|
url := source.Config["URL"]
|
||||||
|
src = sources.NewRSS(c, r.PathPrefix(path).Subrouter(), source.Name, url)
|
||||||
|
}
|
||||||
|
srcs[source.Name] = src
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sink := range mappings.Sinks {
|
||||||
|
var snk sinks.Sink
|
||||||
|
// TODO: Move this logic out to the sinks package
|
||||||
|
switch sink.Type {
|
||||||
|
case "Console":
|
||||||
|
snk = sinks.NewConsoleID(c, sink.Config["ID"])
|
||||||
|
case "Pushover":
|
||||||
|
var err error
|
||||||
|
snk, err = sinks.NewPushover(c, sink.Name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Msgf("Error setting up pushover: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snks[sink.Name] = snk
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range mappings.Mappings {
|
||||||
|
src := srcs[m.From]
|
||||||
|
snk := snks[m.To]
|
||||||
|
NewConnection(src, snk)
|
||||||
}
|
}
|
||||||
|
|
||||||
http.ListenAndServe(":9090", r)
|
http.ListenAndServe(":9090", r)
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package mapping
|
||||||
|
|
||||||
|
type Mapping struct {
|
||||||
|
Sources []MapItem
|
||||||
|
Sinks []MapItem
|
||||||
|
Mappings []MapPair
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapPair struct {
|
||||||
|
From string
|
||||||
|
To string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapItem struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Config map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make a web interface to configure these horrible structures
|
||||||
|
func Example() Mapping {
|
||||||
|
mappings := Mapping{}
|
||||||
|
|
||||||
|
webshit := MapItem{
|
||||||
|
Name: "webshit",
|
||||||
|
Type: "RSS",
|
||||||
|
Config: map[string]string{
|
||||||
|
"prefix": "/rss/webshit",
|
||||||
|
"URL": "http://n-gate.com/hackernews/index.rss",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mappings.Sources = append(mappings.Sources, webshit)
|
||||||
|
genericRest := MapItem{
|
||||||
|
Name: "GenericRest",
|
||||||
|
Type: "GenericRest",
|
||||||
|
Config: map[string]string{
|
||||||
|
"prefix": "/rest",
|
||||||
|
"name": "GenericRest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mappings.Sources = append(mappings.Sources, genericRest)
|
||||||
|
consoleZero := MapItem{
|
||||||
|
Name: "Console-00",
|
||||||
|
Type: "Console",
|
||||||
|
Config: map[string]string{
|
||||||
|
"ID": "00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mappings.Sinks = append(mappings.Sinks, consoleZero)
|
||||||
|
consoleOne := MapItem{
|
||||||
|
Name: "Console-01",
|
||||||
|
Type: "Console",
|
||||||
|
Config: map[string]string{
|
||||||
|
"ID": "01",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mappings.Sinks = append(mappings.Sinks, consoleOne)
|
||||||
|
|
||||||
|
pushOver := MapItem{
|
||||||
|
Name: "Pushover",
|
||||||
|
Type: "Pushover",
|
||||||
|
Config: map[string]string{},
|
||||||
|
}
|
||||||
|
mappings.Sinks = append(mappings.Sinks, pushOver)
|
||||||
|
|
||||||
|
mappings.Mappings = append(mappings.Mappings, MapPair{"GenericRest", "Console-00"})
|
||||||
|
mappings.Mappings = append(mappings.Mappings, MapPair{"GenericRest", "Console-01"})
|
||||||
|
mappings.Mappings = append(mappings.Mappings, MapPair{"webshit", "Pushover"})
|
||||||
|
|
||||||
|
return mappings
|
||||||
|
}
|
Loading…
Reference in New Issue