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  }