generated from rmcguire/go-server-with-otel
55 lines
1.3 KiB
Go
55 lines
1.3 KiB
Go
package econetui
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// pendingStore holds best-effort "desired mode" hints for the brief, async
|
|
// window between a SetMode publish and the Rheem cloud reporting the new mode.
|
|
// Entries expire after a TTL so a mode change that never takes hold quietly
|
|
// falls back to the reported state (a "fresh get") rather than showing a stuck
|
|
// pending badge forever.
|
|
type pendingStore struct {
|
|
mu sync.Mutex
|
|
ttl time.Duration
|
|
m map[string]pendingEntry
|
|
}
|
|
|
|
type pendingEntry struct {
|
|
desired string // desired mode slug
|
|
expiresAt time.Time
|
|
}
|
|
|
|
func newPendingStore(ttl time.Duration) *pendingStore {
|
|
return &pendingStore{ttl: ttl, m: make(map[string]pendingEntry)}
|
|
}
|
|
|
|
func (p *pendingStore) set(serial, desired string) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.m[serial] = pendingEntry{desired: desired, expiresAt: time.Now().Add(p.ttl)}
|
|
}
|
|
|
|
// get returns the desired mode slug for a serial, or ("", false) if there is no
|
|
// pending change or it has expired (expired entries are dropped).
|
|
func (p *pendingStore) get(serial string) (string, bool) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
e, ok := p.m[serial]
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
if time.Now().After(e.expiresAt) {
|
|
delete(p.m, serial)
|
|
return "", false
|
|
}
|
|
return e.desired, true
|
|
}
|
|
|
|
func (p *pendingStore) clear(serial string) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
delete(p.m, serial)
|
|
}
|