forked from evcc-io/evcc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhub.go
135 lines (111 loc) Β· 3.19 KB
/
hub.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package push
import (
"fmt"
"strings"
"text/template"
"github.com/Masterminds/sprig/v3"
"github.com/evcc-io/evcc/core/vehicle"
"github.com/evcc-io/evcc/util"
)
// Event is a notification event
type Event struct {
Loadpoint *int // optional loadpoint id
Event string
}
// EventTemplateConfig is the push message configuration for an event
type EventTemplateConfig struct {
Title, Msg string
}
type Vehicles interface {
// ByName returns a single vehicle adapter by name
ByName(string) (vehicle.API, error)
}
// Hub subscribes to event notifications and sends them to client devices
type Hub struct {
definitions map[string]EventTemplateConfig
sender []Messenger
cache *util.Cache
vehicles Vehicles
}
// NewHub creates push hub with definitions and receiver
func NewHub(cc map[string]EventTemplateConfig, vv Vehicles, cache *util.Cache) (*Hub, error) {
// instantiate all event templates
for k, v := range cc {
if _, err := template.New("out").Funcs(sprig.FuncMap()).Parse(v.Title); err != nil {
return nil, fmt.Errorf("invalid event title: %s (%w)", k, err)
}
if _, err := template.New("out").Funcs(sprig.FuncMap()).Parse(v.Msg); err != nil {
return nil, fmt.Errorf("invalid event message: %s (%w)", k, err)
}
}
h := &Hub{
definitions: cc,
cache: cache,
vehicles: vv,
}
return h, nil
}
// Add adds a sender to the list of senders
func (h *Hub) Add(sender Messenger) {
h.sender = append(h.sender, sender)
}
// apply applies the event template to the content to produce the actual message
func (h *Hub) apply(ev Event, tmpl string) (string, error) {
attr := make(map[string]interface{})
// loadpoint id
if ev.Loadpoint != nil {
attr["loadpoint"] = *ev.Loadpoint + 1
}
// get all values from cache
for _, p := range h.cache.All() {
if p.Loadpoint == nil || ev.Loadpoint == p.Loadpoint {
attr[p.Key] = p.Val
}
}
// add missing attributes
if name, ok := attr["vehicleName"].(string); ok {
if v, err := h.vehicles.ByName(name); err == nil {
attr["vehicleLimitSoc"] = v.GetLimitSoc()
attr["vehicleMinSoc"] = v.GetMinSoc()
attr["vehiclePlanTime"], attr["vehiclePlanSoc"] = v.GetPlanSoc()
instance := v.Instance()
attr["vehicleTitle"] = instance.Title()
attr["vehicleIcon"] = instance.Icon()
attr["vehicleCapacity"] = instance.Capacity()
}
}
return util.ReplaceFormatted(tmpl, attr)
}
// Run is the Hub's main publishing loop
func (h *Hub) Run(events <-chan Event, valueChan chan<- util.Param) {
log := util.NewLogger("push")
for ev := range events {
if len(h.sender) == 0 {
continue
}
definition, ok := h.definitions[ev.Event]
if !ok {
continue
}
// let cache catch up, refs https://github.com/evcc-io/evcc/pull/445
flushC := util.Flusher()
valueChan <- util.Param{Val: flushC}
<-flushC
title, err := h.apply(ev, definition.Title)
if err != nil {
log.ERROR.Printf("invalid title template for %s: %v", ev.Event, err)
continue
}
msg, err := h.apply(ev, definition.Msg)
if err != nil {
log.ERROR.Printf("invalid message template for %s: %v", ev.Event, err)
continue
}
if strings.TrimSpace(msg) == "" {
continue
}
for _, sender := range h.sender {
go sender.Send(title, msg)
}
}
}