From 7b6cc0eb1d6d8e2a7fa22ade10e79eb06f0d6bbf Mon Sep 17 00:00:00 2001
From: Christian Pointner <equinox@helsinki.at>
Date: Mon, 18 Apr 2016 23:58:07 +0200
Subject: fetch state from switch and server if they are stale/missing


diff --git a/src/rhctl/audio_switch.go b/src/rhctl/audio_switch.go
index 8c698b4..dd61f46 100644
--- a/src/rhctl/audio_switch.go
+++ b/src/rhctl/audio_switch.go
@@ -85,9 +85,10 @@ type SwitchState struct {
 		Inputs  [SwitchInputNumMax]bool
 		Silence bool
 	}
-	GPI   [SwitchGPINumMax]bool
-	Relay [SwitchRelayNumMax]bool
-	OC    [SwitchOCNumMax]bool
+	GPI     [SwitchGPINumMax]bool
+	Relay   [SwitchRelayNumMax]bool
+	OC      [SwitchOCNumMax]bool
+	Changed time.Time
 }
 
 type AudioSwitch struct {
@@ -127,6 +128,7 @@ func (sw *AudioSwitch) updateStateAudio(data string) {
 			rhl.Printf("Audioswitch: invalid audio status update (state must be either '1' or '0' but is '%s')", ins[i])
 		}
 	}
+	sw.state.Changed = time.Now()
 	sw.StateChanges <- sw.state
 }
 
@@ -152,6 +154,7 @@ func (sw *AudioSwitch) updateStateGPI(data string) {
 			rhl.Printf("Audioswitch: invalid gpi status update (state must be either '1' or '0' but is '%s')", data[7:8])
 			return
 		}
+		sw.state.Changed = time.Now()
 		sw.StateChanges <- sw.state
 		return
 	}
@@ -177,6 +180,7 @@ func (sw *AudioSwitch) updateStateGPI(data string) {
 			rhl.Printf("Audioswitch: invalid gpi status update (state must be either '1' or '0' but is '%s')", ins[i])
 		}
 	}
+	sw.state.Changed = time.Now()
 	sw.StateChanges <- sw.state
 }
 
@@ -201,6 +205,7 @@ func (sw *AudioSwitch) updateStateRelay(data string) {
 			rhl.Printf("Audioswitch: invalid relay status update (state must be either '1' or '0' but is '%s')", outs[i])
 		}
 	}
+	sw.state.Changed = time.Now()
 	sw.StateChanges <- sw.state
 }
 
@@ -225,6 +230,7 @@ func (sw *AudioSwitch) updateStateOC(data string) {
 			rhl.Printf("Audioswitch: invalid oc status update (state must be either '1' or '0' but is '%s')", outs[i])
 		}
 	}
+	sw.state.Changed = time.Now()
 	sw.StateChanges <- sw.state
 }
 
@@ -249,6 +255,7 @@ func (sw *AudioSwitch) updateStateSilence(data string) {
 			rhl.Printf("Audioswitch: invalid silence status update (state must be either '1' or '0' but is '%s')", outs[i])
 		}
 	}
+	sw.state.Changed = time.Now()
 	sw.StateChanges <- sw.state
 }
 
@@ -261,12 +268,14 @@ func (sw *AudioSwitch) handleData(data string) {
 	rhdl.Printf("Audioswitch: got data: %q", data)
 	if data[0:3] == "RRR" || data[0:3] == "EEE" {
 		if sw.current != nil {
-			resp := SwitchResponse{Message: data}
-			resp.Result = SwitchError
-			if data[0] == 'R' {
-				resp.Result = SwitchOK
+			if sw.current.Response != nil {
+				resp := SwitchResponse{Message: data}
+				resp.Result = SwitchError
+				if data[0] == 'R' {
+					resp.Result = SwitchOK
+				}
+				sw.current.Response <- resp
 			}
-			sw.current.Response <- resp
 			sw.current = nil
 			sw.timer.Stop()
 			sw.timer = nil
@@ -313,7 +322,9 @@ func (sw *AudioSwitch) Run() {
 			case <-stop:
 				return
 			case <-sw.timer.C:
-				sw.current.Response <- fmt.Errorf("command timed out")
+				if sw.current.Response != nil {
+					sw.current.Response <- fmt.Errorf("command timed out")
+				}
 				sw.current = nil
 				sw.timer = nil
 			case data := <-sw.port.rx:
@@ -326,7 +337,9 @@ func (sw *AudioSwitch) Run() {
 			case cmd := <-sw.Commands:
 				c, err := cmd.Cmd.Generate(append(cmd.Args, sw.unit)...)
 				if err != nil {
-					cmd.Response <- err
+					if cmd.Response != nil {
+						cmd.Response <- err
+					}
 				} else {
 					rhdl.Printf("sending '%s' to switch", c)
 					sw.current = cmd
@@ -348,7 +361,7 @@ func SwitchInit(conf *Config) (sw *AudioSwitch, err error) {
 	}
 	sw.unit = conf.Audioswitch.Unit
 	sw.StateChanges = make(chan SwitchState, 16)
-	sw.Commands = make(chan *SwitchCommand, 8)
+	sw.Commands = make(chan *SwitchCommand, 16)
 	sw.Updates = make(chan SwitchUpdate, 32)
 
 	if sw.port, err = SerialOpen(conf.Audioswitch.Device, conf.Audioswitch.Baudrate, ""); err != nil {
diff --git a/src/rhctl/playout_server.go b/src/rhctl/playout_server.go
index ca00611..30577b8 100644
--- a/src/rhctl/playout_server.go
+++ b/src/rhctl/playout_server.go
@@ -48,6 +48,7 @@ type ServerState struct {
 	Name    string
 	Health  ServerHealth
 	Channel string
+	Changed time.Time
 }
 
 type PlayoutServer struct {
@@ -73,6 +74,7 @@ func (srv *PlayoutServer) handleControl(data string) {
 			return
 		}
 		srv.state.Channel = data[8:]
+		srv.state.Changed = time.Now()
 		srv.StateChanges <- srv.state
 		return
 	}
@@ -89,6 +91,7 @@ func (srv *PlayoutServer) handleHeartbeat(data string) {
 
 	old := srv.state.Health
 	srv.state.Health = ServerAlive
+	srv.state.Changed = time.Now()
 	if old != srv.state.Health {
 		srv.StateChanges <- srv.state
 		rhl.Printf("Server(%s): is back from the dead!", srv.name)
@@ -102,6 +105,7 @@ func (srv *PlayoutServer) handleHBTimeout() {
 	rhl.Printf("Server(%s): heartbeat timed-out", srv.name)
 	srv.hbcnt = 0
 	srv.state.Health = ServerDead
+	srv.state.Changed = time.Now()
 	srv.StateChanges <- srv.state
 }
 
diff --git a/src/rhctl/switch_control.go b/src/rhctl/switch_control.go
index 2864cc9..caee99b 100644
--- a/src/rhctl/switch_control.go
+++ b/src/rhctl/switch_control.go
@@ -23,6 +23,7 @@ package main
 
 import (
 	"fmt"
+	"time"
 
 	"github.com/btittelbach/pubsub"
 )
@@ -125,7 +126,20 @@ func handleServer(in <-chan ServerState, out chan<- ServerState) {
 
 func (ctrl *SwitchControl) reconcile(requestedServer string) (result bool) {
 	rhdl.Printf("SwitchCTRL: reconciling state... (requested server: '%s')", requestedServer)
-	// TODO: set mood dependent on overall-state
+	if time.Since(ctrl.state.Switch.Changed) > (2 * time.Hour) { // TODO: hardcoded value
+		ctrl.sw.Commands <- &SwitchCommand{SwitchCmdStateAudio, nil, nil}
+		ctrl.sw.Commands <- &SwitchCommand{SwitchCmdStateGPIAll, nil, nil}
+		ctrl.sw.Commands <- &SwitchCommand{SwitchCmdStateOC, nil, nil}
+		ctrl.sw.Commands <- &SwitchCommand{SwitchCmdStateRelay, nil, nil}
+		ctrl.sw.Commands <- &SwitchCommand{SwitchCmdStateSilence, nil, nil}
+	}
+
+	for _, server := range ctrl.servers {
+		s, exists := ctrl.state.Server[server.name]
+		if !exists || time.Since(s.Changed) > (2*time.Hour) { // TODO: hardcoded value
+			server.UpdateRequest <- true
+		}
+	}
 
 	// TODO: send out commands to switch and/or server to get missing infos
 
@@ -133,6 +147,8 @@ func (ctrl *SwitchControl) reconcile(requestedServer string) (result bool) {
 	//       return true if requested server got selected
 
 	// TODO: change switch output mappings if servers change channels or fail
+
+	// TODO: set mood dependent on overall-state
 	return
 }
 
-- 
cgit v0.10.2