edge/pkg/module/cast/cast.go

196 lines
3.6 KiB
Go

package cast
import (
"context"
"sync"
"time"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type CachedDevice struct {
Device
UpdatedAt time.Time
}
func (d CachedDevice) Expired() bool {
return d.UpdatedAt.Add(30 * time.Minute).Before(time.Now())
}
var cache sync.Map
func getCachedDevice(uuid string) (Device, bool) {
value, exists := cache.Load(uuid)
if !exists {
return nil, false
}
cachedDevice, ok := value.(CachedDevice)
if !ok {
return nil, false
}
if cachedDevice.Expired() {
return nil, false
}
return cachedDevice.Device, true
}
func cacheDevice(dev Device) {
cache.Store(dev.DeviceID(), CachedDevice{
Device: dev,
UpdatedAt: time.Now(),
})
}
func getDeviceClientByID(ctx context.Context, deviceID string) (Client, error) {
device, err := findCachedDeviceByID(ctx, deviceID)
if err != nil {
return nil, errors.WithStack(err)
}
client, err := NewClient(ctx, device)
if err != nil {
return nil, errors.WithStack(err)
}
return client, nil
}
func findCachedDeviceByID(ctx context.Context, deviceID string) (Device, error) {
device, exists := getCachedDevice(deviceID)
if exists {
return device, nil
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
device, err := Find(ctx, deviceID)
if err != nil {
return nil, errors.WithStack(err)
}
cacheDevice(device)
return device, nil
}
func ListDevices(ctx context.Context, refresh bool) ([]Device, error) {
devices := make([]Device, 0)
if !refresh {
cache.Range(func(key, value any) bool {
cached, ok := value.(CachedDevice)
if !ok || cached.Expired() {
return true
}
devices = append(devices, cached.Device)
return true
})
return devices, nil
}
devices, err := SearchDevices(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
return devices, nil
}
var searchDevicesMutex sync.Mutex
func SearchDevices(ctx context.Context) ([]Device, error) {
searchDevicesMutex.Lock()
defer searchDevicesMutex.Unlock()
devices, err := Scan(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
for _, device := range devices {
cacheDevice(device)
}
return devices, nil
}
var loadURLMutex sync.Mutex
func LoadURL(ctx context.Context, deviceID string, url string) error {
loadURLMutex.Lock()
defer loadURLMutex.Unlock()
client, err := getDeviceClientByID(ctx, deviceID)
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := client.Close(); err != nil {
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
}
}()
if err := client.Load(ctx, url); err != nil {
return errors.WithStack(err)
}
return nil
}
var stopCastMutex sync.Mutex
func StopCast(ctx context.Context, deviceID string) error {
stopCastMutex.Lock()
defer stopCastMutex.Unlock()
client, err := getDeviceClientByID(ctx, deviceID)
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := client.Close(); err != nil {
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
}
}()
if err := client.Unload(ctx); err != nil {
return errors.WithStack(err)
}
return nil
}
var getStatusMutex sync.Mutex
func GetStatus(ctx context.Context, deviceID string) (DeviceStatus, error) {
getStatusMutex.Lock()
defer getStatusMutex.Unlock()
client, err := getDeviceClientByID(ctx, deviceID)
if err != nil {
return nil, errors.WithStack(err)
}
defer func() {
if err := client.Close(); err != nil {
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
}
}()
status, err := client.Status(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
return status, nil
}