/
state.go
150 lines (119 loc) · 2.73 KB
/
state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package sl
import (
"encoding/json"
"os"
"path"
"sort"
"sync"
"time"
)
// Station stores the latest state information for the given network and station combination.
type Station struct {
Network string `json:"network"`
Station string `json:"station"`
Sequence int `json:"sequence"`
Timestamp time.Time `json:"timestamp"`
}
// Key returns a blank Station except for the Network and Station entries, this useful as a map key.
func (s Station) Key() Station {
return Station{
Network: s.Network,
Station: s.Station,
}
}
// State maintains the current state information for a seedlink connection.
type State struct {
mu sync.Mutex
once sync.Once
state map[Station]Station
}
// Stations returns a sorted slice of current station state information.
func (s *State) Stations() []Station {
s.mu.Lock()
defer s.mu.Unlock()
var stations []Station
for _, v := range s.state {
stations = append(stations, v)
}
sort.Slice(stations, func(i, j int) bool {
switch {
case stations[i].Network < stations[j].Network:
return true
case stations[i].Network > stations[j].Network:
return false
case stations[i].Station < stations[j].Station:
return true
default:
return false
}
})
return stations
}
// Add inserts or updates the station collection details into the connection state.
func (s *State) Add(station Station) {
s.mu.Lock()
defer s.mu.Unlock()
s.once.Do(func() {
s.state = make(map[Station]Station)
})
// there is an edge case when using wildcard options are in use and
// different sampling rates may generate timestamp mismatches.
s.state[station.Key()] = station
}
func (s *State) Find(stn Station) *Station {
s.mu.Lock()
defer s.mu.Unlock()
for k, v := range s.state {
if ok, err := path.Match(stn.Network, k.Network); err != nil || !ok {
continue
}
if ok, err := path.Match(stn.Station, k.Station); err != nil || !ok {
continue
}
return &v
}
return nil
}
func (s *State) Unmarshal(data []byte) error {
var stations []Station
if err := json.Unmarshal(data, &stations); err != nil {
return err
}
for _, v := range stations {
s.Add(v)
}
return nil
}
func (s *State) Marshal() ([]byte, error) {
data, err := json.MarshalIndent(s.Stations(), "", " ")
if err != nil {
return nil, err
}
return data, nil
}
func (s *State) ReadFile(path string) error {
if path == "" {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return err
}
if err := s.Unmarshal(data); err != nil {
return err
}
return nil
}
func (s *State) WriteFile(path string) error {
if path == "" {
return nil
}
data, err := s.Marshal()
if err != nil {
return err
}
if err := os.WriteFile(path, data, 0644); err != nil { // nolint: gosec
return err
}
return nil
}