Use go templates/sprig for messages (#2527)
This commit is contained in:
parent
2f06a88ead
commit
45a5bdf7d1
6 changed files with 67 additions and 12 deletions
|
|
@ -64,7 +64,7 @@ type typedConfig struct {
|
|||
}
|
||||
|
||||
type messagingConfig struct {
|
||||
Events map[string]push.EventTemplate
|
||||
Events map[string]push.EventTemplateConfig
|
||||
Services []typedConfig
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,10 @@ func configureEEBus(conf map[string]interface{}) error {
|
|||
// setup messaging
|
||||
func configureMessengers(conf messagingConfig, cache *util.Cache) chan push.Event {
|
||||
notificationChan := make(chan push.Event, 1)
|
||||
notificationHub := push.NewHub(conf.Events, cache)
|
||||
notificationHub, err := push.NewHub(conf.Events, cache)
|
||||
if err != nil {
|
||||
log.FATAL.Fatalf("failed configuring push services: %v", err)
|
||||
}
|
||||
|
||||
for _, service := range conf.Services {
|
||||
impl, err := push.NewMessengerFromConfig(service.Type, service.Other)
|
||||
|
|
|
|||
|
|
@ -12,11 +12,6 @@ type Sender interface {
|
|||
Send(title, msg string)
|
||||
}
|
||||
|
||||
// EventTemplate is the push message template for an event
|
||||
type EventTemplate struct {
|
||||
Title, Msg string
|
||||
}
|
||||
|
||||
var log = util.NewLogger("push")
|
||||
|
||||
// NewMessengerFromConfig creates a new messenger
|
||||
|
|
|
|||
47
push/hub.go
47
push/hub.go
|
|
@ -1,8 +1,11 @@
|
|||
package push
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
|
|
@ -12,6 +15,16 @@ type Event struct {
|
|||
Event string
|
||||
}
|
||||
|
||||
// EventTemplateConfig is the push message configuration for an event
|
||||
type EventTemplateConfig struct {
|
||||
Title, Msg string
|
||||
}
|
||||
|
||||
// EventTemplate is the push message template for an event
|
||||
type EventTemplate struct {
|
||||
Title, Msg *template.Template
|
||||
}
|
||||
|
||||
// Hub subscribes to event notifications and sends them to client devices
|
||||
type Hub struct {
|
||||
definitions map[string]EventTemplate
|
||||
|
|
@ -20,12 +33,32 @@ type Hub struct {
|
|||
}
|
||||
|
||||
// NewHub creates push hub with definitions and receiver
|
||||
func NewHub(definitions map[string]EventTemplate, cache *util.Cache) *Hub {
|
||||
func NewHub(cc map[string]EventTemplateConfig, cache *util.Cache) (*Hub, error) {
|
||||
definitions := make(map[string]EventTemplate)
|
||||
|
||||
// instantiate all event templates
|
||||
for k, v := range cc {
|
||||
var def EventTemplate
|
||||
var err error
|
||||
|
||||
def.Title, err = template.New("out").Funcs(template.FuncMap(sprig.FuncMap())).Parse(v.Title)
|
||||
if err == nil {
|
||||
def.Msg, err = template.New("out").Funcs(template.FuncMap(sprig.FuncMap())).Parse(v.Msg)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
definitions[k] = def
|
||||
}
|
||||
|
||||
h := &Hub{
|
||||
definitions: definitions,
|
||||
cache: cache,
|
||||
}
|
||||
return h
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// Add adds a sender to the list of senders
|
||||
|
|
@ -34,7 +67,7 @@ func (h *Hub) Add(sender Sender) {
|
|||
}
|
||||
|
||||
// apply applies the event template to the content to produce the actual message
|
||||
func (h *Hub) apply(ev Event, template string) (string, error) {
|
||||
func (h *Hub) apply(ev Event, tmpl *template.Template) (string, error) {
|
||||
attr := make(map[string]interface{})
|
||||
|
||||
// let cache catch up, refs reverted https://github.com/evcc-io/evcc/pull/445
|
||||
|
|
@ -47,7 +80,13 @@ func (h *Hub) apply(ev Event, template string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return util.ReplaceFormatted(template, attr)
|
||||
// apply data attributes to template using sprig functions
|
||||
applied := new(strings.Builder)
|
||||
if err := tmpl.Execute(applied, attr); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return util.ReplaceFormatted(applied.String(), attr)
|
||||
}
|
||||
|
||||
// Run is the Hub's main publishing loop
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile(`\${(\w+)(:([a-zA-Z0-9%.]+))?}`)
|
||||
|
|
@ -46,6 +50,20 @@ func FormatValue(format string, val interface{}) string {
|
|||
|
||||
// ReplaceFormatted replaces all occurrences of ${key} with formatted val from the kv map
|
||||
func ReplaceFormatted(s string, kv map[string]interface{}) (string, error) {
|
||||
// Enhanced golang template logic
|
||||
tpl, err := template.New("base").Funcs(sprig.FuncMap()).Parse(s)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
var rs bytes.Buffer
|
||||
err = tpl.Execute(&rs, kv)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
s = rs.String()
|
||||
|
||||
// Regex logic for backward compatibility
|
||||
wanted := make([]string, 0)
|
||||
|
||||
for m := re.FindStringSubmatch(s); m != nil; m = re.FindStringSubmatch(s) {
|
||||
|
|
@ -65,7 +83,6 @@ func ReplaceFormatted(s string, kv map[string]interface{}) (string, error) {
|
|||
}
|
||||
|
||||
// return missing keys
|
||||
var err error
|
||||
if len(wanted) > 0 {
|
||||
got := make([]string, 0)
|
||||
for k := range kv {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ func TestReplace(t *testing.T) {
|
|||
v interface{}
|
||||
fmt, expected string
|
||||
}{
|
||||
// regex tests
|
||||
{"foo", true, "${foo}", "true"},
|
||||
{"foo", "1", "abc${foo}${foo}", "abc11"},
|
||||
{"foo", math.Pi, "${foo:%.2f}", "3.14"},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue