package main import ( "code.octet-stream.net/broadcaster/internal/protocol" "encoding/json" "golang.org/x/net/websocket" "time" ) type BeginDelayStatus struct { Playlist string Seconds int Filename string } type BeginWaitForChannelStatus struct { Playlist string Filename string } type BeginPlaybackStatus struct { Playlist string Filename string } type StatusCollector struct { Websocket chan *websocket.Conn PlaylistBeginIdle chan bool PlaylistBeginDelay chan BeginDelayStatus PlaylistBeginWaitForChannel chan BeginWaitForChannelStatus PlaylistBeginPlayback chan BeginPlaybackStatus PTT chan bool COS chan bool Config chan RadioConfig FilesInSync chan bool } var statusCollector = NewStatusCollector() func NewStatusCollector() StatusCollector { sc := StatusCollector{ Websocket: make(chan *websocket.Conn), PlaylistBeginIdle: make(chan bool), PlaylistBeginDelay: make(chan BeginDelayStatus), PlaylistBeginWaitForChannel: make(chan BeginWaitForChannelStatus), PlaylistBeginPlayback: make(chan BeginPlaybackStatus), PTT: make(chan bool), COS: make(chan bool), Config: make(chan RadioConfig), FilesInSync: make(chan bool), } go runStatusCollector(sc) return sc } func runStatusCollector(sc StatusCollector) { config := <-sc.Config var msg protocol.StatusMessage var lastSent protocol.StatusMessage msg.T = protocol.StatusType msg.TimeZone = config.TimeZone msg.Status = protocol.StatusIdle var ws *websocket.Conn // Go 1.23: no need to stop tickers when finished var ticker = time.NewTicker(time.Second * time.Duration(30)) for { select { case newWebsocket := <-sc.Websocket: ws = newWebsocket case <-ticker.C: // should always be ticking at 1 second for these if msg.Status == protocol.StatusDelay { if msg.DelaySecondsRemaining > 0 { msg.DelaySecondsRemaining -= 1 } } if msg.Status == protocol.StatusChannelInUse { msg.WaitingForChannelSeconds += 1 } if msg.Status == protocol.StatusPlaying { msg.PlaybackSecondsElapsed += 1 } case <-sc.PlaylistBeginIdle: msg.Status = protocol.StatusIdle msg.DelaySecondsRemaining = 0 msg.WaitingForChannelSeconds = 0 msg.PlaybackSecondsElapsed = 0 msg.Playlist = "" msg.Filename = "" // Update things more slowly when nothing's playing ticker = time.NewTicker(time.Second * time.Duration(30)) case delay := <-sc.PlaylistBeginDelay: msg.Status = protocol.StatusDelay msg.DelaySecondsRemaining = delay.Seconds msg.WaitingForChannelSeconds = 0 msg.PlaybackSecondsElapsed = 0 msg.Playlist = delay.Playlist msg.Filename = delay.Filename // Align ticker with start of state change, make sure it's faster ticker = time.NewTicker(time.Second * time.Duration(1)) case wait := <-sc.PlaylistBeginWaitForChannel: msg.Status = protocol.StatusChannelInUse msg.DelaySecondsRemaining = 0 msg.WaitingForChannelSeconds = 0 msg.PlaybackSecondsElapsed = 0 msg.Playlist = wait.Playlist msg.Filename = wait.Filename ticker = time.NewTicker(time.Second * time.Duration(1)) case playback := <-sc.PlaylistBeginPlayback: msg.Status = protocol.StatusPlaying msg.DelaySecondsRemaining = 0 msg.WaitingForChannelSeconds = 0 msg.PlaybackSecondsElapsed = 0 msg.Playlist = playback.Playlist msg.Filename = playback.Filename ticker = time.NewTicker(time.Second * time.Duration(1)) case ptt := <-sc.PTT: msg.PTT = ptt case cos := <-sc.COS: msg.COS = cos case inSync := <-sc.FilesInSync: msg.FilesInSync = inSync } msg.LocalTime = time.Now().Format(protocol.LocalTimeFormat) msg.COS = cos.COSValue() if msg == lastSent { continue } if ws != nil { msgJson, _ := json.Marshal(msg) if _, err := ws.Write(msgJson); err != nil { // If websocket has failed, wait 'til we get a new one ws = nil } lastSent = msg } } }