// // rhctl // // Copyright (C) 2009-2016 Christian Pointner // // This file is part of rhctl. // // rhctl is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // rhctl is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with rhctl. If not, see . // package main import ( "fmt" "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 ( CmdState CommandType = iota CmdServer CmdSwitch ) func (c CommandType) String() string { switch c { case CmdState: return "state" case CmdServer: return "server" case CmdSwitch: return "switch" } return "unknown" } type Command struct { Type CommandType Args []string Response chan<- interface{} } 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 CmdState: case CmdServer: case CmdSwitch: if len(cmd.Args) == 0 { rhl.Printf("SwitchCTRL: ignoring empty raw switch command") return } c, err := NewSwitchCommandFromStrings(cmd.Args[0], cmd.Args[1:]...) if err != nil { cmd.Response <- fmt.Errorf("switch command syntax error: %s", err.Error()) return } c.Response = cmd.Response ctrl.sw.Commands <- c } } 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...") serverStateChanges := make(chan ServerState, 8) for _, srv := range ctrl.servers { go handleServer(srv.StateChanges, serverStateChanges) } for { select { case update := <-ctrl.sw.Updates: rhdl.Printf("got update from switch: %+v", update) for _, srv := range ctrl.servers { srv.SwitchUpdates <- update } ctrl.Updates.Pub(update, "switch:"+update.Type.String()) 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) } } } func SwitchControlInit(conf *Config, sw *AudioSwitch, servers []*PlayoutServer) (ctrl *SwitchControl) { 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 }