190 lines
3.6 KiB
Go
190 lines
3.6 KiB
Go
package provider
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/andig/evcc/util"
|
|
"github.com/asaskevich/EventBus"
|
|
"github.com/benbjohnson/clock"
|
|
)
|
|
|
|
var bus = EventBus.New()
|
|
|
|
const reset = "reset"
|
|
|
|
func ResetCached() {
|
|
bus.Publish(reset)
|
|
}
|
|
|
|
// Cached wraps a getter with a cache
|
|
type Cached struct {
|
|
mux sync.Mutex
|
|
log *util.Logger
|
|
clock clock.Clock
|
|
updated time.Time
|
|
cache time.Duration
|
|
getter interface{}
|
|
val interface{}
|
|
err error
|
|
}
|
|
|
|
// NewCached wraps a getter with a cache
|
|
func NewCached(getter interface{}, cache time.Duration) *Cached {
|
|
c := &Cached{
|
|
log: util.NewLogger("cache"),
|
|
clock: clock.New(),
|
|
getter: getter,
|
|
cache: cache,
|
|
}
|
|
|
|
_ = bus.Subscribe(reset, c.reset)
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *Cached) reset() {
|
|
c.mux.Lock()
|
|
c.updated = time.Time{}
|
|
c.mux.Unlock()
|
|
}
|
|
|
|
// FloatGetter gets float value
|
|
func (c *Cached) FloatGetter() func() (float64, error) {
|
|
g, ok := c.getter.(func() (float64, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (float64, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(float64), c.err
|
|
}
|
|
}
|
|
|
|
// IntGetter gets int value
|
|
func (c *Cached) IntGetter() func() (int64, error) {
|
|
g, ok := c.getter.(func() (int64, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (int64, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(int64), c.err
|
|
}
|
|
}
|
|
|
|
// StringGetter gets string value
|
|
func (c *Cached) StringGetter() func() (string, error) {
|
|
g, ok := c.getter.(func() (string, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (string, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(string), c.err
|
|
}
|
|
}
|
|
|
|
// BoolGetter gets bool value
|
|
func (c *Cached) BoolGetter() func() (bool, error) {
|
|
g, ok := c.getter.(func() (bool, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (bool, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(bool), c.err
|
|
}
|
|
}
|
|
|
|
// DurationGetter gets time.Duration value
|
|
func (c *Cached) DurationGetter() func() (time.Duration, error) {
|
|
g, ok := c.getter.(func() (time.Duration, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (time.Duration, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(time.Duration), c.err
|
|
}
|
|
}
|
|
|
|
// TimeGetter gets time.Time value
|
|
func (c *Cached) TimeGetter() func() (time.Time, error) {
|
|
g, ok := c.getter.(func() (time.Time, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (time.Time, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val.(time.Time), c.err
|
|
}
|
|
}
|
|
|
|
// InterfaceGetter gets interface value
|
|
func (c *Cached) InterfaceGetter() func() (interface{}, error) {
|
|
g, ok := c.getter.(func() (interface{}, error))
|
|
if !ok {
|
|
c.log.FATAL.Fatalf("invalid type: %T", c.getter)
|
|
}
|
|
|
|
return func() (interface{}, error) {
|
|
c.mux.Lock()
|
|
defer c.mux.Unlock()
|
|
|
|
if c.clock.Since(c.updated) > c.cache {
|
|
c.val, c.err = g()
|
|
c.updated = c.clock.Now()
|
|
}
|
|
|
|
return c.val, c.err
|
|
}
|
|
}
|