package main
import (
"fmt"
"html/template"
"log"
"sort"
"strconv"
"strings"
"code.octet-stream.net/broadcaster/internal/protocol"
"golang.org/x/net/websocket"
)
func WebSync(ws *websocket.Conn) {
log.Println("A web user connected with WebSocket")
buf := make([]byte, 16384)
badRead := false
isAuthenticated := false
var user User
for {
// Ignore any massively oversize messages
n, err := ws.Read(buf)
if err != nil {
if user.Username != "" {
log.Println("Lost websocket to user:", user)
} else {
log.Println("Lost unauthenticated website websocket")
}
return
}
if n == len(buf) {
badRead = true
continue
} else if badRead {
badRead = false
continue
}
if !isAuthenticated {
token := string(buf[:n])
u, err := users.GetUserForSession(token)
if err != nil {
log.Println("Could not find user for offered token", token, err)
ws.Close()
return
}
user = u
log.Println("User authenticated:", user)
isAuthenticated = true
go KeepWebUpdated(ws)
// send initial playlists message
err = sendRadioStatusToWeb(ws)
if err != nil {
return
}
}
}
}
type WebStatusData struct {
Radios []WebRadioStatus
}
type WebRadioStatus struct {
Name string
LocalTime string
TimeZone string
ChannelClass string
ChannelState string
Playlist string
File string
Status string
Id string
DisableCancel bool
FilesInSync bool
}
func sendRadioStatusToWeb(ws *websocket.Conn) error {
webStatuses := make([]WebRadioStatus, 0)
radioStatuses := status.Statuses()
keys := make([]int, 0)
for i := range radioStatuses {
keys = append(keys, i)
}
sort.Ints(keys)
for _, i := range keys {
v := radioStatuses[i]
radio, err := db.GetRadio(i)
if err != nil {
continue
}
var channelClass, channelState string
if v.PTT {
channelClass = "ptt"
channelState = "PTT"
} else if v.COS {
channelClass = "cos"
channelState = "RX"
} else {
channelClass = "clear"
channelState = "CLEAR"
}
var statusText string
var disableCancel bool
if v.Status == protocol.StatusIdle {
statusText = "Idle"
disableCancel = true
} else if v.Status == protocol.StatusDelay {
statusText = fmt.Sprintf("Performing delay before transmit: %ds remain", v.DelaySecondsRemaining)
disableCancel = false
} else if v.Status == protocol.StatusChannelInUse {
statusText = fmt.Sprintf("Waiting for channel to clear: %ds", v.WaitingForChannelSeconds)
disableCancel = false
} else if v.Status == protocol.StatusPlaying {
statusText = fmt.Sprintf("Playing: %d:%02d", v.PlaybackSecondsElapsed/60, v.PlaybackSecondsElapsed%60)
disableCancel = false
}
playlist := v.Playlist
if playlist == "" {
playlist = "-"
}
filename := v.Filename
if filename == "" {
filename = "-"
}
webStatuses = append(webStatuses, WebRadioStatus{
Name: radio.Name,
LocalTime: v.LocalTime,
TimeZone: v.TimeZone,
ChannelClass: channelClass,
ChannelState: channelState,
Playlist: playlist,
File: filename,
Status: statusText,
Id: strconv.Itoa(i),
DisableCancel: disableCancel,
FilesInSync: v.FilesInSync,
})
}
data := WebStatusData{
Radios: webStatuses,
}
buf := new(strings.Builder)
tmpl := template.Must(template.ParseFS(content, "templates/radios.partial.html"))
tmpl.Execute(buf, data)
_, err := ws.Write([]byte(buf.String()))
return err
}
func KeepWebUpdated(ws *websocket.Conn) {
for {
<-status.ChangeChannel()
err := sendRadioStatusToWeb(ws)
if err != nil {
return
}
}
}