Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

110 lines
1.8 KiB

// Package externalcmd allows to launch external commands.
package externalcmd
import (
"errors"
"fmt"
"os"
"time"
)
const (
restartPause = 5 * time.Second
)
var errTerminated = errors.New("terminated")
// OnExitFunc is the prototype of onExit.
type OnExitFunc func(error)
// Environment is a Cmd environment.
type Environment map[string]string
// Cmd is an external command.
type Cmd struct {
pool *Pool
cmdstr string
restart bool
env Environment
onExit func(error)
// in
terminate chan struct{}
}
// NewCmd allocates a Cmd.
func NewCmd(
pool *Pool,
cmdstr string,
restart bool,
env Environment,
onExit OnExitFunc,
) *Cmd {
// replace variables in both Linux and Windows, in order to allow using the
// same commands on both of them.
cmdstr = os.Expand(cmdstr, func(variable string) string {
if value, ok := env[variable]; ok {
return value
}
return os.Getenv(variable)
})
if onExit == nil {
onExit = func(_ error) {}
}
e := &Cmd{
pool: pool,
cmdstr: cmdstr,
restart: restart,
env: env,
onExit: onExit,
terminate: make(chan struct{}),
}
pool.wg.Add(1)
go e.run()
return e
}
// Close closes the command. It doesn't wait for the command to exit.
func (e *Cmd) Close() {
close(e.terminate)
}
func (e *Cmd) run() {
defer e.pool.wg.Done()
env := append([]string(nil), os.Environ()...)
for key, val := range e.env {
env = append(env, key+"="+val)
}
for {
err := e.runOSSpecific(env)
if errors.Is(err, errTerminated) {
return
}
if !e.restart {
if err != nil {
e.onExit(err)
}
return
}
if err != nil {
e.onExit(err)
} else {
e.onExit(fmt.Errorf("command exited with code 0"))
}
select {
case <-time.After(restartPause):
case <-e.terminate:
return
}
}
}