]> code.octet-stream.net Git - broadcaster/blobdiff - server/web_sync.go
Simplify package names
[broadcaster] / server / web_sync.go
diff --git a/server/web_sync.go b/server/web_sync.go
new file mode 100644 (file)
index 0000000..a6b1a6e
--- /dev/null
@@ -0,0 +1,162 @@
+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
+               }
+       }
+}