evcc-io/plugin/aa55/cache.go
2026-06-04 11:41:03 +02:00

61 lines
1.5 KiB
Go

package aa55
import (
"sync"
"time"
)
const cacheTTL = 2 * time.Second
// cache is the package-level response cache shared across all AA55UDP plugin
// instances. Sharing at package level ensures that multiple source blocks for
// the same (host, pdu) pair — e.g. the four Ppv string registers all using
// READ 125 @ 0x891C — share one UDP exchange per poll cycle.
//
// TTL is 2 s: long enough to serve all source blocks within one evcc poll
// cycle (which completes in well under 1 s), short enough that the next cycle
// always fetches fresh data.
var cache = newResponseCache()
type cacheEntry struct {
payload []byte
expiresAt time.Time
}
type responseCache struct {
mu sync.Mutex
data map[string]cacheEntry
}
func newResponseCache() *responseCache {
return &responseCache{data: make(map[string]cacheEntry)}
}
// get returns the cached payload if it exists and is fresh, or (nil, false)
// otherwise. Expired entries are deleted on access. The map lookup
// m[string(key)] is alloc-free — the Go compiler elides the conversion.
func (c *responseCache) get(key []byte) ([]byte, bool) {
c.mu.Lock()
defer c.mu.Unlock()
entry, ok := c.data[string(key)]
if !ok {
return nil, false
}
if time.Now().After(entry.expiresAt) {
delete(c.data, string(key))
return nil, false
}
return entry.payload, true
}
// put inserts or overwrites a payload in the cache.
func (c *responseCache) put(key, payload []byte) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[string(key)] = cacheEntry{
payload: payload,
expiresAt: time.Now().Add(cacheTTL),
}
}