...
1
16
17 package nodeshutdown
18
19 import (
20 "encoding/json"
21 "io"
22 "os"
23 "path/filepath"
24 "time"
25 )
26
27 type storage interface {
28 Store(data interface{}) (err error)
29 Load(data interface{}) (err error)
30 }
31
32 type localStorage struct {
33 Path string
34 }
35
36 func (l localStorage) Store(data interface{}) (err error) {
37 b, err := json.Marshal(data)
38 if err != nil {
39 return err
40 }
41 return atomicWrite(l.Path, b, 0644)
42 }
43
44 func (l localStorage) Load(data interface{}) (err error) {
45 b, err := os.ReadFile(l.Path)
46 if err != nil {
47 if os.IsNotExist(err) {
48 return nil
49 }
50 return err
51 }
52 return json.Unmarshal(b, data)
53 }
54
55 func timestamp(t time.Time) float64 {
56 if t.IsZero() {
57 return 0
58 }
59 return float64(t.Unix())
60 }
61
62 type state struct {
63 StartTime time.Time `json:"startTime"`
64 EndTime time.Time `json:"endTime"`
65 }
66
67
68 func atomicWrite(filename string, data []byte, perm os.FileMode) error {
69 f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
70 if err != nil {
71 return err
72 }
73 err = os.Chmod(f.Name(), perm)
74 if err != nil {
75 f.Close()
76 return err
77 }
78 n, err := f.Write(data)
79 if err != nil {
80 f.Close()
81 return err
82 }
83 if n < len(data) {
84 f.Close()
85 return io.ErrShortWrite
86 }
87 if err := f.Sync(); err != nil {
88 f.Close()
89 return err
90 }
91 if err := f.Close(); err != nil {
92 return err
93 }
94 return os.Rename(f.Name(), filename)
95 }
96
View as plain text