Skip to content

Commit f8137e6

Browse files
hheimbuergerm1k1o
andauthored
Add support for running go-transcode on Windows (#41)
* build and run (VOD only) on Windows systems. Really the only platform-dependent bits of code were the process group management. I've replaced those with Windows-specific versions, although I haven't fully tested them, because I'm not entirely sure how they're used. Also, the build configuration for Linux and other non-Windows platforms is completely untested. * add Windows command group. * move to utils. --------- Co-authored-by: Miroslav Šedivý <[email protected]>
1 parent a4b556b commit f8137e6

File tree

7 files changed

+81
-13
lines changed

7 files changed

+81
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/go-transcode
44
/bin
55
/.env
6+
.vscode/

hls/manager.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/rs/zerolog/log"
1616

1717
"github.com/m1k1o/go-transcode/internal/utils"
18+
"github.com/m1k1o/go-transcode/internal/utils/cmdgroup"
1819
)
1920

2021
// how often should be cleanup called
@@ -92,8 +93,8 @@ func (m *ManagerCtx) Start() error {
9293
read, write := io.Pipe()
9394
m.cmd.Stdout = write
9495

95-
// create a new process group
96-
m.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
96+
// configure command to run in its own process group / job object
97+
cmdgroup.Configure(m.cmd)
9798

9899
m.active = false
99100
m.lastRequest = time.Now()
@@ -195,21 +196,15 @@ func (m *ManagerCtx) Start() error {
195196
return err
196197
}
197198

199+
// Stop terminates the running command and its children.
198200
func (m *ManagerCtx) Stop() {
199201
m.mu.Lock()
200202
defer m.mu.Unlock()
201203

202204
if m.cmd != nil && m.cmd.Process != nil {
203205
m.logger.Debug().Msg("performing stop")
204-
205-
pgid, err := syscall.Getpgid(m.cmd.Process.Pid)
206-
if err == nil {
207-
err := syscall.Kill(-pgid, syscall.SIGKILL)
208-
m.logger.Err(err).Msg("killing process group")
209-
} else {
210-
m.logger.Err(err).Msg("could not get process group id")
211-
err := m.cmd.Process.Kill()
212-
m.logger.Err(err).Msg("killing process")
206+
if err := cmdgroup.Kill(m.cmd); err != nil {
207+
m.logger.Err(err).Msg("failed to kill process group")
213208
}
214209
}
215210
}

internal/api/http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (a *ApiManagerCtx) Http(r chi.Router) {
2222
// dummy input for testing purposes
2323
file := a.config.AbsPath("profiles", "http-test.sh")
2424
cmd := exec.Command(file)
25-
logger.Info().Msg("command startred")
25+
logger.Info().Msg("command started")
2626

2727
read, write := io.Pipe()
2828
cmd.Stdout = write

internal/api/router.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,6 @@ func (a *ApiManagerCtx) transcodeStart(profilePath string, input string) (*exec.
9090
return nil, fmt.Errorf("stream not found")
9191
}
9292

93-
log.Info().Str("profilePath", profilePath).Str("url", url).Msg("command startred")
93+
log.Info().Str("profilePath", profilePath).Str("url", url).Msg("command started")
9494
return exec.Command(profilePath, url), nil
9595
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package cmdgroup
2+
3+
import "os/exec"
4+
5+
// Configure applies platform-specific settings so the command starts in its own
6+
// process-group / job-object. Call this before cmd.Start().
7+
func Configure(cmd *exec.Cmd) {
8+
platformConfigure(cmd)
9+
}
10+
11+
// Kill terminates the command together with all of its children.
12+
// It is safe to call this even if the command has already exited.
13+
func Kill(cmd *exec.Cmd) error {
14+
return platformKill(cmd)
15+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package cmdgroup
5+
6+
import (
7+
"os/exec"
8+
"syscall"
9+
10+
"github.com/rs/zerolog/log"
11+
)
12+
13+
func platformConfigure(cmd *exec.Cmd) {
14+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
15+
}
16+
17+
func platformKill(cmd *exec.Cmd) error {
18+
if cmd == nil || cmd.Process == nil {
19+
return nil
20+
}
21+
22+
pgid, err := syscall.Getpgid(cmd.Process.Pid)
23+
if err != nil {
24+
// could not obtain pgid, log and fallback to direct kill
25+
log.Err(err).Msg("could not get process group id")
26+
return cmd.Process.Kill()
27+
}
28+
29+
return syscall.Kill(-pgid, syscall.SIGKILL)
30+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package cmdgroup
5+
6+
import (
7+
"os"
8+
"os/exec"
9+
"strconv"
10+
"syscall"
11+
)
12+
13+
func platformConfigure(cmd *exec.Cmd) {
14+
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP}
15+
}
16+
17+
func platformKill(cmd *exec.Cmd) error {
18+
if cmd == nil || cmd.Process == nil {
19+
return nil
20+
}
21+
22+
// TASKKILL /T /PID <pid>
23+
kill := exec.Command("TASKKILL", "/T", "/PID", strconv.Itoa(cmd.Process.Pid))
24+
kill.Stdout = os.Stdout
25+
kill.Stderr = os.Stderr
26+
return kill.Run()
27+
}

0 commit comments

Comments
 (0)