]> code.octet-stream.net Git - broadcaster/blobdiff - radio/files_machine.go
Simplify package names
[broadcaster] / radio / files_machine.go
diff --git a/radio/files_machine.go b/radio/files_machine.go
new file mode 100644 (file)
index 0000000..143397a
--- /dev/null
@@ -0,0 +1,117 @@
+package main
+
+import (
+       "code.octet-stream.net/broadcaster/internal/protocol"
+       "crypto/sha256"
+       "encoding/hex"
+       "io"
+       "log"
+       "net/http"
+       "os"
+       "path/filepath"
+)
+
+type FilesMachine struct {
+       specs     []protocol.FileSpec
+       cachePath string
+       missing   []string
+}
+
+func NewFilesMachine(cachePath string) FilesMachine {
+       if err := os.MkdirAll(cachePath, 0750); err != nil {
+               log.Fatal(err)
+       }
+       return FilesMachine{
+               cachePath: cachePath,
+       }
+}
+
+func (m *FilesMachine) UpdateSpecs(specs []protocol.FileSpec) {
+       m.specs = specs
+       m.RefreshMissing()
+}
+
+func (m *FilesMachine) RefreshMissing() {
+       // Delete any files in the cache dir who are not in the spec
+       entries, err := os.ReadDir(m.cachePath)
+       if err != nil {
+               log.Fatal(err)
+       }
+       okay := make([]string, 0)
+       for _, file := range entries {
+               hash := ""
+               for _, spec := range m.specs {
+                       if file.Name() == spec.Name {
+                               hash = spec.Hash
+                               break
+                       }
+               }
+               // if we have an extraneous file, delete it
+               if hash == "" {
+                       log.Println("Deleting extraneous cached audio file:", file.Name())
+                       os.Remove(filepath.Join(m.cachePath, file.Name()))
+                       continue
+               }
+               // if the hash isn't right, delete it
+               f, err := os.Open(filepath.Join(m.cachePath, file.Name()))
+               if err != nil {
+                       log.Fatal(err)
+               }
+               hasher := sha256.New()
+               io.Copy(hasher, f)
+               if hex.EncodeToString(hasher.Sum(nil)) != hash {
+                       log.Println("Deleting cached audio file with incorrect hash:", file.Name())
+                       os.Remove(filepath.Join(m.cachePath, file.Name()))
+               } else {
+                       okay = append(okay, file.Name())
+               }
+       }
+       m.missing = nil
+       for _, spec := range m.specs {
+               missing := true
+               for _, file := range okay {
+                       if spec.Name == file {
+                               missing = false
+                       }
+               }
+               if missing {
+                       m.missing = append(m.missing, spec.Name)
+               }
+       }
+       if len(m.missing) > 1 {
+               log.Println(len(m.missing), "missing files")
+       } else if len(m.missing) == 1 {
+               log.Println("1 missing file")
+       } else {
+               log.Println("All files are in sync with server")
+       }
+       statusCollector.FilesInSync <- len(m.missing) == 0
+}
+
+func (m *FilesMachine) IsCacheComplete() bool {
+       return len(m.missing) == 0
+}
+
+func (m *FilesMachine) NextFile() string {
+       next, remainder := m.missing[0], m.missing[1:]
+       m.missing = remainder
+       return next
+}
+
+func (m *FilesMachine) DownloadSingle(filename string, downloadResult chan<- error) {
+       log.Println("Downloading", filename)
+       out, err := os.Create(filepath.Join(m.cachePath, filename))
+       if err != nil {
+               downloadResult <- err
+               return
+       }
+       defer out.Close()
+       resp, err := http.Get(config.ServerURL + "/file-downloads/" + filename)
+       if err != nil {
+               downloadResult <- err
+               return
+       }
+       defer resp.Body.Close()
+       _, err = io.Copy(out, resp.Body)
+       downloadResult <- err
+}