2023-11-05 20:23:31 +01:00
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2023-11-10 03:24:12 +01:00
|
|
|
"errors"
|
2023-11-05 20:23:31 +01:00
|
|
|
"log"
|
|
|
|
"os"
|
2023-11-10 03:24:12 +01:00
|
|
|
"path"
|
2023-11-05 20:23:31 +01:00
|
|
|
"slices"
|
|
|
|
|
|
|
|
"gitlab.hamburg.ccc.de/ccchh/spaceapid/types"
|
|
|
|
)
|
|
|
|
|
2023-11-10 03:24:12 +01:00
|
|
|
const savedStateJSONPath = "/var/lib/spaceapid/spaceapid-state.json"
|
|
|
|
|
2023-11-05 20:23:31 +01:00
|
|
|
// ParseTemplate parses the given file and
|
|
|
|
func ParseTemplate(file string) (resp types.SpaceAPIResponseV14) {
|
|
|
|
|
|
|
|
// Read template file
|
|
|
|
template, err := os.ReadFile(file)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed reading file:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse JSON
|
|
|
|
dec := json.NewDecoder(bytes.NewReader(template))
|
|
|
|
dec.DisallowUnknownFields()
|
|
|
|
err = dec.Decode(&resp)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Could not parse SpaceAPI response template:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if compatible with v14
|
|
|
|
if !slices.Contains(resp.APICompatibility, "14") {
|
|
|
|
log.Fatalln("Provided template doesn't specify compatibility with API version 14")
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2023-11-10 03:24:12 +01:00
|
|
|
|
|
|
|
// MergeOldState merges a given SpaceAPIResponse with the state saved at the time of last program exit and then deletes
|
|
|
|
// the file containing the old state.
|
|
|
|
func MergeOldState(response *types.SpaceAPIResponseV14) {
|
|
|
|
var (
|
|
|
|
err error
|
|
|
|
oldState []byte
|
|
|
|
)
|
|
|
|
|
|
|
|
// Create state directory if not present
|
|
|
|
err = os.MkdirAll(path.Dir(savedStateJSONPath), 0750)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed creating", savedStateJSONPath, ", aborting... error:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if state.json is present
|
|
|
|
_, err = os.Stat(savedStateJSONPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Old state json not accessible at", savedStateJSONPath, ", skipping merge... error:", err)
|
|
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
goto removeOld
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read file and merge
|
|
|
|
oldState, err = os.ReadFile(savedStateJSONPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Error reading old state from", savedStateJSONPath, ", skipping merge... error:", err)
|
|
|
|
goto removeOld
|
|
|
|
}
|
|
|
|
err = json.Unmarshal(oldState, response)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(savedStateJSONPath, "doesn't seem to contain valid data... error:", err)
|
|
|
|
goto removeOld
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete old state json
|
|
|
|
removeOld:
|
|
|
|
err = os.RemoveAll(savedStateJSONPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Failed to remove", savedStateJSONPath, ", continuing... error:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func SaveCurrentState(response types.SpaceAPIResponseV14) {
|
|
|
|
file, err := os.OpenFile(savedStateJSONPath, os.O_RDWR|os.O_CREATE, 0644)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed opening", savedStateJSONPath, "while trying to save current state... error:", err)
|
|
|
|
}
|
|
|
|
defer func(file *os.File) {
|
|
|
|
_ = file.Close()
|
|
|
|
}(file)
|
|
|
|
|
|
|
|
// Create persistent state
|
|
|
|
persistentStateV14 := types.PersistentStateV14{
|
|
|
|
State: struct {
|
|
|
|
Open bool `json:"open"`
|
|
|
|
LastChange int64 `json:"lastchange"`
|
|
|
|
}{Open: response.State.Open, LastChange: response.State.LastChange},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serialize persistent state
|
|
|
|
marshal, err := json.MarshalIndent(persistentStateV14, "", "\t")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed serializing persistent state... error:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write to file
|
|
|
|
_, err = file.Write(marshal)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed writing persistent state to file", file.Name(), "... error:", err)
|
|
|
|
}
|
|
|
|
}
|