]> code.octet-stream.net Git - broadcaster/blob - server/files.go
Solve race condition when updating files or playlists and notifying radios
[broadcaster] / server / files.go
1 package main
2
3 import (
4 "crypto/sha256"
5 "encoding/hex"
6 "io"
7 "log"
8 "os"
9 "path/filepath"
10 "sync"
11 )
12
13 type FileSpec struct {
14 Name string
15 Hash string
16 }
17
18 type AudioFiles struct {
19 path string
20 list []FileSpec
21 changeWait chan bool
22 filesMutex sync.Mutex
23 }
24
25 var files AudioFiles
26
27 func InitAudioFiles(path string) {
28 files.changeWait = make(chan bool)
29 files.path = path
30 log.Println("initing audio files")
31 files.Refresh()
32 log.Println("done")
33 }
34
35 func (r *AudioFiles) Refresh() {
36 entries, err := os.ReadDir(r.path)
37 if err != nil {
38 log.Println("couldn't read dir", r.path)
39 return
40 }
41 r.filesMutex.Lock()
42 defer r.filesMutex.Unlock()
43 r.list = nil
44 for _, file := range entries {
45 f, err := os.Open(filepath.Join(r.path, file.Name()))
46 if err != nil {
47 log.Println("couldn't open", file.Name())
48 return
49 }
50 hash := sha256.New()
51 io.Copy(hash, f)
52 r.list = append(r.list, FileSpec{Name: file.Name(), Hash: hex.EncodeToString(hash.Sum(nil))})
53 }
54 log.Println("Files updated", r.list)
55 close(files.changeWait)
56 files.changeWait = make(chan bool)
57 }
58
59 func (r *AudioFiles) Path() string {
60 return r.path
61 }
62
63 func (r *AudioFiles) Files() []FileSpec {
64 r.filesMutex.Lock()
65 defer r.filesMutex.Unlock()
66 return r.list
67 }
68
69 func (r *AudioFiles) Delete(filename string) {
70 path := filepath.Join(r.path, filepath.Base(filename))
71 if filepath.Clean(r.path) != filepath.Clean(path) {
72 os.Remove(path)
73 r.Refresh()
74 }
75 }
76
77 func (r *AudioFiles) WatchForChanges() ([]FileSpec, chan bool) {
78 r.filesMutex.Lock()
79 defer r.filesMutex.Unlock()
80 return r.list, r.changeWait
81 }