From 84735426eb72ce57bf492d00bbf4fcd463e744aa Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Wed, 8 Dec 2021 21:23:45 +0100 Subject: [PATCH] print a message when a custom command exits suddently --- internal/core/path.go | 15 ++++++++++++--- internal/core/rtmp_conn.go | 8 +++++++- internal/core/rtsp_conn.go | 3 +++ internal/core/rtsp_session.go | 5 ++++- internal/externalcmd/cmd.go | 13 +++++++++++-- internal/externalcmd/cmd_unix.go | 25 +++++++++++++++++-------- internal/externalcmd/cmd_win.go | 27 ++++++++++++++++++--------- 7 files changed, 72 insertions(+), 24 deletions(-) diff --git a/internal/core/path.go b/internal/core/path.go index 7cbb45bc..e4d669b1 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -343,7 +343,10 @@ func (pa *path) run() { onInitCmd = externalcmd.New( pa.conf.RunOnInit, pa.conf.RunOnInitRestart, - pa.externalCmdEnv()) + pa.externalCmdEnv(), + func(co int) { + pa.log(logger.Info, "runOnInit command exited with code %d", co) + }) } err := func() error { @@ -543,7 +546,10 @@ func (pa *path) onDemandStartSource() { pa.onDemandCmd = externalcmd.New( pa.conf.RunOnDemand, pa.conf.RunOnDemandRestart, - pa.externalCmdEnv()) + pa.externalCmdEnv(), + func(co int) { + pa.log(logger.Info, "runOnDemand command exited with code %d", co) + }) pa.onDemandReadyTimer = time.NewTimer(time.Duration(pa.conf.RunOnDemandStartTimeout)) } @@ -796,7 +802,10 @@ func (pa *path) handlePublisherRecord(req pathPublisherRecordReq) { pa.onPublishCmd = externalcmd.New( pa.conf.RunOnPublish, pa.conf.RunOnPublishRestart, - pa.externalCmdEnv()) + pa.externalCmdEnv(), + func(co int) { + pa.log(logger.Info, "runOnPublish command exited with code %d", co) + }) } req.Res <- pathPublisherRecordRes{Stream: pa.stream} diff --git a/internal/core/rtmp_conn.go b/internal/core/rtmp_conn.go index 3595546a..e6a22780 100644 --- a/internal/core/rtmp_conn.go +++ b/internal/core/rtmp_conn.go @@ -154,6 +154,9 @@ func (c *rtmpConn) run() { externalcmd.Environment{ "RTSP_PATH": "", "RTSP_PORT": port, + }, + func(co int) { + c.log(logger.Info, "runOnConnect command exited with code %d", co) }) defer func() { @@ -289,7 +292,10 @@ func (c *rtmpConn) runRead(ctx context.Context) error { onReadCmd := externalcmd.New( c.path.Conf().RunOnRead, c.path.Conf().RunOnReadRestart, - c.path.externalCmdEnv()) + c.path.externalCmdEnv(), + func(co int) { + c.log(logger.Info, "runOnRead command exited with code %d", co) + }) defer func() { onReadCmd.Close() c.log(logger.Info, "runOnRead command stopped") diff --git a/internal/core/rtsp_conn.go b/internal/core/rtsp_conn.go index 2479b88c..7ce98748 100644 --- a/internal/core/rtsp_conn.go +++ b/internal/core/rtsp_conn.go @@ -71,6 +71,9 @@ func newRTSPConn( externalcmd.Environment{ "RTSP_PATH": "", "RTSP_PORT": port, + }, + func(co int) { + c.log(logger.Info, "runOnInit command exited with code %d", co) }) } diff --git a/internal/core/rtsp_session.go b/internal/core/rtsp_session.go index 0abcb507..a2fb0a17 100644 --- a/internal/core/rtsp_session.go +++ b/internal/core/rtsp_session.go @@ -279,7 +279,10 @@ func (s *rtspSession) onPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Respo s.onReadCmd = externalcmd.New( s.path.Conf().RunOnRead, s.path.Conf().RunOnReadRestart, - s.path.externalCmdEnv()) + s.path.externalCmdEnv(), + func(co int) { + s.log(logger.Info, "runOnRead command exited with code %d", co) + }) } s.stateMutex.Lock() diff --git a/internal/externalcmd/cmd.go b/internal/externalcmd/cmd.go index e06bf5d9..6f59d0d7 100644 --- a/internal/externalcmd/cmd.go +++ b/internal/externalcmd/cmd.go @@ -16,6 +16,7 @@ type Cmd struct { cmdstr string restart bool env Environment + onExit func(int) // in terminate chan struct{} @@ -25,11 +26,17 @@ type Cmd struct { } // New allocates an Cmd. -func New(cmdstr string, restart bool, env Environment) *Cmd { +func New( + cmdstr string, + restart bool, + env Environment, + onExit func(int), +) *Cmd { e := &Cmd{ cmdstr: cmdstr, restart: restart, env: env, + onExit: onExit, terminate: make(chan struct{}), done: make(chan struct{}), } @@ -50,11 +57,13 @@ func (e *Cmd) run() { for { ok := func() bool { - ok := e.runInner() + c, ok := e.runInner() if !ok { return false } + e.onExit(c) + if !e.restart { <-e.terminate return false diff --git a/internal/externalcmd/cmd_unix.go b/internal/externalcmd/cmd_unix.go index 2178c6b8..54ee202e 100644 --- a/internal/externalcmd/cmd_unix.go +++ b/internal/externalcmd/cmd_unix.go @@ -9,7 +9,7 @@ import ( "syscall" ) -func (e *Cmd) runInner() bool { +func (e *Cmd) runInner() (int, bool) { cmd := exec.Command("/bin/sh", "-c", "exec "+e.cmdstr) cmd.Env = append([]string(nil), os.Environ()...) @@ -22,22 +22,31 @@ func (e *Cmd) runInner() bool { err := cmd.Start() if err != nil { - return true + return 0, true } - cmdDone := make(chan struct{}) + cmdDone := make(chan int) go func() { - defer close(cmdDone) - cmd.Wait() + cmdDone <- func() int { + err := cmd.Wait() + if err == nil { + return 0 + } + ee, ok := err.(*exec.ExitError) + if !ok { + return 0 + } + return ee.ExitCode() + }() }() select { case <-e.terminate: syscall.Kill(cmd.Process.Pid, syscall.SIGINT) <-cmdDone - return false + return 0, false - case <-cmdDone: - return true + case c := <-cmdDone: + return c, true } } diff --git a/internal/externalcmd/cmd_win.go b/internal/externalcmd/cmd_win.go index 73c7dfef..6513764d 100644 --- a/internal/externalcmd/cmd_win.go +++ b/internal/externalcmd/cmd_win.go @@ -11,7 +11,7 @@ import ( "github.com/kballard/go-shellquote" ) -func (e *Cmd) runInner() bool { +func (e *Cmd) runInner() (int, bool) { // On Windows, the shell is not used and command is started directly. // Variables are replaced manually in order to guarantee compatibility // with Linux commands. @@ -21,7 +21,7 @@ func (e *Cmd) runInner() bool { } parts, err := shellquote.Split(tmp) if err != nil { - return true + return 0, true } cmd := exec.Command(parts[0], parts[1:]...) @@ -36,13 +36,22 @@ func (e *Cmd) runInner() bool { err = cmd.Start() if err != nil { - return true + return 0, true } - cmdDone := make(chan struct{}) + cmdDone := make(chan int) go func() { - defer close(cmdDone) - cmd.Wait() + cmdDone <- func() int { + err := cmd.Wait() + if err == nil { + return 0 + } + ee, ok := err.(*exec.ExitError) + if !ok { + return 0 + } + return ee.ExitCode() + }() }() select { @@ -51,9 +60,9 @@ func (e *Cmd) runInner() bool { // Kill() is the only supported way. cmd.Process.Kill() <-cmdDone - return false + return 0, false - case <-cmdDone: - return true + case c := <-cmdDone: + return c, true } }