From 38f73f60186e20a927be4bb1fc4a05df0f8bcb53 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 3 Nov 2020 14:08:14 +0100 Subject: [PATCH] Auto restart executed commands --- cmdrunner.go | 105 ++++++++++++++++++++++++++++++++++++++++ controlstream.go | 11 +++-- main.go | 6 +-- runcmd.go | 123 ----------------------------------------------- serialtcpsrv.go | 3 +- 5 files changed, 117 insertions(+), 131 deletions(-) create mode 100644 cmdrunner.go delete mode 100644 runcmd.go diff --git a/cmdrunner.go b/cmdrunner.go new file mode 100644 index 0000000..2b8e4e5 --- /dev/null +++ b/cmdrunner.go @@ -0,0 +1,105 @@ +package main + +import ( + "os/exec" + "strings" + "syscall" + "time" +) + +const startCmdDelay = time.Second + +type cmdRunner struct { + restartNeeded chan bool + runEndNeeded chan bool + runEndFinished chan bool +} + +var runCmdRunner cmdRunner +var serialCmdRunner cmdRunner +var rigctldRunner cmdRunner + +func (c *cmdRunner) kill(cmd *exec.Cmd) { + err := cmd.Process.Kill() + if err != nil { + err = cmd.Process.Signal(syscall.SIGKILL) + if err != nil { + log.Error("can't kill ", cmd) + } + } +} + +func (c *cmdRunner) run(cmdLine string) { + var cmd *exec.Cmd + + defer func() { + if cmd != nil { + c.kill(cmd) + } + c.runEndFinished <- true + }() + + s := strings.Split(cmdLine, " ") + + for { + select { + case <-c.runEndNeeded: + return + case <-time.After(startCmdDelay): + } + + cmd = exec.Command(s[0], s[1:]...) + err := cmd.Start() + if err != nil { + log.Error("error starting ", cmd) + continue + } + + log.Print("started: ", cmd) + + finishedChan := make(chan error) + go func() { + finishedChan <- cmd.Wait() + }() + + select { + case <-c.restartNeeded: + log.Debug("restarting ", cmd) + c.kill(cmd) + case err := <-finishedChan: + if err != nil { + log.Error(cmd, " error: ", err) + } + case <-c.runEndNeeded: + return + } + } +} + +func (c *cmdRunner) startIfNeeded(cmdLine string) { + if c.runEndNeeded != nil || cmdLine == "" || cmdLine == "-" { + return + } + + c.restartNeeded = make(chan bool) + c.runEndNeeded = make(chan bool) + c.runEndFinished = make(chan bool) + go c.run(cmdLine) +} + +func (c *cmdRunner) restart() { + if c.restartNeeded == nil { + return + } + + c.restartNeeded <- true +} + +func (c *cmdRunner) stop() { + if c.runEndNeeded == nil { + return + } + + c.runEndNeeded <- true + <-c.runEndFinished +} diff --git a/controlstream.go b/controlstream.go index d5f6a10..6f724a1 100644 --- a/controlstream.go +++ b/controlstream.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "encoding/binary" "errors" + "fmt" "time" ) @@ -258,9 +259,13 @@ func (s *controlStream) handleRead(r []byte) error { s.serialAndAudioStreamOpened = true statusLog.startPeriodicPrint() - startCmdIfNeeded() - startSerialPortCmdIfNeeded() - startRigctldCmdIfNeeded() + runCmdRunner.startIfNeeded(runCmd) + if enableSerialDevice { + serialCmdRunner.startIfNeeded(runCmdOnSerialPortCreated) + } + if !disableRigctld { + rigctldRunner.startIfNeeded(fmt.Sprint("rigctld -m ", rigctldModel, " -r :", serialTCPPort)) + } } } return nil diff --git a/main.go b/main.go index e3c3788..ac10550 100644 --- a/main.go +++ b/main.go @@ -132,9 +132,9 @@ func main() { } } - stopCmd() - stopSerialPortCmd() - stopRigctldCmd() + runCmdRunner.stop() + serialCmdRunner.stop() + rigctldRunner.stop() audio.deinit() serialTCPSrv.deinit() serialPort.deinit() diff --git a/runcmd.go b/runcmd.go deleted file mode 100644 index 5014a38..0000000 --- a/runcmd.go +++ /dev/null @@ -1,123 +0,0 @@ -package main - -import ( - "fmt" - "os/exec" - "strings" - "time" -) - -const startCmdDelay = time.Second - -var startedRigctldCmd *exec.Cmd -var rigctldCmdStartTimer *time.Timer -var startedCmd *exec.Cmd -var cmdStartTimer *time.Timer -var serialPortStartedCmd *exec.Cmd -var serialPortCmdStartTimer *time.Timer - -func doStartRigctldCmd() { - startedRigctldCmd = exec.Command("rigctld", "-m", fmt.Sprint(rigctldModel), "-r", - fmt.Sprint(":", serialTCPPort)) - err := startedRigctldCmd.Start() - if err == nil { - log.Print("rigctld started: ", startedRigctldCmd) - } else { - log.Error("error starting rigctld: ", err) - startedCmd = nil - } - rigctldCmdStartTimer = nil -} - -func startRigctldCmdIfNeeded() { - if startedRigctldCmd != nil || disableRigctld { - return - } - - if rigctldCmdStartTimer != nil { - rigctldCmdStartTimer.Stop() - } - rigctldCmdStartTimer = time.AfterFunc(startCmdDelay, doStartRigctldCmd) -} - -func stopRigctldCmd() { - if startedRigctldCmd == nil { - return - } - - if err := startedRigctldCmd.Process.Kill(); err != nil { - log.Error("failed to stop rigctld: ", err) - } - _ = startedRigctldCmd.Wait() - startedRigctldCmd = nil -} - -func doStartCmd() { - c := strings.Split(runCmd, " ") - startedCmd = exec.Command(c[0], c[1:]...) - err := startedCmd.Start() - if err == nil { - log.Print("cmd started: ", runCmd) - } else { - log.Error("error starting ", runCmd, ": ", err) - startedCmd = nil - } - cmdStartTimer = nil -} - -func startCmdIfNeeded() { - if startedCmd != nil || runCmd == "" { - return - } - - if cmdStartTimer != nil { - cmdStartTimer.Stop() - } - cmdStartTimer = time.AfterFunc(startCmdDelay, doStartCmd) -} - -func stopCmd() { - if startedCmd == nil { - return - } - - if err := startedCmd.Process.Kill(); err != nil { - log.Error("failed to stop cmd ", runCmd, ": ", err) - } - startedCmd = nil -} - -func doSerialPortStartCmd() { - c := strings.Split(runCmdOnSerialPortCreated, " ") - serialPortStartedCmd = exec.Command(c[0], c[1:]...) - err := serialPortStartedCmd.Start() - if err == nil { - log.Print("cmd started: ", runCmdOnSerialPortCreated) - } else { - log.Error("error starting ", runCmdOnSerialPortCreated, ": ", err) - serialPortStartedCmd = nil - } - serialPortCmdStartTimer = nil -} - -func startSerialPortCmdIfNeeded() { - if !enableSerialDevice || serialPortStartedCmd != nil || runCmdOnSerialPortCreated == "-" { - return - } - - if serialPortCmdStartTimer != nil { - serialPortCmdStartTimer.Stop() - } - serialPortCmdStartTimer = time.AfterFunc(startCmdDelay, doSerialPortStartCmd) -} - -func stopSerialPortCmd() { - if serialPortStartedCmd == nil { - return - } - - if err := serialPortStartedCmd.Process.Kill(); err != nil { - log.Error("failed to stop cmd ", runCmdOnSerialPortCreated, ": ", err) - } - serialPortStartedCmd = nil -} diff --git a/serialtcpsrv.go b/serialtcpsrv.go index 256fc14..79619a7 100644 --- a/serialtcpsrv.go +++ b/serialtcpsrv.go @@ -104,8 +104,7 @@ func (s *serialTCPSrvStruct) loop() { s.disconnectClient() log.Print("client ", s.client.RemoteAddr().String(), " disconnected") - stopRigctldCmd() - startRigctldCmdIfNeeded() + rigctldRunner.restart() } }