Files

163 lines
3.6 KiB
Go

package handlers
import (
"net/http"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type RemoteQueueItem struct {
Title string `json:"title"`
Owner string `json:"owner"`
ColorBg string `json:"color_bg"`
ColorText string `json:"color_text"`
Img string `json:"img,omitempty"`
}
type RemoteVersion struct {
Title string `json:"title"`
Artist string `json:"artist"`
Duration string `json:"duration"`
Img string `json:"img,omitempty"`
}
type RemoteState struct {
Title string `json:"title"`
Artist string `json:"artist"`
Cover string `json:"cover"`
IsPlaying bool `json:"is_playing"`
Volume float64 `json:"volume"`
Progress float64 `json:"progress"`
Duration float64 `json:"duration"`
QueueLen int `json:"queue_len"`
CurIdx int `json:"cur_idx"`
Queue []RemoteQueueItem `json:"queue,omitempty"`
Versions []RemoteVersion `json:"versions,omitempty"`
ActiveVersion int `json:"active_version"`
}
type RemoteCommand struct {
ID string `json:"id"`
Cmd string `json:"cmd"`
Value float64 `json:"value,omitempty"`
Text string `json:"text,omitempty"`
}
type remoteRoom struct {
state RemoteState
commands []RemoteCommand
lastSeen time.Time
mu sync.Mutex
}
var (
remoteMu sync.RWMutex
remoteRooms = map[string]*remoteRoom{}
)
func init() {
go func() {
for {
time.Sleep(30 * time.Minute)
remoteMu.Lock()
for id, r := range remoteRooms {
if time.Since(r.lastSeen) > 4*time.Hour {
delete(remoteRooms, id)
}
}
remoteMu.Unlock()
}
}()
}
func CreateRemoteRoom(c *gin.Context) {
id := uuid.NewString()[:8]
remoteMu.Lock()
remoteRooms[id] = &remoteRoom{lastSeen: time.Now()}
remoteMu.Unlock()
c.JSON(http.StatusOK, gin.H{"id": id})
}
func PushRemoteState(c *gin.Context) {
id := c.Param("id")
remoteMu.RLock()
room, ok := remoteRooms[id]
remoteMu.RUnlock()
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
var s RemoteState
if err := c.ShouldBindJSON(&s); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
room.mu.Lock()
room.state = s
room.lastSeen = time.Now()
room.mu.Unlock()
c.Status(http.StatusNoContent)
}
func GetRemoteState(c *gin.Context) {
id := c.Param("id")
remoteMu.RLock()
room, ok := remoteRooms[id]
remoteMu.RUnlock()
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
room.mu.Lock()
s := room.state
room.mu.Unlock()
c.JSON(http.StatusOK, s)
}
func SendRemoteCommand(c *gin.Context) {
id := c.Param("id")
remoteMu.RLock()
room, ok := remoteRooms[id]
remoteMu.RUnlock()
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
var cmd RemoteCommand
if err := c.ShouldBindJSON(&cmd); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
cmd.ID = uuid.NewString()
room.mu.Lock()
room.commands = append(room.commands, cmd)
if len(room.commands) > 50 {
room.commands = room.commands[len(room.commands)-50:]
}
room.mu.Unlock()
c.JSON(http.StatusOK, gin.H{"ok": true})
}
func PollRemoteCommands(c *gin.Context) {
id := c.Param("id")
remoteMu.RLock()
room, ok := remoteRooms[id]
remoteMu.RUnlock()
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
room.mu.Lock()
cmds := room.commands
room.commands = nil
room.lastSeen = time.Now()
room.mu.Unlock()
if cmds == nil {
cmds = []RemoteCommand{}
}
c.JSON(http.StatusOK, cmds)
}