package main import ( "os" "os/signal" "runtime/debug" "strings" "syscall" "time" ) const waitBetweenRetries = time.Second const retryCount = 5 const waitOnRetryFailure = 65 * time.Second var gotErrChan = make(chan bool) var quitChan = make(chan bool) func getAboutStr() string { var v string bi, ok := debug.ReadBuildInfo() if ok { v = bi.Main.Version } else { v = "(devel)" } return "kappanhang " + v + " by Norbert Varga HA2NON and Akos Marton ES1AKOS https://github.com/nonoo/kappanhang" } func wait(d time.Duration, osSignal chan os.Signal) (shouldExit bool) { for sec := d.Seconds(); sec > 0; sec-- { log.Print("waiting ", sec, " seconds...") select { case <-time.After(time.Second): case <-osSignal: log.Print("sigterm received") return true case <-quitChan: return true } } return false } func runControlStream(osSignal chan os.Signal) (requireWait, shouldExit bool, exitCode int) { // Depleting gotErrChan. var finished bool for !finished { select { case <-gotErrChan: default: finished = true } } ctrl := &controlStream{} if err := ctrl.init(); err != nil { log.Error(err) ctrl.deinit() if strings.Contains(err.Error(), "invalid username/password") { return false, true, 1 } return } select { // Need to wait before reinit because the IC-705 will disconnect our audio stream eventually if we relogin // in a too short interval without a deauth... case requireWait = <-gotErrChan: ctrl.deinit() return case <-osSignal: log.Print("sigterm received") ctrl.deinit() return false, true, 0 case <-quitChan: ctrl.deinit() return false, true, 0 } } func reportError(err error) { if !strings.Contains(err.Error(), "use of closed network connection") { log.ErrorC(log.GetCallerFileName(true), ": ", err) } requireWait := true if strings.Contains(err.Error(), "got radio disconnected") { requireWait = false } // Non-blocking notify. select { case gotErrChan <- requireWait: default: } } func main() { parseArgs() log.Init() log.Print(getAboutStr()) osSignal := make(chan os.Signal, 1) signal.Notify(osSignal, os.Interrupt, syscall.SIGTERM) var retries int var requireWait bool var shouldExit bool var exitCode int exit: for { requireWait, shouldExit, exitCode = runControlStream(osSignal) if shouldExit { break } select { case <-osSignal: log.Print("sigterm received") break exit case <-quitChan: break exit default: } if requireWait { if retries < retryCount { retries++ shouldExit = wait(waitBetweenRetries, osSignal) } else { retries = 0 shouldExit = wait(waitOnRetryFailure, osSignal) } } else { retries = 0 shouldExit = wait(time.Second, osSignal) } if shouldExit { break } log.Print("restarting control stream...") } rigctld.deinit() serialTCPSrv.deinit() runCmdRunner.stop() serialCmdRunner.stop() audio.deinit() serialPort.deinit() if statusLog.isRealtimeInternal() { keyboard.deinit() } log.Print("exiting") os.Exit(exitCode) }