Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
82 lines
2.2 KiB
Go
82 lines
2.2 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type playerStatusRecord struct {
|
|
ScreenID string `json:"screen_id"`
|
|
Timestamp string `json:"ts"`
|
|
Status string `json:"status"`
|
|
ServerConnectivity string `json:"server_connectivity,omitempty"`
|
|
ReceivedAt string `json:"received_at,omitempty"`
|
|
Stale bool `json:"stale,omitempty"`
|
|
DerivedState string `json:"derived_state,omitempty"`
|
|
ServerURL string `json:"server_url,omitempty"`
|
|
MQTTBroker string `json:"mqtt_broker,omitempty"`
|
|
HeartbeatEverySeconds int `json:"heartbeat_every_seconds,omitempty"`
|
|
StartedAt string `json:"started_at,omitempty"`
|
|
LastHeartbeatAt string `json:"last_heartbeat_at,omitempty"`
|
|
}
|
|
|
|
type playerStatusStore interface {
|
|
Save(record playerStatusRecord)
|
|
Get(screenID string) (playerStatusRecord, bool)
|
|
List() []playerStatusRecord
|
|
Now() time.Time
|
|
}
|
|
|
|
type inMemoryPlayerStatusStore struct {
|
|
mu sync.RWMutex
|
|
records map[string]playerStatusRecord
|
|
now func() time.Time
|
|
}
|
|
|
|
func newInMemoryPlayerStatusStore() *inMemoryPlayerStatusStore {
|
|
return &inMemoryPlayerStatusStore{records: make(map[string]playerStatusRecord), now: time.Now}
|
|
}
|
|
|
|
func NewPlayerStatusStore() playerStatusStore {
|
|
return newInMemoryPlayerStatusStore()
|
|
}
|
|
|
|
func (s *inMemoryPlayerStatusStore) Save(record playerStatusRecord) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.now != nil && record.ReceivedAt == "" {
|
|
record.ReceivedAt = s.now().Format(time.RFC3339)
|
|
}
|
|
s.records[record.ScreenID] = record
|
|
}
|
|
|
|
func (s *inMemoryPlayerStatusStore) Get(screenID string) (playerStatusRecord, bool) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
record, ok := s.records[screenID]
|
|
return record, ok
|
|
}
|
|
|
|
func (s *inMemoryPlayerStatusStore) List() []playerStatusRecord {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
|
|
records := make([]playerStatusRecord, 0, len(s.records))
|
|
for _, record := range s.records {
|
|
records = append(records, record)
|
|
}
|
|
|
|
sort.Slice(records, func(i, j int) bool {
|
|
return records[i].ScreenID < records[j].ScreenID
|
|
})
|
|
|
|
return records
|
|
}
|
|
|
|
func (s *inMemoryPlayerStatusStore) Now() time.Time {
|
|
if s.now == nil {
|
|
return time.Now()
|
|
}
|
|
return s.now()
|
|
}
|