// // 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" "strings" "time" ) type ServerHealth bool const ( ServerDead ServerHealth = false ServerAlive ServerHealth = true ) func (s ServerHealth) String() string { switch s { case ServerDead: return "dead" case ServerAlive: return "alive" } return "unknown" } type ServerStatus struct { Health ServerHealth Channel string } type PlayoutServer struct { name string control *SerialPort heartbeat *SerialPort hbtimeout time.Duration hbtimer *time.Timer hbthreshold uint hbcnt uint status ServerStatus Updates chan ServerStatus } func (srv *PlayoutServer) handleControl(data string) { rhdl.Printf("Server(%s): got control message: %q", srv.name, data) if strings.HasPrefix(data, "channel ") { if len(data) <= 8 { rhl.Printf("Server(%s) sent empty channel name", srv.name) return } srv.status.Channel = data[8:] srv.Updates <- srv.status return } rhl.Printf("Server(%s): ignoring unknown control message: %q", srv.name, data) } func (srv *PlayoutServer) handleHeartbeat(data string) { rhdl.Printf("Server(%s): got heartbeat message: %q", srv.name, data) srv.hbtimer.Reset(srv.hbtimeout) srv.hbcnt++ if srv.hbcnt < srv.hbthreshold { return } old := srv.status.Health srv.status.Health = ServerAlive if old != srv.status.Health { srv.Updates <- srv.status } } func (srv *PlayoutServer) handleHBTimeout() { rhl.Printf("Server(%s): heartbeat timed-out", srv.name) srv.hbcnt = 0 srv.status.Health = ServerDead srv.Updates <- srv.status } func (srv *PlayoutServer) Run() { stop := make(chan bool) srv.control.Run(stop) srv.heartbeat.Run(stop) srv.hbtimer = time.NewTimer(srv.hbtimeout) srv.hbcnt = 0 rhdl.Printf("Server(%s): handler running...", srv.name) for { select { case <-stop: return case data := <-srv.control.rx: srv.handleControl(data) case data := <-srv.heartbeat.rx: srv.handleHeartbeat(data) case <-srv.hbtimer.C: srv.handleHBTimeout() } } } func ServerInit(name string, conf *Config) (srv *PlayoutServer, err error) { srv = &PlayoutServer{} srv.name = name srv.hbtimeout = 3 * time.Second if conf.Servers[name].HeartbeatTimeout.Duration > time.Duration(0) { srv.hbtimeout = conf.Servers[name].HeartbeatTimeout.Duration } srv.hbthreshold = 10 if conf.Servers[name].HeartbeatThreshold > 0 { srv.hbthreshold = conf.Servers[name].HeartbeatThreshold } srv.status.Health = ServerDead srv.status.Channel = "" srv.Updates = make(chan ServerStatus, 8) if srv.control, err = SerialOpen(conf.Servers[name].ControlDevice, conf.Servers[name].ControlBaudrate, "\r\n"); err != nil { err = fmt.Errorf("Server(%s): error opening control port: %s", srv.name, err) return } if srv.heartbeat, err = SerialOpen(conf.Servers[name].HeartbeatDevice, conf.Servers[name].HeartbeatBaudrate, "\r\n"); err != nil { err = fmt.Errorf("Server(%s): error opening heartbeat port: %s", srv.name, err) return } return }