forked from evcc-io/evcc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwatchdog.go
150 lines (123 loc) Β· 2.88 KB
/
watchdog.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package provider
import (
"context"
"strconv"
"sync"
"time"
"github.com/evcc-io/evcc/util"
)
type watchdogProvider struct {
mu sync.Mutex
ctx context.Context
log *util.Logger
reset *string
set Config
timeout time.Duration
cancel func()
}
func init() {
registry.AddCtx("watchdog", NewWatchDogFromConfig)
}
// NewWatchDogFromConfig creates watchDog provider
func NewWatchDogFromConfig(ctx context.Context, other map[string]interface{}) (Provider, error) {
var cc struct {
Reset *string
Set Config
Timeout time.Duration
}
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
o := &watchdogProvider{
ctx: ctx,
log: contextLogger(ctx, util.NewLogger("watchdog")),
reset: cc.Reset,
set: cc.Set,
timeout: cc.Timeout,
}
return o, nil
}
func (o *watchdogProvider) wdt(ctx context.Context, set func() error) {
tick := time.NewTicker(o.timeout / 2)
for range tick.C {
select {
case <-ctx.Done():
tick.Stop()
return
default:
if err := set(); err != nil {
o.log.ERROR.Println(err)
}
}
}
}
// setter is the generic setter function for watchdogProvider
// it is currently not possible to write this as a method
func setter[T comparable](o *watchdogProvider, set func(T) error, reset *T) func(T) error {
return func(val T) error {
o.mu.Lock()
// stop wdt on new write
if o.cancel != nil {
o.cancel()
o.cancel = nil
}
// start wdt on non-reset value
if reset == nil || val != *reset {
var ctx context.Context
ctx, o.cancel = context.WithCancel(context.Background())
go o.wdt(ctx, func() error {
return set(val)
})
}
o.mu.Unlock()
return set(val)
}
}
var _ SetIntProvider = (*watchdogProvider)(nil)
func (o *watchdogProvider) IntSetter(param string) (func(int64) error, error) {
set, err := NewIntSetterFromConfig(o.ctx, param, o.set)
if err != nil {
return nil, err
}
var reset *int64
if o.reset != nil {
val, err := strconv.ParseInt(*o.reset, 10, 64)
if err != nil {
return nil, err
}
reset = &val
}
return setter(o, set, reset), nil
}
var _ SetFloatProvider = (*watchdogProvider)(nil)
func (o *watchdogProvider) FloatSetter(param string) (func(float64) error, error) {
set, err := NewFloatSetterFromConfig(o.ctx, param, o.set)
if err != nil {
return nil, err
}
var reset *float64
if o.reset != nil {
val, err := strconv.ParseFloat(*o.reset, 64)
if err != nil {
return nil, err
}
reset = &val
}
return setter(o, set, reset), nil
}
var _ SetBoolProvider = (*watchdogProvider)(nil)
func (o *watchdogProvider) BoolSetter(param string) (func(bool) error, error) {
set, err := NewBoolSetterFromConfig(o.ctx, param, o.set)
if err != nil {
return nil, err
}
var reset *bool
if o.reset != nil {
val, err := strconv.ParseBool(*o.reset)
if err != nil {
return nil, err
}
reset = &val
}
return setter(o, set, reset), nil
}