github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/internal/outlet/state_file.go (about) 1 package outlet 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 7 "github.com/martinohmann/rfoutlet/internal/schedule" 8 ) 9 10 // outletState represents the state of a single outlet. 11 type outletState struct { 12 State State `json:"state,omitempty"` 13 Schedule *schedule.Schedule `json:"schedule,omitempty"` 14 } 15 16 // StateFile holds the state and schedule of all configured outlets. This is 17 // used as persistence across rfoutlet restarts. 18 type StateFile struct { 19 Filename string 20 } 21 22 // NewStateFile creates a new *StateFile with filename. 23 func NewStateFile(filename string) *StateFile { 24 return &StateFile{ 25 Filename: filename, 26 } 27 } 28 29 // ReadBack reads outlet state from the state file back into the passed in 30 // outlets. Returns an error if the state file cannot be read or if its 31 // contents are invalid. 32 func (f *StateFile) ReadBack(outlets []*Outlet) error { 33 buf, err := ioutil.ReadFile(f.Filename) 34 if err != nil { 35 return err 36 } 37 38 var stateMap map[string]outletState 39 40 err = json.Unmarshal(buf, &stateMap) 41 if err != nil { 42 return err 43 } 44 45 applyOutletStates(outlets, stateMap) 46 47 return nil 48 } 49 50 // WriteOut writes out the outlet states to the state file. Returns an error if 51 // writing the state file fails. 52 func (f *StateFile) WriteOut(outlets []*Outlet) error { 53 stateMap := collectOutletStates(outlets) 54 55 buf, err := json.Marshal(stateMap) 56 if err != nil { 57 return err 58 } 59 60 return ioutil.WriteFile(f.Filename, buf, 0664) 61 } 62 63 func applyOutletStates(outlets []*Outlet, stateMap map[string]outletState) { 64 for _, o := range outlets { 65 outletState, ok := stateMap[o.ID] 66 if !ok { 67 continue 68 } 69 70 o.SetState(outletState.State) 71 o.Schedule = outletState.Schedule 72 if o.Schedule == nil { 73 o.Schedule = schedule.New() 74 } 75 } 76 } 77 78 func collectOutletStates(outlets []*Outlet) map[string]outletState { 79 stateMap := make(map[string]outletState) 80 81 for _, o := range outlets { 82 stateMap[o.ID] = outletState{ 83 State: o.GetState(), 84 Schedule: o.Schedule, 85 } 86 } 87 88 return stateMap 89 }