github.com/simpleiot/simpleiot@v0.18.3/network/manager.go (about) 1 package network 2 3 import ( 4 "errors" 5 "log" 6 "time" 7 ) 8 9 // State is used to describe the network state 10 type State int 11 12 // define valid states 13 const ( 14 StateNotDetected State = iota 15 StateConfigure 16 StateConnecting 17 StateConnected 18 StateError 19 ) 20 21 func (s State) String() string { 22 switch s { 23 case StateNotDetected: 24 return "Not detected" 25 case StateConfigure: 26 return "Configure" 27 case StateConnecting: 28 return "Connecting" 29 case StateConnected: 30 return "Connected" 31 case StateError: 32 return "Error" 33 default: 34 return "unknown" 35 } 36 } 37 38 // Manager is used to configure the network and manage the 39 // lifecycle. 40 type Manager struct { 41 state State 42 stateStart time.Time 43 interfaces []Interface 44 errResetCnt int 45 errCnt int 46 interfaceIndex int 47 } 48 49 // NewManager constructor 50 func NewManager(errResetCnt int) *Manager { 51 return &Manager{ 52 stateStart: time.Now(), 53 errResetCnt: errResetCnt, 54 } 55 } 56 57 // AddInterface adds a network interface to the manager. Interfaces added first 58 // have higher priority 59 func (m *Manager) AddInterface(iface Interface) { 60 m.interfaces = append(m.interfaces, iface) 61 } 62 63 func (m *Manager) setState(state State) { 64 if state != m.state { 65 log.Printf("Network state: %v -> %v", m.state, state) 66 m.state = state 67 m.stateStart = time.Now() 68 } 69 } 70 71 func (m *Manager) getStatus() (InterfaceStatus, error) { 72 if len(m.interfaces) <= 0 { 73 return InterfaceStatus{}, nil 74 } 75 76 return m.interfaces[m.interfaceIndex].GetStatus() 77 } 78 79 // Desc returns current interface description 80 func (m *Manager) Desc() string { 81 if len(m.interfaces) <= 0 { 82 return "none" 83 } 84 85 return m.interfaces[m.interfaceIndex].Desc() 86 } 87 88 // nextInterface resets state and checks if there is another interface to try. 89 // If there are no more interfaces, sets state to error. 90 func (m *Manager) nextInterface() { 91 m.interfaceIndex++ 92 if m.interfaceIndex >= len(m.interfaces) { 93 m.interfaceIndex = 0 94 log.Println("Network: no more interfaces, go to error state") 95 m.setState(StateError) 96 return 97 } 98 99 m.setState(StateNotDetected) 100 101 log.Println("Network: trying next interface:", m.Desc()) 102 } 103 104 func (m *Manager) connect() error { 105 if len(m.interfaces) <= 0 { 106 return errors.New("No interfaces to connect to") 107 } 108 109 return m.interfaces[m.interfaceIndex].Connect() 110 } 111 112 func (m *Manager) configure() (InterfaceConfig, error) { 113 if len(m.interfaces) <= 0 { 114 return InterfaceConfig{}, errors.New("No interfaces to configure") 115 } 116 117 return m.interfaces[m.interfaceIndex].Configure() 118 } 119 120 // Reset resets all network interfaces 121 func (m *Manager) Reset() { 122 for _, i := range m.interfaces { 123 err := i.Reset() 124 if err != nil { 125 log.Println("Error resetting interface:", err) 126 } 127 } 128 } 129 130 // Run must be called periodically to process the network life cycle 131 // -- perhaps every 10s 132 func (m *Manager) Run() (State, InterfaceConfig, InterfaceStatus) { 133 count := 0 134 135 status := InterfaceStatus{} 136 config := InterfaceConfig{} 137 138 // state machine for network manager 139 for { 140 count++ 141 if count > 10 { 142 log.Println("network state machine ran too many times") 143 if time.Since(m.stateStart) > time.Second*15 { 144 log.Println("Network: timeout:", m.Desc()) 145 m.nextInterface() 146 } 147 148 return m.state, config, status 149 } 150 151 if m.state != StateError { 152 var err error 153 status, err = m.getStatus() 154 if err != nil { 155 log.Println("Error getting interface status:", err) 156 continue 157 } 158 } 159 160 switch m.state { 161 case StateNotDetected: 162 // give ourselves 15 seconds or so in detecting state 163 // in case we just reset the devices 164 if status.Detected { 165 log.Printf("Network: %v detected\n", m.Desc()) 166 m.setState(StateConfigure) 167 continue 168 } else if time.Since(m.stateStart) > time.Second*15 { 169 log.Println("Network: timeout detecting:", m.Desc()) 170 m.nextInterface() 171 continue 172 } 173 174 case StateConfigure: 175 try := 0 176 for ; try < 3; try++ { 177 if try > 0 { 178 log.Println("Trying again ...") 179 } 180 var err error 181 config, err = m.configure() 182 if err != nil { 183 log.Printf("Error configuring device: %v: %v\n", 184 m.Desc(), err) 185 186 continue 187 } 188 189 break 190 } 191 192 if try < 3 { 193 m.setState(StateConnecting) 194 } else { 195 log.Println("giving up configuring device:", m.Desc()) 196 m.nextInterface() 197 } 198 199 case StateConnecting: 200 if status.Connected { 201 log.Printf("Network: %v connected\n", m.Desc()) 202 m.setState(StateConnected) 203 } else { 204 if time.Since(m.stateStart) > time.Minute { 205 log.Println("Network: timeout connecting:", m.Desc()) 206 m.nextInterface() 207 continue 208 } 209 210 // try again to connect 211 err := m.connect() 212 if err != nil { 213 log.Println("Error connecting:", err) 214 } 215 } 216 217 case StateConnected: 218 if !status.Connected { 219 // try to reconnect 220 m.setState(StateConnecting) 221 } 222 223 case StateError: 224 if time.Since(m.stateStart) > time.Minute { 225 log.Println("Network: reset and try again ...") 226 m.Reset() 227 m.setState(StateNotDetected) 228 } 229 } 230 231 // if we want to re-run state machine, must execute continue above 232 break 233 } 234 235 return m.state, config, status 236 } 237 238 // Error is called any time there is a network error 239 // after errResetCnt errors are reached, we reset all the interfaces and 240 // start over 241 func (m *Manager) Error() { 242 m.errCnt++ 243 244 if m.errCnt >= m.errResetCnt { 245 m.Reset() 246 m.setState(StateNotDetected) 247 m.errCnt = 0 248 } 249 } 250 251 // Success is called any time there is a network success 252 // so that we know to reset the internal error count 253 func (m *Manager) Success() { 254 m.errCnt = 0 255 }