kvm/internal/native/server.go

91 lines
2.5 KiB
Go

package native
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/caarlos0/env/v11"
"github.com/erikdubbelboer/gspt"
"github.com/rs/zerolog"
)
// Native Process
// stdout - exchange messages with the parent process
// stderr - logging and error messages
// RunNativeProcess runs the native process mode
func RunNativeProcess(binaryName string) {
// Initialize logger
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
gspt.SetProcTitle(binaryName + " [native]")
// Determine socket path
socketPath := os.Getenv("JETKVM_NATIVE_SOCKET")
videoStreamSocketPath := os.Getenv("JETKVM_VIDEO_STREAM_SOCKET")
if socketPath == "" || videoStreamSocketPath == "" {
logger.Fatal().Str("socket_path", socketPath).Str("video_stream_socket_path", videoStreamSocketPath).Msg("socket path or video stream socket path is not set")
}
// connect to video stream socket
conn, err := net.Dial("unixpacket", videoStreamSocketPath)
if err != nil {
logger.Fatal().Err(err).Msg("failed to connect to video stream socket")
}
logger.Info().Str("video_stream_socket_path", videoStreamSocketPath).Msg("connected to video stream socket")
var nativeOptions NativeOptions
if err := env.Parse(&nativeOptions); err != nil {
logger.Fatal().Err(err).Msg("failed to parse native options")
}
nativeOptions.OnVideoFrameReceived = func(frame []byte, duration time.Duration) {
_, err := conn.Write(frame)
if err != nil {
logger.Fatal().Err(err).Msg("failed to write frame to video stream socket")
}
}
// Create native instance
nativeInstance := NewNative(nativeOptions)
// Start native instance
if err := nativeInstance.Start(); err != nil {
logger.Fatal().Err(err).Msg("failed to start native instance")
}
// Create gRPC server
grpcServer := NewGRPCServer(nativeInstance, &logger)
logger.Info().Msg("starting gRPC server")
// Start gRPC server
server, lis, err := StartGRPCServer(grpcServer, fmt.Sprintf("@%v", socketPath), &logger)
if err != nil {
logger.Fatal().Err(err).Msg("failed to start gRPC server")
}
gspt.SetProcTitle(binaryName + " [native] ready")
// Signal that we're ready by writing socket path to stdout (for parent to read)
fmt.Fprintf(os.Stdout, "%s\n", socketPath)
defer os.Stdout.Close()
// Set up signal handling
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
// Wait for signal
<-sigChan
logger.Info().Msg("received termination signal")
// Graceful shutdown
server.GracefulStop()
lis.Close()
logger.Info().Msg("native process exiting")
}