golanggohlsrtmpwebrtcmedia-serverobs-studiortcprtmp-proxyrtmp-serverrtprtsprtsp-proxyrtsp-relayrtsp-serversrtstreamingwebrtc-proxy
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
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 |
|
} |
|
} |
|
}
|
|
|