All checks were successful
CI / changes (push) Successful in 19s
CI / test (push) Successful in 24s
CI / build-ai-gateway (push) Successful in 1m6s
CI / build-ha-gateway (push) Successful in 1m3s
CI / build-discord-bot (push) Successful in 1m4s
CI / build-alexa-bridge (push) Successful in 1m15s
CI / build-tts-gateway (push) Successful in 1m5s
CI / build-tts-sidecar (push) Has been skipped
CI / build-tts-model (push) Has been skipped
- Implemented SetTemperature in ClimateService for setting an absolute target temperature. - Updated ClimateServiceClient and ClimateServiceServer interfaces to include SetTemperature. - Added corresponding handler and tests for SetTemperature in ClimateGRPC. - Modified ClimateApp to handle SetTemperature requests without clamping. - Updated climate.proto to define SetTemperatureRequest message. - Adjusted Dockerfiles to include alexa-bridge dependencies.
49 lines
1.4 KiB
Go
49 lines
1.4 KiB
Go
package entities
|
|
|
|
import (
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"gitea.nik4nao.com/nik/home-services/alexa-bridge/internal/core/domain"
|
|
)
|
|
|
|
// Resolver implements driven.EntityResolver via an atomically-swapped
|
|
// snapshot map, so an in-flight Alexa request never observes a half-built
|
|
// map while a refresh is in progress.
|
|
type Resolver struct {
|
|
snapshot atomic.Pointer[map[string]domain.Entity]
|
|
}
|
|
|
|
// NewResolver constructs a Resolver with an empty snapshot; call Replace
|
|
// (directly, or via Refresher.Start) to populate it before serving requests.
|
|
func NewResolver() *Resolver {
|
|
r := &Resolver{}
|
|
empty := map[string]domain.Entity{}
|
|
r.snapshot.Store(&empty)
|
|
return r
|
|
}
|
|
|
|
// Replace rebuilds the lookup map, keyed by normalized friendly name, and
|
|
// swaps it in atomically.
|
|
func (r *Resolver) Replace(list []domain.Entity) {
|
|
m := make(map[string]domain.Entity, len(list))
|
|
for _, e := range list {
|
|
m[normalize(e.FriendlyName)] = e
|
|
}
|
|
r.snapshot.Store(&m)
|
|
}
|
|
|
|
// Resolve implements driven.EntityResolver. Matching is exact-match only on
|
|
// the normalized (lowercased, trimmed) friendly name — see
|
|
// alexa-bridge/plan.md's Decisions on open questions #5 for why fuzzy
|
|
// matching isn't implemented here.
|
|
func (r *Resolver) Resolve(friendlyName string) (domain.Entity, bool) {
|
|
m := *r.snapshot.Load()
|
|
e, ok := m[normalize(friendlyName)]
|
|
return e, ok
|
|
}
|
|
|
|
func normalize(s string) string {
|
|
return strings.ToLower(strings.TrimSpace(s))
|
|
}
|