8
8
"io"
9
9
"net"
10
10
"os"
11
+ "os/exec"
11
12
"sync"
12
13
"time"
13
14
@@ -41,6 +42,11 @@ var ongoingRequests = make(map[int32]chan *CtrlResponse)
41
42
42
43
var lock = & sync.Mutex {}
43
44
45
+ var (
46
+ nativeCmd * exec.Cmd
47
+ nativeCmdLock = & sync.Mutex {}
48
+ )
49
+
44
50
func CallCtrlAction (action string , params map [string ]interface {}) (* CtrlResponse , error ) {
45
51
lock .Lock ()
46
52
defer lock .Unlock ()
@@ -129,16 +135,26 @@ func StartNativeSocketServer(socketPath string, handleClient func(net.Conn), isC
129
135
scopedLogger .Info ().Msg ("server listening" )
130
136
131
137
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 )
140
157
}
141
- handleClient (conn )
142
158
}()
143
159
144
160
return listener
@@ -235,6 +251,51 @@ func handleVideoClient(conn net.Conn) {
235
251
}
236
252
}
237
253
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
+
238
299
func ExtractAndRunNativeBin () error {
239
300
binaryPath := "/userdata/jetkvm/bin/jetkvm_native"
240
301
if err := ensureBinaryUpdated (binaryPath ); err != nil {
@@ -246,12 +307,28 @@ func ExtractAndRunNativeBin() error {
246
307
return fmt .Errorf ("failed to make binary executable: %w" , err )
247
308
}
248
309
// Run the binary in the background
249
- cmd , err := startNativeBinary (binaryPath )
310
+ cmd , err := startNativeBinaryWithLock (binaryPath )
250
311
if err != nil {
251
312
return fmt .Errorf ("failed to start binary: %w" , err )
252
313
}
253
314
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
+
255
332
go func () {
256
333
<- appCtx .Done ()
257
334
nativeLogger .Info ().Int ("pid" , cmd .Process .Pid ).Msg ("killing process" )
0 commit comments