Browse Source

handle external commands with a dedicated struct

pull/101/head
aler9 5 years ago
parent
commit
3b79f6beb4
  1. 17
      client.go
  2. 49
      externalcmd.go
  3. 15
      path.go
  4. 32
      utils.go

17
client.go

@ -5,8 +5,6 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"os"
"os/exec"
"strconv" "strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
@ -192,7 +190,7 @@ var errRunPlay = errors.New("play")
var errRunRecord = errors.New("record") var errRunRecord = errors.New("record")
func (c *client) run() { func (c *client) run() {
var onConnectCmd *exec.Cmd var onConnectCmd *externalCmd
if c.p.conf.RunOnConnect != "" { if c.p.conf.RunOnConnect != "" {
var err error var err error
onConnectCmd, err = startExternalCommand(c.p.conf.RunOnConnect, "") onConnectCmd, err = startExternalCommand(c.p.conf.RunOnConnect, "")
@ -208,8 +206,7 @@ func (c *client) run() {
} }
if onConnectCmd != nil { if onConnectCmd != nil {
onConnectCmd.Process.Signal(os.Interrupt) onConnectCmd.close()
onConnectCmd.Wait()
} }
close(c.describe) close(c.describe)
@ -886,7 +883,7 @@ func (c *client) runPlay() bool {
return "tracks" return "tracks"
}(), c.streamProtocol) }(), c.streamProtocol)
var onReadCmd *exec.Cmd var onReadCmd *externalCmd
if c.path.conf.RunOnRead != "" { if c.path.conf.RunOnRead != "" {
var err error var err error
onReadCmd, err = startExternalCommand(c.path.conf.RunOnRead, c.path.name) onReadCmd, err = startExternalCommand(c.path.conf.RunOnRead, c.path.name)
@ -902,8 +899,7 @@ func (c *client) runPlay() bool {
} }
if onReadCmd != nil { if onReadCmd != nil {
onReadCmd.Process.Signal(os.Interrupt) onReadCmd.close()
onReadCmd.Wait()
} }
return false return false
@ -1037,7 +1033,7 @@ func (c *client) runRecord() bool {
return "tracks" return "tracks"
}(), c.streamProtocol) }(), c.streamProtocol)
var onPublishCmd *exec.Cmd var onPublishCmd *externalCmd
if c.path.conf.RunOnPublish != "" { if c.path.conf.RunOnPublish != "" {
var err error var err error
onPublishCmd, err = startExternalCommand(c.path.conf.RunOnPublish, c.path.name) onPublishCmd, err = startExternalCommand(c.path.conf.RunOnPublish, c.path.name)
@ -1053,8 +1049,7 @@ func (c *client) runRecord() bool {
} }
if onPublishCmd != nil { if onPublishCmd != nil {
onPublishCmd.Process.Signal(os.Interrupt) onPublishCmd.close()
onPublishCmd.Wait()
} }
return false return false

49
externalcmd.go

@ -0,0 +1,49 @@
package main
import (
"os"
"os/exec"
"runtime"
"strings"
)
type externalCmd struct {
cmd *exec.Cmd
}
func startExternalCommand(cmdstr string, pathName string) (*externalCmd, error) {
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
// in Windows the shell is not used and command is started directly
// variables are replaced manually in order to allow
// compatibility with linux commands
cmdstr = strings.ReplaceAll(cmdstr, "$RTSP_SERVER_PATH", pathName)
args := strings.Fields(cmdstr)
cmd = exec.Command(args[0], args[1:]...)
} else {
cmd = exec.Command("/bin/sh", "-c", "exec "+cmdstr)
}
// variables are available through environment variables
cmd.Env = append(os.Environ(),
"RTSP_SERVER_PATH="+pathName,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
return nil, err
}
return &externalCmd{
cmd: cmd,
}, nil
}
func (e *externalCmd) close() {
e.cmd.Process.Signal(os.Interrupt)
e.cmd.Wait()
}

15
path.go

@ -2,8 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"os"
"os/exec"
"time" "time"
) )
@ -29,8 +27,8 @@ type path struct {
publisherSdp []byte publisherSdp []byte
lastDescribeReq time.Time lastDescribeReq time.Time
lastDescribeActivation time.Time lastDescribeActivation time.Time
onInitCmd *exec.Cmd onInitCmd *externalCmd
onDemandCmd *exec.Cmd onDemandCmd *externalCmd
} }
func newPath(p *program, name string, conf *pathConf) *path { func newPath(p *program, name string, conf *pathConf) *path {
@ -77,14 +75,12 @@ func (pa *path) onClose(wait bool) {
if pa.onInitCmd != nil { if pa.onInitCmd != nil {
pa.log("stopping on init command (closing)") pa.log("stopping on init command (closing)")
pa.onInitCmd.Process.Signal(os.Interrupt) pa.onInitCmd.close()
pa.onInitCmd.Wait()
} }
if pa.onDemandCmd != nil { if pa.onDemandCmd != nil {
pa.log("stopping on demand command (closing)") pa.log("stopping on demand command (closing)")
pa.onDemandCmd.Process.Signal(os.Interrupt) pa.onDemandCmd.close()
pa.onDemandCmd.Wait()
} }
for c := range pa.p.clients { for c := range pa.p.clients {
@ -161,8 +157,7 @@ func (pa *path) onCheck() {
!pa.hasClientReaders() && !pa.hasClientReaders() &&
time.Since(pa.lastDescribeReq) >= onDemandCmdStopAfterDescribeSecs { time.Since(pa.lastDescribeReq) >= onDemandCmdStopAfterDescribeSecs {
pa.log("stopping on demand command (not requested anymore)") pa.log("stopping on demand command (not requested anymore)")
pa.onDemandCmd.Process.Signal(os.Interrupt) pa.onDemandCmd.close()
pa.onDemandCmd.Wait()
pa.onDemandCmd = nil pa.onDemandCmd = nil
} }

32
utils.go

@ -4,9 +4,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"os/exec"
"regexp" "regexp"
"runtime"
"strings" "strings"
"sync" "sync"
@ -137,36 +135,6 @@ func checkPathName(name string) error {
return nil return nil
} }
func startExternalCommand(cmdstr string, pathName string) (*exec.Cmd, error) {
var cmd *exec.Cmd
if runtime.GOOS == "windows" {
// in Windows the shell is not used and command is started directly
// variables are replaced manually in order to allow
// compatibility with linux commands
cmdstr = strings.ReplaceAll(cmdstr, "$RTSP_SERVER_PATH", pathName)
args := strings.Fields(cmdstr)
cmd = exec.Command(args[0], args[1:]...)
} else {
cmd = exec.Command("/bin/sh", "-c", "exec "+cmdstr)
}
// variables are available through environment variables
cmd.Env = append(os.Environ(),
"RTSP_SERVER_PATH="+pathName,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
return nil, err
}
return cmd, nil
}
func isBindError(err error) bool { func isBindError(err error) bool {
if nerr, ok := err.(*net.OpError); ok { if nerr, ok := err.(*net.OpError); ok {
if serr, ok := nerr.Err.(*os.SyscallError); ok { if serr, ok := nerr.Err.(*os.SyscallError); ok {

Loading…
Cancel
Save