summaryrefslogtreecommitdiff
path: root/src/rhctl
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2016-04-02 23:13:25 (GMT)
committerChristian Pointner <equinox@helsinki.at>2016-04-02 23:13:25 (GMT)
commit2f34a5e62285a3c5334c270c6111e43fc12e8dbf (patch)
tree8931b4d9fa0262f3ccc61d6b59d28a7ebd2a34dd /src/rhctl
parentdf49dff4c6f96d1c2e032cc93e7b6bdb57f11833 (diff)
refactoring of server, switch states
Diffstat (limited to 'src/rhctl')
-rw-r--r--src/rhctl/audio_switch.go26
-rw-r--r--src/rhctl/audio_switch_command.go30
-rw-r--r--src/rhctl/main.go1
-rw-r--r--src/rhctl/playout_server.go36
-rw-r--r--src/rhctl/switch_control.go90
-rw-r--r--src/rhctl/telnet.go43
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) }