163 lines
3.6 KiB
Go
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)
|
|
}
|