Skip to content

Commit 50049a2

Browse files
authored
Merge pull request #15 from m1k1o/hls-exit-on-error
HLS: add error to OnStop.
2 parents 133e266 + 903b44c commit 50049a2

File tree

2 files changed

+52
-26
lines changed

2 files changed

+52
-26
lines changed

hls/manager.go

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
// how often should be cleanup called
2121
const cleanupPeriod = 4 * time.Second
2222

23-
// timeot for first playlist, when it waits for new data
23+
// timeout for first playlist, when it waits for new data
2424
const playlistTimeout = 60 * time.Second
2525

2626
// minimum segments available to consider stream as active
@@ -40,7 +40,7 @@ type ManagerCtx struct {
4040
events struct {
4141
onStart func()
4242
onCmdLog func(message string)
43-
onStop func()
43+
onStop func(err error)
4444
}
4545

4646
cmd *exec.Cmd
@@ -92,7 +92,7 @@ func (m *ManagerCtx) Start() error {
9292
read, write := io.Pipe()
9393
m.cmd.Stdout = write
9494

95-
//create a new process group
95+
// create a new process group
9696
m.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
9797

9898
m.active = false
@@ -104,6 +104,7 @@ func (m *ManagerCtx) Start() error {
104104
m.playlistLoad = make(chan string)
105105
m.shutdown = make(chan interface{})
106106

107+
// read playlist on stdout
107108
go func() {
108109
buf := make([]byte, 1024)
109110

@@ -125,14 +126,15 @@ func (m *ManagerCtx) Start() error {
125126
}
126127
}
127128

129+
// if stdout pipe has been closed
128130
if err != nil {
129-
// When command fails to start, we reach this branch after a while
130131
m.logger.Err(err).Msg("cmd read failed")
131132
return
132133
}
133134
}
134135
}()
135136

137+
// periodic cleanup
136138
go func() {
137139
ticker := time.NewTicker(cleanupPeriod)
138140
defer ticker.Stop()
@@ -152,21 +154,54 @@ func (m *ManagerCtx) Start() error {
152154
m.events.onStart()
153155
}
154156

155-
return m.cmd.Start()
157+
// start program
158+
err = m.cmd.Start()
159+
160+
// wait for program to exit
161+
go func() {
162+
err = m.cmd.Wait()
163+
if err != nil {
164+
if exiterr, ok := err.(*exec.ExitError); ok {
165+
// The program has exited with an exit code != 0
166+
167+
// This works on both Unix and Windows. Although package
168+
// syscall is generally platform dependent, WaitStatus is
169+
// defined for both Unix and Windows and in both cases has
170+
// an ExitStatus() method with the same signature.
171+
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
172+
m.logger.Warn().Int("exit-status", status.ExitStatus()).Msg("the program has exited with an exit code != 0")
173+
}
174+
} else {
175+
m.logger.Err(err).Msg("the program has exited with an error")
176+
}
177+
} else {
178+
m.logger.Info().Msg("the program has successfully exited")
179+
}
180+
181+
close(m.shutdown)
182+
183+
if m.events.onStop != nil {
184+
m.events.onStop(err)
185+
}
186+
187+
err := os.RemoveAll(m.tempdir)
188+
m.logger.Err(err).Msg("removing tempdir")
189+
190+
m.mu.Lock()
191+
m.cmd = nil
192+
m.mu.Unlock()
193+
}()
194+
195+
return err
156196
}
157197

158198
func (m *ManagerCtx) Stop() {
159199
m.mu.Lock()
160200
defer m.mu.Unlock()
161201

162-
if m.cmd == nil {
163-
return
164-
}
165-
166-
m.logger.Debug().Msg("performing stop")
167-
close(m.shutdown)
202+
if m.cmd != nil && m.cmd.Process != nil {
203+
m.logger.Debug().Msg("performing stop")
168204

169-
if m.cmd.Process != nil {
170205
pgid, err := syscall.Getpgid(m.cmd.Process.Pid)
171206
if err == nil {
172207
err := syscall.Kill(-pgid, syscall.SIGKILL)
@@ -176,15 +211,6 @@ func (m *ManagerCtx) Stop() {
176211
err := m.cmd.Process.Kill()
177212
m.logger.Err(err).Msg("killing proccess")
178213
}
179-
_ = m.cmd.Wait()
180-
m.cmd = nil
181-
}
182-
183-
err := os.RemoveAll(m.tempdir)
184-
m.logger.Err(err).Msg("removing tempdir")
185-
186-
if m.events.onStop != nil {
187-
m.events.onStop()
188214
}
189215
}
190216

@@ -225,14 +251,14 @@ func (m *ManagerCtx) ServePlaylist(w http.ResponseWriter, r *http.Request) {
225251
if !m.active {
226252
select {
227253
case playlist = <-m.playlistLoad:
254+
// when command exits before providing any playlist
228255
case <-m.shutdown:
229256
m.logger.Warn().Msg("playlist load failed because of shutdown")
230-
// When command failed to start and timeout has been increased we reach this branch after a while
231-
http.Error(w, "404 playlist not found", http.StatusNotFound)
257+
http.Error(w, "500 playlist not available", http.StatusInternalServerError)
232258
return
233259
case <-time.After(playlistTimeout):
234260
m.logger.Warn().Msg("playlist load channel timeouted")
235-
http.Error(w, "500 not available", http.StatusInternalServerError)
261+
http.Error(w, "504 playlist timeout", http.StatusGatewayTimeout)
236262
return
237263
}
238264
}
@@ -269,6 +295,6 @@ func (m *ManagerCtx) OnCmdLog(event func(message string)) {
269295
m.events.onCmdLog = event
270296
}
271297

272-
func (m *ManagerCtx) OnStop(event func()) {
298+
func (m *ManagerCtx) OnStop(event func(err error)) {
273299
m.events.onStop = event
274300
}

hls/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ type Manager interface {
1212

1313
OnStart(event func())
1414
OnCmdLog(event func(message string))
15-
OnStop(event func())
15+
OnStop(event func(err error))
1616
}

0 commit comments

Comments
 (0)