var config ServerConfig = NewServerConfig()
-// Channel that will be closed and recreated every time the playlists change
-var playlistChangeWait = make(chan bool)
-
func main() {
configFlag := flag.String("c", "", "path to configuration file")
// TODO: support this
InitDatabase()
defer db.CloseDatabase()
+ InitPlaylists()
InitAudioFiles(config.AudioFilesPath)
InitServerStatus()
}
db.SetEntriesForPlaylist(cleanedEntries, id)
// Notify connected radios
- close(playlistChangeWait)
- playlistChangeWait = make(chan bool)
+ playlists.NotifyChanges()
}
http.Redirect(w, r, "/playlist/", http.StatusFound)
}
return
}
db.DeletePlaylist(id)
+ playlists.NotifyChanges()
}
http.Redirect(w, r, "/playlist/", http.StatusFound)
}
"log"
"os"
"path/filepath"
+ "sync"
)
type FileSpec struct {
path string
list []FileSpec
changeWait chan bool
+ filesMutex sync.Mutex
}
var files AudioFiles
log.Println("couldn't read dir", r.path)
return
}
+ r.filesMutex.Lock()
+ defer r.filesMutex.Unlock()
r.list = nil
for _, file := range entries {
f, err := os.Open(filepath.Join(r.path, file.Name()))
}
func (r *AudioFiles) Files() []FileSpec {
+ r.filesMutex.Lock()
+ defer r.filesMutex.Unlock()
return r.list
}
}
}
-func (r *AudioFiles) ChangeChannel() chan bool {
- return r.changeWait
+func (r *AudioFiles) WatchForChanges() ([]FileSpec, chan bool) {
+ r.filesMutex.Lock()
+ defer r.filesMutex.Unlock()
+ return r.list, r.changeWait
}
--- /dev/null
+package main
+
+import (
+ "sync"
+)
+
+type Playlists struct {
+ changeWait chan bool
+ playlistMutex sync.Mutex
+}
+
+var playlists Playlists
+
+func InitPlaylists() {
+ playlists.changeWait = make(chan bool)
+}
+
+func (p *Playlists) GetPlaylists() []Playlist {
+ p.playlistMutex.Lock()
+ defer p.playlistMutex.Unlock()
+ return db.GetPlaylists()
+}
+
+func (p *Playlists) WatchForChanges() ([]Playlist, chan bool) {
+ p.playlistMutex.Lock()
+ defer p.playlistMutex.Unlock()
+ return db.GetPlaylists(), p.changeWait
+}
+
+func (p *Playlists) NotifyChanges() {
+ p.playlistMutex.Lock()
+ defer p.playlistMutex.Unlock()
+ close(p.changeWait)
+ p.changeWait = make(chan bool)
+}
isAuthenticated = true
go KeepFilesUpdated(ws)
-
- // send initial file message
- err = sendFilesMessageToRadio(ws)
- if err != nil {
- return
- }
-
go KeepPlaylistsUpdated(ws)
-
- // send initial playlists message
- err = sendPlaylistsMessageToRadio(ws)
- if err != nil {
- return
- }
}
if t == protocol.StatusType {
}
}
-func sendPlaylistsMessageToRadio(ws *websocket.Conn) error {
+func sendPlaylistsMessageToRadio(ws *websocket.Conn, p []Playlist) error {
playlistSpecs := make([]protocol.PlaylistSpec, 0)
- for _, v := range db.GetPlaylists() {
+ for _, v := range p {
if v.Enabled {
entrySpecs := make([]protocol.EntrySpec, 0)
for _, e := range db.GetEntriesForPlaylist(v.Id) {
func KeepPlaylistsUpdated(ws *websocket.Conn) {
for {
- <-playlistChangeWait
- err := sendPlaylistsMessageToRadio(ws)
+ p, ch := playlists.WatchForChanges()
+ err := sendPlaylistsMessageToRadio(ws, p)
if err != nil {
return
}
+ <-ch
}
}
-func sendFilesMessageToRadio(ws *websocket.Conn) error {
+func sendFilesMessageToRadio(ws *websocket.Conn, f []FileSpec) error {
specs := make([]protocol.FileSpec, 0)
- for _, v := range files.Files() {
+ for _, v := range f {
specs = append(specs, protocol.FileSpec{Name: v.Name, Hash: v.Hash})
}
files := protocol.FilesMessage{
func KeepFilesUpdated(ws *websocket.Conn) {
for {
- <-files.ChangeChannel()
- err := sendFilesMessageToRadio(ws)
+ f, ch := files.WatchForChanges()
+ err := sendFilesMessageToRadio(ws, f)
if err != nil {
return
}
+ <-ch
}
}