mediamtx/internal/externalcmd/cmd.go

89 lines
1.3 KiB
Go
Raw Normal View History

2022-09-17 19:19:45 +00:00
// Package externalcmd allows to launch external commands.
package externalcmd
import (
"errors"
"strings"
"time"
)
const (
restartPause = 5 * time.Second
)
var errTerminated = errors.New("terminated")
2020-11-21 12:35:33 +00:00
// Environment is a Cmd environment.
type Environment map[string]string
2020-11-01 16:33:06 +00:00
2020-11-21 12:35:33 +00:00
// Cmd is an external command.
type Cmd struct {
pool *Pool
2020-11-01 16:33:06 +00:00
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 func(error),
) *Cmd {
// replace variables in both Linux and Windows, in order to allow using the
// same commands on both of them.
for key, val := range env {
cmdstr = strings.ReplaceAll(cmdstr, "$"+key, val)
}
2020-11-21 12:35:33 +00:00
e := &Cmd{
pool: pool,
cmdstr: cmdstr,
restart: restart,
2020-11-01 16:33:06 +00:00
env: env,
onExit: onExit,
terminate: make(chan struct{}),
}
pool.wg.Add(1)
go e.run()
2021-08-01 14:58:46 +00:00
return e
}
// Close closes the command. It doesn't wait for the command to exit.
2020-11-21 12:35:33 +00:00
func (e *Cmd) Close() {
close(e.terminate)
}
2020-11-21 12:35:33 +00:00
func (e *Cmd) run() {
defer e.pool.wg.Done()
for {
err := e.runOSSpecific()
if err == errTerminated {
return
2020-10-31 16:03:03 +00:00
}
e.onExit(err)
if !e.restart {
<-e.terminate
return
}
select {
case <-time.After(restartPause):
case <-e.terminate:
return
}
}
}