av/cmd/vidforward/file.go

178 lines
4.7 KiB
Go

/*
DESCRIPTION
files.go provides the functionality required for saving and loading
broadcastManager state. This includes marshalling/unmarshalling overrides.
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2022-2023 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package main
import (
"encoding/json"
"fmt"
"os"
"bitbucket.org/ausocean/av/cmd/vidforward/global"
)
// inTest is used to indicate if we are within a test; some functionality is not
// employed in this case.
var inTest bool
// The file name for the broadcast manager state save.
const fileName = "state.json"
// BroadcastBasic is a crude version of the Broadcast used to simplify
// marshal/unmarshal overriding.
type BroadcastBasic struct {
MAC
URLs []string
Status string
}
// ManagerBasic is a crude version of the BroadcastManager struct use to simplify
// marshal/unmarshal overriding.
type ManagerBasic struct {
Broadcasts map[MAC]Broadcast
SlateExitSignals []MAC
}
// MarshalJSON calls the default marshalling behaviour for the BroadcastBasic
// struct using the information from b.
func (b Broadcast) MarshalJSON() ([]byte, error) {
return json.Marshal(BroadcastBasic{
MAC: b.mac,
URLs: b.urls,
Status: b.status,
})
}
// UnmarshalJSON unmarshals into a value of the BroadcastBasic struct and then
// populates a Broadcast value.
func (b *Broadcast) UnmarshalJSON(data []byte) error {
var bm BroadcastBasic
err := json.Unmarshal(data, &bm)
if err != nil {
return fmt.Errorf("could not unmarshal JSON: %w", err)
}
b.mac = bm.MAC
b.urls = bm.URLs
b.status = bm.Status
b.rv, err = newRevid(global.GetLogger(), b.urls)
if err != nil {
return fmt.Errorf("could not populate RV field: %w", err)
}
err = b.rv.Start()
if err != nil {
return fmt.Errorf("could not start revid pipeline: %w", err)
}
return nil
}
// MarshalJSON calls the default marshaller for a ManagerBasic value using data
// from a broadcastManager value.
func (m *broadcastManager) MarshalJSON() ([]byte, error) {
var signals []MAC
for k := range m.slateExitSignals {
signals = append(signals, k)
}
return json.Marshal(ManagerBasic{
Broadcasts: m.broadcasts,
SlateExitSignals: signals,
})
}
// UnmarshalJSON populates a ManagerBasic value from the provided data and then
// populates the receiver broadcastManager to a usable state based on this data.
func (m *broadcastManager) UnmarshalJSON(data []byte) error {
var mb ManagerBasic
err := json.Unmarshal(data, &mb)
if err != nil {
return fmt.Errorf("could not unmarshal JSON: %w", err)
}
m.broadcasts = mb.Broadcasts
m.slateExitSignals = make(map[MAC]chan struct{})
m.log = global.GetLogger()
notifier, err := newWatchdogNotifier(m.log, terminationCallback(m))
if err != nil {
return fmt.Errorf("could not create watchdog notifier: %w", err)
}
m.dogNotifier = notifier
for _, mac := range mb.SlateExitSignals {
sigCh := make(chan struct{})
m.slateExitSignals[mac] = sigCh
rv := m.getPipeline(mac)
if rv == nil {
panic("no pipeline for MAC")
}
if !inTest {
err := writeSlateAndCheckErrors(rv, sigCh, m.log)
if err != nil {
return fmt.Errorf("couldn't write slate for MAC %v: %w", mac, err)
}
}
}
return nil
}
// save utilises marshalling functionality to save the broadcastManager state
// to a file.
func (m *broadcastManager) save() error {
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return fmt.Errorf("could not open file: %w", err)
}
defer f.Close()
bytes, err := json.Marshal(m)
if err != nil {
return fmt.Errorf("could not marshal broadcast manager: %w", err)
}
_, err = f.Write(bytes)
if err != nil {
return fmt.Errorf("could not write bytes to file: %w", err)
}
return nil
}
// load populates a broadcastManager value based on the previously saved state.
func (m *broadcastManager) load() error {
bytes, err := os.ReadFile(fileName)
if err != nil {
return fmt.Errorf("could not read state file: %w", err)
}
err = json.Unmarshal(bytes, &m)
if err != nil {
return fmt.Errorf("could not unmarshal state data: %w", err)
}
return nil
}