mirror of https://github.com/jetkvm/kvm.git
reconfigure display on native restart
This commit is contained in:
parent
91d3b47ec3
commit
afd8ab75bc
|
|
@ -232,6 +232,14 @@ func updateStaticContents() {
|
||||||
// nativeInstance.UpdateLabelAndChangeVisibility("boot_screen_device_id", GetDeviceID())
|
// nativeInstance.UpdateLabelAndChangeVisibility("boot_screen_device_id", GetDeviceID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configureDisplayOnNativeRestart is called when the native process restarts
|
||||||
|
// it ensures the display is configured correctly after the restart
|
||||||
|
func configureDisplayOnNativeRestart() {
|
||||||
|
displayLogger.Info().Msg("native restarted, configuring display")
|
||||||
|
updateStaticContents()
|
||||||
|
requestDisplayUpdate(true, "native_restart")
|
||||||
|
}
|
||||||
|
|
||||||
// setDisplayBrightness sets /sys/class/backlight/backlight/brightness to alter
|
// setDisplayBrightness sets /sys/class/backlight/backlight/brightness to alter
|
||||||
// the backlight brightness of the JetKVM hardware's display.
|
// the backlight brightness of the JetKVM hardware's display.
|
||||||
func setDisplayBrightness(brightness int, reason string) error {
|
func setDisplayBrightness(brightness int, reason string) error {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/erikdubbelboer/gspt"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|
@ -160,6 +159,9 @@ func (s *grpcServer) VideoLogStatus(ctx context.Context, req *pb.Empty) (*pb.Vid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
||||||
|
procPrefix = "jetkvm: [native]"
|
||||||
|
setProcTitle(lastProcTitle)
|
||||||
|
|
||||||
if err := s.native.VideoStop(); err != nil {
|
if err := s.native.VideoStop(); err != nil {
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -167,6 +169,9 @@ func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) VideoStart(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
func (s *grpcServer) VideoStart(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
||||||
|
procPrefix = "jetkvm: [native+video]"
|
||||||
|
setProcTitle(lastProcTitle)
|
||||||
|
|
||||||
if err := s.native.VideoStart(); err != nil {
|
if err := s.native.VideoStart(); err != nil {
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -315,7 +320,8 @@ func (s *grpcServer) DoNotUseThisIsForCrashTestingOnly(ctx context.Context, req
|
||||||
|
|
||||||
// StreamEvents streams events from the native process
|
// StreamEvents streams events from the native process
|
||||||
func (s *grpcServer) StreamEvents(req *pb.Empty, stream pb.NativeService_StreamEventsServer) error {
|
func (s *grpcServer) StreamEvents(req *pb.Empty, stream pb.NativeService_StreamEventsServer) error {
|
||||||
gspt.SetProcTitle("jetkvm: [native] connected")
|
setProcTitle("connected")
|
||||||
|
defer setProcTitle("waiting")
|
||||||
|
|
||||||
eventCh := make(chan *pb.Event, 100)
|
eventCh := make(chan *pb.Event, 100)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ type NativeOptions struct {
|
||||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||||
OnIndevEvent func(event string)
|
OnIndevEvent func(event string)
|
||||||
OnRpcEvent func(event string)
|
OnRpcEvent func(event string)
|
||||||
|
OnNativeRestart func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNative(opts NativeOptions) *Native {
|
func NewNative(opts NativeOptions) *Native {
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,13 @@ type nativeProxyOptions struct {
|
||||||
BinaryPath string `env:"JETKVM_NATIVE_BINARY_PATH"`
|
BinaryPath string `env:"JETKVM_NATIVE_BINARY_PATH"`
|
||||||
LoggerLevel zerolog.Level `env:"JETKVM_NATIVE_LOGGER_LEVEL"`
|
LoggerLevel zerolog.Level `env:"JETKVM_NATIVE_LOGGER_LEVEL"`
|
||||||
HandshakeMessage string `env:"JETKVM_NATIVE_HANDSHAKE_MESSAGE"`
|
HandshakeMessage string `env:"JETKVM_NATIVE_HANDSHAKE_MESSAGE"`
|
||||||
|
MaxRestartAttempts uint
|
||||||
|
|
||||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||||
OnIndevEvent func(event string)
|
OnIndevEvent func(event string)
|
||||||
OnRpcEvent func(event string)
|
OnRpcEvent func(event string)
|
||||||
OnVideoStateChange func(state VideoState)
|
OnVideoStateChange func(state VideoState)
|
||||||
|
OnNativeRestart func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomId(binaryLength int) string {
|
func randomId(binaryLength int) string {
|
||||||
|
|
@ -63,6 +65,7 @@ func (n *NativeOptions) toProxyOptions() *nativeProxyOptions {
|
||||||
OnIndevEvent: n.OnIndevEvent,
|
OnIndevEvent: n.OnIndevEvent,
|
||||||
OnRpcEvent: n.OnRpcEvent,
|
OnRpcEvent: n.OnRpcEvent,
|
||||||
OnVideoStateChange: n.OnVideoStateChange,
|
OnVideoStateChange: n.OnVideoStateChange,
|
||||||
|
OnNativeRestart: n.OnNativeRestart,
|
||||||
HandshakeMessage: handshakeMessage,
|
HandshakeMessage: handshakeMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +121,7 @@ type NativeProxy struct {
|
||||||
ready chan struct{}
|
ready chan struct{}
|
||||||
options *nativeProxyOptions
|
options *nativeProxyOptions
|
||||||
restartM sync.Mutex
|
restartM sync.Mutex
|
||||||
|
restarts uint
|
||||||
stopped bool
|
stopped bool
|
||||||
processWait chan error
|
processWait chan error
|
||||||
}
|
}
|
||||||
|
|
@ -142,10 +146,7 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) {
|
||||||
ready: make(chan struct{}),
|
ready: make(chan struct{}),
|
||||||
options: proxyOptions,
|
options: proxyOptions,
|
||||||
processWait: make(chan error, 1),
|
processWait: make(chan error, 1),
|
||||||
}
|
restarts: 0,
|
||||||
proxy.cmd, err = proxy.toProcessCommand()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create process: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return proxy, nil
|
return proxy, nil
|
||||||
|
|
@ -195,6 +196,7 @@ func (w *nativeProxyStdoutHandler) Write(p []byte) (n int, err error) {
|
||||||
if !w.handshakeDone && strings.Contains(string(p), w.handshakeMessage) {
|
if !w.handshakeDone && strings.Contains(string(p), w.handshakeMessage) {
|
||||||
w.handshakeDone = true
|
w.handshakeDone = true
|
||||||
w.handshakeCh <- true
|
w.handshakeCh <- true
|
||||||
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Stdout.Write(p)
|
os.Stdout.Write(p)
|
||||||
|
|
@ -287,6 +289,11 @@ func (p *NativeProxy) setUpGRPCClient() error {
|
||||||
return fmt.Errorf("failed to wait for ready: %w", err)
|
return fmt.Errorf("failed to wait for ready: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call on native restart callback if it exists and restarts are greater than 0
|
||||||
|
if p.options.OnNativeRestart != nil && p.restarts > 0 {
|
||||||
|
p.options.OnNativeRestart()
|
||||||
|
}
|
||||||
|
|
||||||
// Start monitoring process for crashes
|
// Start monitoring process for crashes
|
||||||
go p.monitorProcess()
|
go p.monitorProcess()
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -298,6 +305,13 @@ func (p *NativeProxy) start() error {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
cmd, err := p.toProcessCommand()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create process: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.cmd = cmd
|
||||||
|
|
||||||
if err := p.cmd.Start(); err != nil {
|
if err := p.cmd.Start(); err != nil {
|
||||||
return fmt.Errorf("failed to start native process: %w", err)
|
return fmt.Errorf("failed to start native process: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -390,6 +404,8 @@ func (p *NativeProxy) restartProcess() error {
|
||||||
_ = p.client.Close()
|
_ = p.client.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.restarts++
|
||||||
|
|
||||||
if err := p.start(); err != nil {
|
if err := p.start(); err != nil {
|
||||||
return fmt.Errorf("failed to start native process: %w", err)
|
return fmt.Errorf("failed to start native process: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,37 @@ import (
|
||||||
// stdout - exchange messages with the parent process
|
// stdout - exchange messages with the parent process
|
||||||
// stderr - logging and error messages
|
// stderr - logging and error messages
|
||||||
|
|
||||||
// RunNativeProcess runs the native process mode
|
var (
|
||||||
func RunNativeProcess(binaryName string) {
|
procPrefix string = "jetkvm: [native]"
|
||||||
logger := *nativeLogger
|
lastProcTitle string
|
||||||
// Initialize logger
|
)
|
||||||
|
|
||||||
gspt.SetProcTitle("jetkvm: [native] starting")
|
func setProcTitle(status string) {
|
||||||
|
lastProcTitle = status
|
||||||
var proxyOptions nativeProxyOptions
|
if status != "" {
|
||||||
if err := env.Parse(&proxyOptions); err != nil {
|
status = " " + status
|
||||||
logger.Fatal().Err(err).Msg("failed to parse native options")
|
}
|
||||||
|
title := fmt.Sprintf("%s%s", procPrefix, status)
|
||||||
|
gspt.SetProcTitle(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect to video stream socket
|
// RunNativeProcess runs the native process mode
|
||||||
|
func RunNativeProcess(binaryName string) {
|
||||||
|
logger := nativeLogger.With().Int("pid", os.Getpid()).Logger()
|
||||||
|
setProcTitle("starting")
|
||||||
|
|
||||||
|
// Parse native options
|
||||||
|
var proxyOptions nativeProxyOptions
|
||||||
|
if err := env.Parse(&proxyOptions); err != nil {
|
||||||
|
logger.Fatal().Err(err).Msg("failed to parse native proxy options")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to video stream socket
|
||||||
conn, err := net.Dial("unixpacket", proxyOptions.VideoStreamUnixSocket)
|
conn, err := net.Dial("unixpacket", proxyOptions.VideoStreamUnixSocket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal().Err(err).Msg("failed to connect to video stream socket")
|
logger.Fatal().Err(err).Msg("failed to connect to video stream socket")
|
||||||
}
|
}
|
||||||
logger.Info().Str("video_stream_socket_path", proxyOptions.VideoStreamUnixSocket).Msg("connected to video stream socket")
|
logger.Info().Str("videoStreamSocketPath", proxyOptions.VideoStreamUnixSocket).Msg("connected to video stream socket")
|
||||||
|
|
||||||
nativeOptions := proxyOptions.toNativeOptions()
|
nativeOptions := proxyOptions.toNativeOptions()
|
||||||
nativeOptions.OnVideoFrameReceived = func(frame []byte, duration time.Duration) {
|
nativeOptions.OnVideoFrameReceived = func(frame []byte, duration time.Duration) {
|
||||||
|
|
@ -52,9 +65,10 @@ func RunNativeProcess(binaryName string) {
|
||||||
logger.Fatal().Err(err).Msg("failed to start native instance")
|
logger.Fatal().Err(err).Msg("failed to start native instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
gspt.SetProcTitle("jetkvm: [native] starting gRPC server")
|
grpcLogger := logger.With().Str("socketPath", fmt.Sprintf("@%v", proxyOptions.CtrlUnixSocket)).Logger()
|
||||||
|
setProcTitle("starting gRPC server")
|
||||||
// Create gRPC server
|
// Create gRPC server
|
||||||
grpcServer := NewGRPCServer(nativeInstance, &logger)
|
grpcServer := NewGRPCServer(nativeInstance, &grpcLogger)
|
||||||
|
|
||||||
logger.Info().Msg("starting gRPC server")
|
logger.Info().Msg("starting gRPC server")
|
||||||
// Start gRPC server
|
// Start gRPC server
|
||||||
|
|
@ -62,7 +76,7 @@ func RunNativeProcess(binaryName string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal().Err(err).Msg("failed to start gRPC server")
|
logger.Fatal().Err(err).Msg("failed to start gRPC server")
|
||||||
}
|
}
|
||||||
gspt.SetProcTitle("jetkvm: [native] ready")
|
setProcTitle("ready")
|
||||||
|
|
||||||
// Signal that we're ready by writing handshake message to stdout (for parent to read)
|
// Signal that we're ready by writing handshake message to stdout (for parent to read)
|
||||||
// Stdout.Write is used to avoid buffering the message
|
// Stdout.Write is used to avoid buffering the message
|
||||||
|
|
@ -76,8 +90,10 @@ func RunNativeProcess(binaryName string) {
|
||||||
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
|
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
|
||||||
// Wait for signal
|
// Wait for signal
|
||||||
<-sigChan
|
sig := <-sigChan
|
||||||
logger.Info().Msg("received termination signal")
|
logger.Info().
|
||||||
|
Str("signal", sig.String()).
|
||||||
|
Msg("received termination signal")
|
||||||
|
|
||||||
// Graceful shutdown
|
// Graceful shutdown
|
||||||
server.GracefulStop()
|
server.GracefulStop()
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) {
|
||||||
AppVersion: appVersion,
|
AppVersion: appVersion,
|
||||||
DisplayRotation: config.GetDisplayRotation(),
|
DisplayRotation: config.GetDisplayRotation(),
|
||||||
DefaultQualityFactor: config.VideoQualityFactor,
|
DefaultQualityFactor: config.VideoQualityFactor,
|
||||||
|
OnNativeRestart: func() {
|
||||||
|
configureDisplayOnNativeRestart()
|
||||||
|
},
|
||||||
OnVideoStateChange: func(state native.VideoState) {
|
OnVideoStateChange: func(state native.VideoState) {
|
||||||
lastVideoState = state
|
lastVideoState = state
|
||||||
triggerVideoStateUpdate()
|
triggerVideoStateUpdate()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue