Skip to content

Commit 6f037a8

Browse files
authored
feat(native): restart jetkvm_native automatically (#629)
1 parent ccba27c commit 6f037a8

File tree

1 file changed

+88
-11
lines changed

1 file changed

+88
-11
lines changed

native.go

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"net"
1010
"os"
11+
"os/exec"
1112
"sync"
1213
"time"
1314

@@ -41,6 +42,11 @@ var ongoingRequests = make(map[int32]chan *CtrlResponse)
4142

4243
var lock = &sync.Mutex{}
4344

45+
var (
46+
nativeCmd *exec.Cmd
47+
nativeCmdLock = &sync.Mutex{}
48+
)
49+
4450
func CallCtrlAction(action string, params map[string]interface{}) (*CtrlResponse, error) {
4551
lock.Lock()
4652
defer lock.Unlock()
@@ -129,16 +135,26 @@ func StartNativeSocketServer(socketPath string, handleClient func(net.Conn), isC
129135
scopedLogger.Info().Msg("server listening")
130136

131137
go func() {
132-
conn, err := listener.Accept()
133-
listener.Close()
134-
if err != nil {
135-
scopedLogger.Warn().Err(err).Msg("failed to accept socket")
136-
}
137-
if isCtrl {
138-
close(ctrlClientConnected)
139-
scopedLogger.Debug().Msg("first native ctrl socket client connected")
138+
for {
139+
conn, err := listener.Accept()
140+
141+
if err != nil {
142+
scopedLogger.Warn().Err(err).Msg("failed to accept socket")
143+
continue
144+
}
145+
if isCtrl {
146+
// check if the channel is closed
147+
select {
148+
case <-ctrlClientConnected:
149+
scopedLogger.Debug().Msg("ctrl client reconnected")
150+
default:
151+
close(ctrlClientConnected)
152+
scopedLogger.Debug().Msg("first native ctrl socket client connected")
153+
}
154+
}
155+
156+
go handleClient(conn)
140157
}
141-
handleClient(conn)
142158
}()
143159

144160
return listener
@@ -235,6 +251,51 @@ func handleVideoClient(conn net.Conn) {
235251
}
236252
}
237253

254+
func startNativeBinaryWithLock(binaryPath string) (*exec.Cmd, error) {
255+
nativeCmdLock.Lock()
256+
defer nativeCmdLock.Unlock()
257+
258+
cmd, err := startNativeBinary(binaryPath)
259+
if err != nil {
260+
return nil, err
261+
}
262+
nativeCmd = cmd
263+
return cmd, nil
264+
}
265+
266+
func restartNativeBinary(binaryPath string) error {
267+
time.Sleep(10 * time.Second)
268+
// restart the binary
269+
nativeLogger.Info().Msg("restarting jetkvm_native binary")
270+
cmd, err := startNativeBinary(binaryPath)
271+
if err != nil {
272+
nativeLogger.Warn().Err(err).Msg("failed to restart binary")
273+
}
274+
nativeCmd = cmd
275+
return err
276+
}
277+
278+
func superviseNativeBinary(binaryPath string) error {
279+
nativeCmdLock.Lock()
280+
defer nativeCmdLock.Unlock()
281+
282+
if nativeCmd == nil || nativeCmd.Process == nil {
283+
return restartNativeBinary(binaryPath)
284+
}
285+
286+
err := nativeCmd.Wait()
287+
288+
if err == nil {
289+
nativeLogger.Info().Err(err).Msg("jetkvm_native binary exited with no error")
290+
} else if exiterr, ok := err.(*exec.ExitError); ok {
291+
nativeLogger.Warn().Int("exit_code", exiterr.ExitCode()).Msg("jetkvm_native binary exited with error")
292+
} else {
293+
nativeLogger.Warn().Err(err).Msg("jetkvm_native binary exited with unknown error")
294+
}
295+
296+
return restartNativeBinary(binaryPath)
297+
}
298+
238299
func ExtractAndRunNativeBin() error {
239300
binaryPath := "/userdata/jetkvm/bin/jetkvm_native"
240301
if err := ensureBinaryUpdated(binaryPath); err != nil {
@@ -246,12 +307,28 @@ func ExtractAndRunNativeBin() error {
246307
return fmt.Errorf("failed to make binary executable: %w", err)
247308
}
248309
// Run the binary in the background
249-
cmd, err := startNativeBinary(binaryPath)
310+
cmd, err := startNativeBinaryWithLock(binaryPath)
250311
if err != nil {
251312
return fmt.Errorf("failed to start binary: %w", err)
252313
}
253314

254-
//TODO: add auto restart
315+
// check if the binary is still running every 10 seconds
316+
go func() {
317+
for {
318+
select {
319+
case <-appCtx.Done():
320+
nativeLogger.Info().Msg("stopping native binary supervisor")
321+
return
322+
default:
323+
err := superviseNativeBinary(binaryPath)
324+
if err != nil {
325+
nativeLogger.Warn().Err(err).Msg("failed to supervise native binary")
326+
time.Sleep(1 * time.Second) // Add a short delay to prevent rapid successive calls
327+
}
328+
}
329+
}
330+
}()
331+
255332
go func() {
256333
<-appCtx.Done()
257334
nativeLogger.Info().Int("pid", cmd.Process.Pid).Msg("killing process")

0 commit comments

Comments
 (0)