2023-02-17 10:38:45 +01:00
|
|
|
package cast
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-04-20 19:20:52 +02:00
|
|
|
"sync"
|
2023-02-17 10:38:45 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
|
|
)
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
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 {
|
2024-01-12 12:11:41 +01:00
|
|
|
return nil, false
|
2023-04-20 19:20:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cachedDevice, ok := value.(CachedDevice)
|
|
|
|
if !ok {
|
2024-01-12 12:11:41 +01:00
|
|
|
return nil, false
|
2023-04-20 19:20:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if cachedDevice.Expired() {
|
2024-01-12 12:11:41 +01:00
|
|
|
return nil, false
|
2023-04-20 19:20:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return cachedDevice.Device, true
|
|
|
|
}
|
|
|
|
|
|
|
|
func cacheDevice(dev Device) {
|
2024-01-12 12:11:41 +01:00
|
|
|
cache.Store(dev.DeviceID(), CachedDevice{
|
2023-04-20 19:20:52 +02:00
|
|
|
Device: dev,
|
|
|
|
UpdatedAt: time.Now(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func getDeviceClientByID(ctx context.Context, deviceID string) (Client, error) {
|
|
|
|
device, err := findCachedDeviceByID(ctx, deviceID)
|
2023-02-17 10:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
client, err := NewClient(ctx, device)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
2023-02-17 10:38:45 +01:00
|
|
|
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func findCachedDeviceByID(ctx context.Context, deviceID string) (Device, error) {
|
|
|
|
device, exists := getCachedDevice(deviceID)
|
2023-04-20 19:20:52 +02:00
|
|
|
if exists {
|
|
|
|
return device, nil
|
|
|
|
}
|
2023-02-17 10:38:45 +01:00
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
device, err := Find(ctx, deviceID)
|
2023-04-20 19:20:52 +02:00
|
|
|
if err != nil {
|
2024-01-12 12:11:41 +01:00
|
|
|
return nil, errors.WithStack(err)
|
2023-04-20 19:20:52 +02:00
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
cacheDevice(device)
|
2023-02-17 10:38:45 +01:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
return device, nil
|
2023-04-20 19:20:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2023-02-17 10:38:45 +01:00
|
|
|
}
|
2023-04-20 19:20:52 +02:00
|
|
|
|
|
|
|
devices = append(devices, cached.Device)
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return devices, nil
|
2023-02-17 10:38:45 +01:00
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
devices, err := SearchDevices(ctx)
|
2023-04-20 19:20:52 +02:00
|
|
|
if err != nil {
|
2023-02-17 10:38:45 +01:00
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
return devices, nil
|
2023-02-17 10:38:45 +01:00
|
|
|
}
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
var searchDevicesMutex sync.Mutex
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func SearchDevices(ctx context.Context) ([]Device, error) {
|
|
|
|
searchDevicesMutex.Lock()
|
|
|
|
defer searchDevicesMutex.Unlock()
|
2023-04-20 19:20:52 +02:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
devices, err := Scan(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
2023-04-20 19:20:52 +02:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
for _, device := range devices {
|
|
|
|
cacheDevice(device)
|
|
|
|
}
|
2023-02-17 10:38:45 +01:00
|
|
|
|
|
|
|
return devices, nil
|
|
|
|
}
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
var loadURLMutex sync.Mutex
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func LoadURL(ctx context.Context, deviceID string, url string) error {
|
2023-04-20 19:20:52 +02:00
|
|
|
loadURLMutex.Lock()
|
|
|
|
defer loadURLMutex.Unlock()
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
client, err := getDeviceClientByID(ctx, deviceID)
|
2023-02-17 10:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
defer func() {
|
|
|
|
if err := client.Close(); err != nil {
|
|
|
|
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
|
|
|
|
}
|
|
|
|
}()
|
2023-02-17 10:38:45 +01:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
if err := client.Load(ctx, url); err != nil {
|
2023-02-17 10:38:45 +01:00
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
var stopCastMutex sync.Mutex
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func StopCast(ctx context.Context, deviceID string) error {
|
2023-04-20 19:20:52 +02:00
|
|
|
stopCastMutex.Lock()
|
|
|
|
defer stopCastMutex.Unlock()
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
client, err := getDeviceClientByID(ctx, deviceID)
|
2023-02-17 10:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
defer func() {
|
|
|
|
if err := client.Close(); err != nil {
|
|
|
|
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
|
|
|
|
}
|
|
|
|
}()
|
2023-02-17 10:38:45 +01:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
if err := client.Unload(ctx); err != nil {
|
2023-02-17 10:38:45 +01:00
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-20 19:20:52 +02:00
|
|
|
var getStatusMutex sync.Mutex
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
func GetStatus(ctx context.Context, deviceID string) (DeviceStatus, error) {
|
2023-04-20 19:20:52 +02:00
|
|
|
getStatusMutex.Lock()
|
|
|
|
defer getStatusMutex.Unlock()
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
client, err := getDeviceClientByID(ctx, deviceID)
|
2023-02-17 10:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
defer func() {
|
|
|
|
if err := client.Close(); err != nil {
|
|
|
|
logger.Error(ctx, "could not close client", logger.CapturedE(errors.WithStack(err)))
|
|
|
|
}
|
|
|
|
}()
|
2023-02-17 10:38:45 +01:00
|
|
|
|
2024-01-12 12:11:41 +01:00
|
|
|
status, err := client.Status(ctx)
|
2023-02-17 10:38:45 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return status, nil
|
|
|
|
}
|