diff options
author | Christian Pointner <equinox@helsinki.at> | 2016-04-02 23:13:25 (GMT) |
---|---|---|
committer | Christian Pointner <equinox@helsinki.at> | 2016-04-02 23:13:25 (GMT) |
commit | 2f34a5e62285a3c5334c270c6111e43fc12e8dbf (patch) | |
tree | 8931b4d9fa0262f3ccc61d6b59d28a7ebd2a34dd | |
parent | df49dff4c6f96d1c2e032cc93e7b6bdb57f11833 (diff) |
refactoring of server, switch states
-rw-r--r-- | src/rhctl/audio_switch.go | 26 | ||||
-rw-r--r-- | src/rhctl/audio_switch_command.go | 30 | ||||
-rw-r--r-- | src/rhctl/main.go | 1 | ||||
-rw-r--r-- | src/rhctl/playout_server.go | 36 | ||||
-rw-r--r-- | src/rhctl/switch_control.go | 90 | ||||
-rw-r--r-- | src/rhctl/telnet.go | 43 |
6 files changed, 155 insertions, 71 deletions
diff --git a/src/rhctl/audio_switch.go b/src/rhctl/audio_switch.go index bb94f61..07e0270 100644 --- a/src/rhctl/audio_switch.go +++ b/src/rhctl/audio_switch.go @@ -79,14 +79,20 @@ type SwitchUpdate struct { Data string } +type SwitchState struct { + // TODO: fill this up with data +} + type AudioSwitch struct { - port *SerialPort - timeout time.Duration - current *SwitchCommand - timer *time.Timer - unit SwitchUnitID - Commands chan *SwitchCommand - Updates chan SwitchUpdate + port *SerialPort + timeout time.Duration + current *SwitchCommand + timer *time.Timer + unit SwitchUnitID + state SwitchState + StateChanges chan SwitchState + Commands chan *SwitchCommand + Updates chan SwitchUpdate } func (sw *AudioSwitch) handleData(data string) { @@ -115,14 +121,19 @@ func (sw *AudioSwitch) handleData(data string) { } case "S0L": sw.Updates <- SwitchUpdate{SwitchAudio, data} + // TODO: update state and send it out case "S0P": sw.Updates <- SwitchUpdate{SwitchGPI, data} + // TODO: update state and send it out case "S0O": sw.Updates <- SwitchUpdate{SwitchOC, data} + // TODO: update state and send it out case "S0R": sw.Updates <- SwitchUpdate{SwitchRelay, data} + // TODO: update state and send it out case "S0S": sw.Updates <- SwitchUpdate{SwitchSilence, data} + // TODO: update state and send it out default: rhl.Printf("Audioswitch: ignoring invalid data: %q", data) } @@ -172,6 +183,7 @@ func SwitchInit(conf *Config) (sw *AudioSwitch, err error) { sw.timeout = conf.Audioswitch.Timeout.Duration } sw.unit = conf.Audioswitch.Unit + sw.StateChanges = make(chan SwitchState, 16) sw.Commands = make(chan *SwitchCommand, 8) sw.Updates = make(chan SwitchUpdate, 32) diff --git a/src/rhctl/audio_switch_command.go b/src/rhctl/audio_switch_command.go index d3aef7e..17be8d3 100644 --- a/src/rhctl/audio_switch_command.go +++ b/src/rhctl/audio_switch_command.go @@ -124,11 +124,11 @@ func (o *SwitchOCNum) FromString(str string) error { type SwitchCmdString string const ( - SwitchCmdStatusAudio SwitchCmdString = "*uSL" - SwitchCmdStatusGPI SwitchCmdString = "*uSPA" - SwitchCmdStatusOC SwitchCmdString = "*uSO" - SwitchCmdStatusRelay SwitchCmdString = "*uSR" - SwitchCmdStatusSilence SwitchCmdString = "*uSS" + SwitchCmdStateAudio SwitchCmdString = "*uSL" + SwitchCmdStateGPI SwitchCmdString = "*uSPA" + SwitchCmdStateOC SwitchCmdString = "*uSO" + SwitchCmdStateRelay SwitchCmdString = "*uSR" + SwitchCmdStateSilence SwitchCmdString = "*uSS" SwitchCmdAudioApplyInput SwitchCmdString = "*uiio" SwitchCmdAudioApplyInputAll SwitchCmdString = "*uiiA" @@ -177,24 +177,24 @@ type SwitchCommand struct { Response chan<- interface{} } -func SwitchCommandParseStatus(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { +func SwitchCommandParseState(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { if len(args) == 0 { - err = fmt.Errorf("missing argument <status-type>") + err = fmt.Errorf("missing argument <state-type>") return } switch args[0] { case "audio": - cmdstr = SwitchCmdStatusAudio + cmdstr = SwitchCmdStateAudio case "gpi": - cmdstr = SwitchCmdStatusGPI + cmdstr = SwitchCmdStateGPI case "oc": - cmdstr = SwitchCmdStatusOC + cmdstr = SwitchCmdStateOC case "relay": - cmdstr = SwitchCmdStatusRelay + cmdstr = SwitchCmdStateRelay case "silence": - cmdstr = SwitchCmdStatusSilence + cmdstr = SwitchCmdStateSilence default: - err = fmt.Errorf("unknown status-type: '%s'", args[0]) + err = fmt.Errorf("unknown state-type: '%s'", args[0]) return } return @@ -353,8 +353,8 @@ func SwitchCommandParseOC(args []string) (cmdstr SwitchCmdString, cmdargs []inte func NewSwitchCommandFromStrings(cmd string, args ...string) (c *SwitchCommand, err error) { c = &SwitchCommand{} switch cmd { - case "status": - c.Cmd, c.Args, err = SwitchCommandParseStatus(args) + case "state": + c.Cmd, c.Args, err = SwitchCommandParseState(args) case "out": c.Cmd, c.Args, err = SwitchCommandParseAudio(args) case "relay": diff --git a/src/rhctl/main.go b/src/rhctl/main.go index 2d5b8c9..6c8d750 100644 --- a/src/rhctl/main.go +++ b/src/rhctl/main.go @@ -95,6 +95,7 @@ func main() { } servers = append(servers, server) } + // TODO: re-enable this check // if len(servers) <= 0 { // rhl.Printf("Error: there is no playout server configured...") // return diff --git a/src/rhctl/playout_server.go b/src/rhctl/playout_server.go index adba52d..ca00611 100644 --- a/src/rhctl/playout_server.go +++ b/src/rhctl/playout_server.go @@ -44,7 +44,7 @@ func (s ServerHealth) String() string { return "unknown" } -type ServerStatus struct { +type ServerState struct { Name string Health ServerHealth Channel string @@ -58,8 +58,8 @@ type PlayoutServer struct { hbtimer *time.Timer hbthreshold uint hbcnt uint - status ServerStatus - Updates chan ServerStatus + state ServerState + StateChanges chan ServerState UpdateRequest chan bool SwitchUpdates chan SwitchUpdate } @@ -72,8 +72,8 @@ func (srv *PlayoutServer) handleControl(data string) { rhl.Printf("Server(%s) sent empty channel name", srv.name) return } - srv.status.Channel = data[8:] - srv.Updates <- srv.status + srv.state.Channel = data[8:] + srv.StateChanges <- srv.state return } rhl.Printf("Server(%s): ignoring unknown control message: %q", srv.name, data) @@ -87,12 +87,12 @@ func (srv *PlayoutServer) handleHeartbeat(data string) { return } - old := srv.status.Health - srv.status.Health = ServerAlive - if old != srv.status.Health { - srv.Updates <- srv.status + old := srv.state.Health + srv.state.Health = ServerAlive + if old != srv.state.Health { + srv.StateChanges <- srv.state rhl.Printf("Server(%s): is back from the dead!", srv.name) - if srv.status.Channel == "" { + if srv.state.Channel == "" { srv.control.tx <- "channel ?" } } @@ -101,8 +101,8 @@ func (srv *PlayoutServer) handleHeartbeat(data string) { func (srv *PlayoutServer) handleHBTimeout() { rhl.Printf("Server(%s): heartbeat timed-out", srv.name) srv.hbcnt = 0 - srv.status.Health = ServerDead - srv.Updates <- srv.status + srv.state.Health = ServerDead + srv.StateChanges <- srv.state } func (srv *PlayoutServer) Run() { @@ -124,8 +124,8 @@ func (srv *PlayoutServer) Run() { case <-srv.hbtimer.C: srv.handleHBTimeout() case <-srv.UpdateRequest: - if srv.status.Health == ServerDead { - srv.Updates <- srv.status + if srv.state.Health == ServerDead { + srv.StateChanges <- srv.state } else { srv.control.tx <- "channel ?" } @@ -146,10 +146,10 @@ func ServerInit(name string, conf *Config) (srv *PlayoutServer, err error) { if conf.Servers[name].HeartbeatThreshold > 0 { srv.hbthreshold = conf.Servers[name].HeartbeatThreshold } - srv.status.Name = srv.name - srv.status.Health = ServerDead - srv.status.Channel = "" - srv.Updates = make(chan ServerStatus, 8) + srv.state.Name = srv.name + srv.state.Health = ServerDead + srv.state.Channel = "" + srv.StateChanges = make(chan ServerState, 16) srv.UpdateRequest = make(chan bool, 8) srv.SwitchUpdates = make(chan SwitchUpdate, 32) diff --git a/src/rhctl/switch_control.go b/src/rhctl/switch_control.go index f52e9a2..91cc161 100644 --- a/src/rhctl/switch_control.go +++ b/src/rhctl/switch_control.go @@ -27,18 +27,67 @@ import ( "github.com/btittelbach/pubsub" ) +type Mood uint + +const ( + MoodAwakening Mood = iota + MoodSad + MoodNervous + MoodHappy +) + +func (m Mood) String() string { + switch m { + case MoodAwakening: + return "awakening" + case MoodSad: + return "sad" + case MoodNervous: + return "nervous" + case MoodHappy: + return "happy" + } + return "unknown" +} + +type State struct { + Mood Mood + Switch SwitchState + ActiveServer string + Server map[string]ServerState +} + +func (ctrl *SwitchControl) updateOverallState(update interface{}) { + switch update.(type) { + case SwitchState: + // s := update.(SwitchState) + rhdl.Printf("SwitchCTRL overall-state: got switch update") + // TODO: update ctrl.state + // TODO: publish new "state" + case ServerState: + s := update.(ServerState) + rhdl.Printf("SwitchCTRL overall-state: got server update from '%s'", s.Name) + // TODO: update ctrl.state + // TODO: publish new "state" + default: + rhl.Printf("SwitchCTRL overall-state: got unknown state-update of type %T", update) + return + } + rhdl.Printf("SwitchCTRL overall-state: %+v", ctrl.state) +} + type CommandType uint8 const ( - CmdStatus CommandType = iota + CmdState CommandType = iota CmdServer CmdSwitch ) func (c CommandType) String() string { switch c { - case CmdStatus: - return "status" + case CmdState: + return "state" case CmdServer: return "server" case CmdSwitch: @@ -56,13 +105,14 @@ type Command struct { type SwitchControl struct { sw *AudioSwitch servers []*PlayoutServer + state State Updates *pubsub.PubSub Commands chan *Command } func (ctrl *SwitchControl) handleCommand(cmd *Command) { switch cmd.Type { - case CmdStatus: + case CmdState: case CmdServer: case CmdSwitch: if len(cmd.Args) == 0 { @@ -79,19 +129,29 @@ func (ctrl *SwitchControl) handleCommand(cmd *Command) { } } -func handleServer(in <-chan ServerStatus, out chan<- ServerStatus) { +func handleServer(in <-chan ServerState, out chan<- ServerState) { for { update := <-in out <- update } } +func (ctrl *SwitchControl) reconcile() { + rhdl.Printf("SwitchCTRL: reconciling state...") + // TODO: set mood dependent on overall-state + // if mood changes publish new "state" + + // TODO: send out commands to switch, server to get missing infos + + // TODO: change switch output mappings if servers change channels or fail +} + func (ctrl *SwitchControl) Run() { rhdl.Printf("SwitchCTRL: handler running...") - serverUpdates := make(chan ServerStatus, 8) + serverStateChanges := make(chan ServerState, 8) for _, srv := range ctrl.servers { - go handleServer(srv.Updates, serverUpdates) + go handleServer(srv.StateChanges, serverStateChanges) } for { @@ -102,10 +162,16 @@ func (ctrl *SwitchControl) Run() { srv.SwitchUpdates <- update } ctrl.Updates.Pub(update, "switch:"+update.Type.String()) - case status := <-serverUpdates: - rhdl.Printf("got server status update: %+v", status) - ctrl.Updates.Pub(status, "server:status") - // TODO: recalculate overall status and send out commands to switch + case state := <-ctrl.sw.StateChanges: + rhdl.Printf("got switch state update: %+v", state) + ctrl.Updates.Pub(state, "switch:state") + ctrl.updateOverallState(state) + ctrl.reconcile() + case state := <-serverStateChanges: + rhdl.Printf("got server state update: %+v", state) + ctrl.Updates.Pub(state, "server:state") + ctrl.updateOverallState(state) + ctrl.reconcile() case cmd := <-ctrl.Commands: ctrl.handleCommand(cmd) } @@ -116,6 +182,8 @@ func SwitchControlInit(conf *Config, sw *AudioSwitch, servers []*PlayoutServer) ctrl = &SwitchControl{} ctrl.sw = sw ctrl.servers = servers + ctrl.state.Mood = MoodAwakening + ctrl.state.Server = make(map[string]ServerState) ctrl.Updates = pubsub.NewNonBlocking(32) ctrl.Commands = make(chan *Command, 8) return diff --git a/src/rhctl/telnet.go b/src/rhctl/telnet.go index e693e70..de98475 100644 --- a/src/rhctl/telnet.go +++ b/src/rhctl/telnet.go @@ -29,8 +29,8 @@ type TelnetInterface struct { server *telgo.Server } -func telnetCmdStatus(c *telgo.Client, args []string, ctrl *SwitchControl) bool { - ctrl.Commands <- &Command{Type: CmdStatus} +func telnetCmdState(c *telgo.Client, args []string, ctrl *SwitchControl) bool { + ctrl.Commands <- &Command{Type: CmdState} // TODO: implement this return false } @@ -45,13 +45,13 @@ func telnetUpdateListener(c *telgo.Client, ctrl *SwitchControl) { switch data.(type) { case SwitchUpdate: update := data.(SwitchUpdate) - if !c.Sayln("audio-switch status(%v): %s", update.Type, update.Data) { + if !c.Sayln("audio-switch update(%v): %s", update.Type, update.Data) { ctrl.Updates.Unsub(ch) return } - case ServerStatus: - status := data.(ServerStatus) - if !c.Sayln("playout-server(%s): health=%s, channel=%s", status.Name, status.Health, status.Channel) { + case ServerState: + state := data.(ServerState) + if !c.Sayln("playout-server(%s): health=%s, channel=%s", state.Name, state.Health, state.Channel) { ctrl.Updates.Unsub(ch) return } @@ -79,10 +79,12 @@ func telnetCmdListen(c *telgo.Client, args []string, ctrl *SwitchControl) bool { } switch args[1] { - case "status": - ctrl.Updates.AddSub(ch, "status") + case "state": + ctrl.Updates.AddSub(ch, "state") case "server": - ctrl.Updates.AddSub(ch, "server:status") + ctrl.Updates.AddSub(ch, "server:state") + case "switch": + ctrl.Updates.AddSub(ch, "switch:state") case "audio": fallthrough case "gpi": @@ -140,20 +142,21 @@ func telnetHelp(c *telgo.Client, args []string) bool { c.Sayln("usage: help [ <cmd> ]") c.Sayln(" prints command overview or detailed info to <cmd>.") return false - case "status": - c.Sayln("usage: status") - c.Sayln(" show the status of the switch and servers") + case "state": + c.Sayln("usage: state") + c.Sayln(" show the state of the switch and servers") return false case "listen": c.Sayln("usage: listen <type>") c.Sayln(" subscribe to messages of type <type>. The following types are allowed:") - c.Sayln(" - status overall status changes") - c.Sayln(" - server status/health of the playout server") + c.Sayln(" - state overall state changes") + c.Sayln(" - server state/health of the playout server") + c.Sayln(" - switch state/health of switch") c.Sayln(" - audio audio input/output mapping changes") - c.Sayln(" - gpi general purpose input status messages") - c.Sayln(" - oc open-collector status messages") - c.Sayln(" - relay relay status messages") - c.Sayln(" - silence status of the silence detector") + c.Sayln(" - gpi general purpose input state messages") + c.Sayln(" - oc open-collector state messages") + c.Sayln(" - relay relay state messages") + c.Sayln(" - silence state of the silence detector") return false case "server": c.Sayln("usage: server <name>") @@ -171,7 +174,7 @@ func telnetHelp(c *telgo.Client, args []string) bool { c.Sayln(" available commands:") c.Sayln(" quit close connection (or use Ctrl-D)") c.Sayln(" help [ <cmd> ] print this, or help for specific command") - c.Sayln(" status show status of switch and all servers") + c.Sayln(" state show state of switch and all servers") c.Sayln(" listen <type> add listener for messages of type <type>") c.Sayln(" server <name> switch to server <name>") c.Sayln(" switch <cmd> [ [ <arg1> ] ... ] send command to switch") @@ -194,7 +197,7 @@ func TelnetInit(conf *Config, ctrl *SwitchControl) (telnet *TelnetInterface) { telnet = &TelnetInterface{} cmdlist := make(telgo.CmdList) - cmdlist["status"] = func(c *telgo.Client, args []string) bool { return telnetCmdStatus(c, args, ctrl) } + cmdlist["state"] = func(c *telgo.Client, args []string) bool { return telnetCmdState(c, args, ctrl) } cmdlist["listen"] = func(c *telgo.Client, args []string) bool { return telnetCmdListen(c, args, ctrl) } cmdlist["server"] = func(c *telgo.Client, args []string) bool { return telnetCmdServer(c, args, ctrl) } cmdlist["switch"] = func(c *telgo.Client, args []string) bool { return telnetCmdSwitch(c, args, ctrl) } |