mirror of https://github.com/jetkvm/kvm.git
dead simple dual build target POC
This commit is contained in:
parent
bca9afd1d7
commit
2f868bc36d
|
|
@ -42,6 +42,8 @@ FetchContent_MakeAvailable(lvgl)
|
|||
# Get source files, excluding CMake generated files
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.c" "ui/*.c")
|
||||
list(FILTER sources EXCLUDE REGEX "CMakeFiles.*CompilerId.*\\.c$")
|
||||
# Exclude main.c from library sources (it's used for the binary target)
|
||||
list(FILTER sources EXCLUDE REGEX "main\\.c$")
|
||||
|
||||
add_library(jknative STATIC ${sources} ${CMAKE_CURRENT_SOURCE_DIR}/ctrl.h)
|
||||
|
||||
|
|
@ -68,4 +70,14 @@ target_link_libraries(jknative PRIVATE
|
|||
# libgpiod
|
||||
)
|
||||
|
||||
install(TARGETS jknative DESTINATION lib)
|
||||
# Binary target using main.c as entry point
|
||||
add_executable(jknative-bin ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
|
||||
|
||||
# Link the binary to the library (if needed in the future)
|
||||
target_link_libraries(jknative-bin PRIVATE
|
||||
jknative
|
||||
pthread
|
||||
)
|
||||
|
||||
install(TARGETS jknative DESTINATION lib)
|
||||
install(TARGETS jknative-bin DESTINATION bin)
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/select.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include "ctrl.h"
|
||||
#include "main.h"
|
||||
|
||||
#define SOCKET_PATH "/tmp/video.sock"
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
// Global state
|
||||
static int client_fd = -1;
|
||||
static pthread_mutex_t client_fd_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void jetkvm_c_log_handler(int level, const char *filename, const char *funcname, int line, const char *message) {
|
||||
// printf("[%s] %s:%d %s: %s\n", filename ? filename : "unknown", funcname ? funcname : "unknown", line, message ? message : "");
|
||||
fprintf(stderr, "[%s] %s:%d %s: %s\n", filename ? filename : "unknown", funcname ? funcname : "unknown", line, message ? message : "");
|
||||
}
|
||||
|
||||
// Video handler that pipes frames to the Unix socket
|
||||
// This will be called by the video subsystem via video_send_frame -> jetkvm_set_video_handler's handler
|
||||
void jetkvm_video_handler(const uint8_t *frame, ssize_t len) {
|
||||
// pthread_mutex_lock(&client_fd_mutex);
|
||||
// if (client_fd >= 0 && frame != NULL && len > 0) {
|
||||
// ssize_t bytes_written = 0;
|
||||
// while (bytes_written < len) {
|
||||
// ssize_t n = write(client_fd, frame + bytes_written, len - bytes_written);
|
||||
// if (n < 0) {
|
||||
// if (errno == EPIPE || errno == ECONNRESET) {
|
||||
// // Client disconnected
|
||||
// close(client_fd);
|
||||
// client_fd = -1;
|
||||
// break;
|
||||
// }
|
||||
// perror("write");
|
||||
// break;
|
||||
// }
|
||||
// bytes_written += n;
|
||||
// }
|
||||
// }
|
||||
// pthread_mutex_unlock(&client_fd_mutex);
|
||||
}
|
||||
|
||||
void jetkvm_video_state_handler(jetkvm_video_state_t *state) {
|
||||
fprintf(stderr, "Video state: {\n"
|
||||
"\"ready\": %d,\n"
|
||||
"\"error\": \"%s\",\n"
|
||||
"\"width\": %d,\n"
|
||||
"\"height\": %d,\n"
|
||||
"\"frame_per_second\": %f\n"
|
||||
"}\n", state->ready, state->error, state->width, state->height, state->frame_per_second);
|
||||
}
|
||||
|
||||
void jetkvm_indev_handler(int code) {
|
||||
fprintf(stderr, "Video indev: %d\n", code);
|
||||
}
|
||||
|
||||
void jetkvm_rpc_handler(const char *method, const char *params) {
|
||||
fprintf(stderr, "Video rpc: %s %s\n", method, params);
|
||||
}
|
||||
|
||||
// Note: jetkvm_set_video_handler, jetkvm_set_indev_handler, jetkvm_set_rpc_handler,
|
||||
// jetkvm_call_rpc_handler, and jetkvm_set_video_state_handler are implemented in
|
||||
// the library (ctrl.c) and will be used from there when linking.
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *socket_path = SOCKET_PATH;
|
||||
|
||||
// Allow custom socket path via command line argument
|
||||
if (argc > 1) {
|
||||
socket_path = argv[1];
|
||||
}
|
||||
|
||||
// Remove existing socket file if it exists
|
||||
unlink(socket_path);
|
||||
|
||||
// Set handlers
|
||||
jetkvm_set_log_handler(&jetkvm_c_log_handler);
|
||||
jetkvm_set_video_handler(&jetkvm_video_handler);
|
||||
jetkvm_set_video_state_handler(&jetkvm_video_state_handler);
|
||||
jetkvm_set_indev_handler(&jetkvm_indev_handler);
|
||||
jetkvm_set_rpc_handler(&jetkvm_rpc_handler);
|
||||
|
||||
// Initialize video first (before accepting connections)
|
||||
fprintf(stderr, "Initializing video...\n");
|
||||
if (jetkvm_video_init(1.0) != 0) {
|
||||
fprintf(stderr, "Failed to initialize video\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Start video streaming - frames will be sent via video_send_frame
|
||||
// which calls the video handler we set up
|
||||
jetkvm_video_start();
|
||||
fprintf(stderr, "Video streaming started.\n");
|
||||
|
||||
// Create Unix domain socket
|
||||
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (server_fd < 0) {
|
||||
perror("socket");
|
||||
jetkvm_video_stop();
|
||||
jetkvm_video_shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make socket non-blocking
|
||||
int flags = fcntl(server_fd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(server_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
perror("fcntl");
|
||||
close(server_fd);
|
||||
jetkvm_video_stop();
|
||||
jetkvm_video_shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Bind socket to path
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||
|
||||
if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(server_fd);
|
||||
jetkvm_video_stop();
|
||||
jetkvm_video_shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Listen for connections
|
||||
if (listen(server_fd, 1) < 0) {
|
||||
perror("listen");
|
||||
close(server_fd);
|
||||
jetkvm_video_stop();
|
||||
jetkvm_video_shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Listening on Unix socket: %s (non-blocking)\n", socket_path);
|
||||
fprintf(stderr, "Video frames will be sent to connected clients...\n");
|
||||
|
||||
// Main loop: check for new connections and handle client disconnections
|
||||
fd_set read_fds;
|
||||
struct timeval timeout;
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(server_fd, &read_fds);
|
||||
|
||||
pthread_mutex_lock(&client_fd_mutex);
|
||||
int current_client_fd = client_fd;
|
||||
if (current_client_fd >= 0) {
|
||||
FD_SET(current_client_fd, &read_fds);
|
||||
}
|
||||
int max_fd = (current_client_fd > server_fd) ? current_client_fd : server_fd;
|
||||
pthread_mutex_unlock(&client_fd_mutex);
|
||||
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
int result = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (result < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for new connection
|
||||
if (FD_ISSET(server_fd, &read_fds)) {
|
||||
int accepted_fd = accept(server_fd, NULL, NULL);
|
||||
if (accepted_fd >= 0) {
|
||||
fprintf(stderr, "Client connected\n");
|
||||
pthread_mutex_lock(&client_fd_mutex);
|
||||
if (client_fd >= 0) {
|
||||
// Close previous client if any
|
||||
close(client_fd);
|
||||
}
|
||||
client_fd = accepted_fd;
|
||||
pthread_mutex_unlock(&client_fd_mutex);
|
||||
} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
perror("accept");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if client disconnected
|
||||
pthread_mutex_lock(&client_fd_mutex);
|
||||
current_client_fd = client_fd;
|
||||
pthread_mutex_unlock(&client_fd_mutex);
|
||||
|
||||
if (current_client_fd >= 0 && FD_ISSET(current_client_fd, &read_fds)) {
|
||||
// Client sent data or closed connection
|
||||
char buffer[1];
|
||||
if (read(current_client_fd, buffer, 1) <= 0) {
|
||||
fprintf(stderr, "Client disconnected\n");
|
||||
pthread_mutex_lock(&client_fd_mutex);
|
||||
close(client_fd);
|
||||
client_fd = -1;
|
||||
pthread_mutex_unlock(&client_fd_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop video streaming
|
||||
jetkvm_video_stop();
|
||||
jetkvm_video_shutdown();
|
||||
|
||||
// Cleanup
|
||||
pthread_mutex_lock(&client_fd_mutex);
|
||||
if (client_fd >= 0) {
|
||||
close(client_fd);
|
||||
client_fd = -1;
|
||||
}
|
||||
pthread_mutex_unlock(&client_fd_mutex);
|
||||
|
||||
close(server_fd);
|
||||
unlink(socket_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef JETKVM_NATIVE_MAIN_H
|
||||
#define JETKVM_NATIVE_MAIN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include "ctrl.h"
|
||||
|
||||
void jetkvm_c_log_handler(int level, const char *filename, const char *funcname, int line, const char *message);
|
||||
void jetkvm_video_handler(const uint8_t *frame, ssize_t len);
|
||||
void jetkvm_video_state_handler(jetkvm_video_state_t *state);
|
||||
void jetkvm_indev_handler(int code);
|
||||
void jetkvm_rpc_handler(const char *method, const char *params);
|
||||
|
||||
|
||||
// typedef void (jetkvm_video_state_handler_t)(jetkvm_video_state_t *state);
|
||||
// typedef void (jetkvm_log_handler_t)(int level, const char *filename, const char *funcname, int line, const char *message);
|
||||
// typedef void (jetkvm_rpc_handler_t)(const char *method, const char *params);
|
||||
// typedef void (jetkvm_video_handler_t)(const uint8_t *frame, ssize_t len);
|
||||
// typedef void (jetkvm_indev_handler_t)(int code);
|
||||
|
||||
#endif
|
||||
|
|
@ -28,11 +28,11 @@ type Native struct {
|
|||
}
|
||||
|
||||
type NativeOptions struct {
|
||||
Disable bool `env:"JETKVM_NATIVE_DISABLE"`
|
||||
SystemVersion *semver.Version `env:"JETKVM_NATIVE_SYSTEM_VERSION"`
|
||||
AppVersion *semver.Version `env:"JETKVM_NATIVE_APP_VERSION"`
|
||||
DisplayRotation uint16 `env:"JETKVM_NATIVE_DISPLAY_ROTATION"`
|
||||
DefaultQualityFactor float64 `env:"JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR"`
|
||||
Disable bool
|
||||
SystemVersion *semver.Version
|
||||
AppVersion *semver.Version
|
||||
DisplayRotation uint16
|
||||
DefaultQualityFactor float64
|
||||
OnVideoStateChange func(state VideoState)
|
||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
OnIndevEvent func(event string)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/jetkvm/kvm/internal/supervisor"
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/jetkvm/kvm/internal/utils"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
|
|
@ -17,6 +18,48 @@ const (
|
|||
maxFrameSize = 1920 * 1080 / 2
|
||||
)
|
||||
|
||||
type nativeProxyOptions struct {
|
||||
Disable bool `env:"JETKVM_NATIVE_DISABLE"`
|
||||
SystemVersion *semver.Version `env:"JETKVM_NATIVE_SYSTEM_VERSION"`
|
||||
AppVersion *semver.Version `env:"JETKVM_NATIVE_APP_VERSION"`
|
||||
DisplayRotation uint16 `env:"JETKVM_NATIVE_DISPLAY_ROTATION"`
|
||||
DefaultQualityFactor float64 `env:"JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR"`
|
||||
CtrlUnixSocket string `env:"JETKVM_NATIVE_CTRL_UNIX_SOCKET"`
|
||||
VideoStreamUnixSocket string `env:"JETKVM_NATIVE_VIDEO_STREAM_UNIX_SOCKET"`
|
||||
BinaryPath string `env:"JETKVM_NATIVE_BINARY_PATH"`
|
||||
LoggerLevel zerolog.Level `env:"JETKVM_NATIVE_LOGGER_LEVEL"`
|
||||
HandshakeMessage string `env:"JETKVM_NATIVE_HANDSHAKE_MESSAGE"`
|
||||
|
||||
OnVideoFrameReceived func(frame []byte, duration time.Duration)
|
||||
OnIndevEvent func(event string)
|
||||
OnRpcEvent func(event string)
|
||||
OnVideoStateChange func(state VideoState)
|
||||
}
|
||||
|
||||
func (n *NativeOptions) toProxyOptions() *nativeProxyOptions {
|
||||
return &nativeProxyOptions{
|
||||
Disable: n.Disable,
|
||||
SystemVersion: n.SystemVersion,
|
||||
AppVersion: n.AppVersion,
|
||||
DisplayRotation: n.DisplayRotation,
|
||||
DefaultQualityFactor: n.DefaultQualityFactor,
|
||||
OnVideoFrameReceived: n.OnVideoFrameReceived,
|
||||
OnIndevEvent: n.OnIndevEvent,
|
||||
OnRpcEvent: n.OnRpcEvent,
|
||||
OnVideoStateChange: n.OnVideoStateChange,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *nativeProxyOptions) toNativeOptions() *NativeOptions {
|
||||
return &NativeOptions{
|
||||
Disable: p.Disable,
|
||||
SystemVersion: p.SystemVersion,
|
||||
AppVersion: p.AppVersion,
|
||||
DisplayRotation: p.DisplayRotation,
|
||||
DefaultQualityFactor: p.DefaultQualityFactor,
|
||||
}
|
||||
}
|
||||
|
||||
// cmdWrapper wraps exec.Cmd to implement processCmd interface
|
||||
type cmdWrapper struct {
|
||||
*exec.Cmd
|
||||
|
|
@ -55,23 +98,17 @@ type NativeProxy struct {
|
|||
cmd *cmdWrapper
|
||||
logger *zerolog.Logger
|
||||
ready chan struct{}
|
||||
options *NativeOptions
|
||||
options *nativeProxyOptions
|
||||
restartM sync.Mutex
|
||||
stopped bool
|
||||
processWait chan error
|
||||
}
|
||||
|
||||
func ensureDirectoryExists(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return os.MkdirAll(path, 0600)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNativeProxy creates a new NativeProxy that spawns a separate process
|
||||
func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) {
|
||||
nativeUnixSocket := "jetkvm-native-grpc"
|
||||
videoStreamUnixSocket := "@jetkvm-native-video-stream"
|
||||
proxyOptions := opts.toProxyOptions()
|
||||
proxyOptions.CtrlUnixSocket = "jetkvm-native-grpc"
|
||||
proxyOptions.VideoStreamUnixSocket = "@jetkvm-native-video-stream"
|
||||
|
||||
// Get the current executable path to spawn itself
|
||||
exePath, err := os.Executable()
|
||||
|
|
@ -80,12 +117,12 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) {
|
|||
}
|
||||
|
||||
proxy := &NativeProxy{
|
||||
nativeUnixSocket: nativeUnixSocket,
|
||||
videoStreamUnixSocket: videoStreamUnixSocket,
|
||||
nativeUnixSocket: proxyOptions.CtrlUnixSocket,
|
||||
videoStreamUnixSocket: proxyOptions.VideoStreamUnixSocket,
|
||||
binaryPath: exePath,
|
||||
logger: nativeLogger,
|
||||
ready: make(chan struct{}),
|
||||
options: &opts,
|
||||
options: proxyOptions,
|
||||
processWait: make(chan error, 1),
|
||||
}
|
||||
proxy.cmd, err = proxy.spawnProcess()
|
||||
|
|
@ -95,7 +132,7 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) {
|
|||
}
|
||||
|
||||
// create unix packet
|
||||
listener, err := net.Listen("unixpacket", videoStreamUnixSocket)
|
||||
listener, err := net.Listen("unixpacket", proxyOptions.VideoStreamUnixSocket)
|
||||
if err != nil {
|
||||
nativeLogger.Warn().Err(err).Msg("failed to start server")
|
||||
return nil, fmt.Errorf("failed to start server: %w", err)
|
||||
|
|
@ -116,6 +153,11 @@ func NewNativeProxy(opts NativeOptions) (*NativeProxy, error) {
|
|||
}
|
||||
|
||||
func (p *NativeProxy) spawnProcess() (*cmdWrapper, error) {
|
||||
envArgs, err := utils.MarshalEnv(p.options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal environment variables: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
p.binaryPath,
|
||||
"-subcomponent=native",
|
||||
|
|
@ -125,13 +167,7 @@ func (p *NativeProxy) spawnProcess() (*cmdWrapper, error) {
|
|||
// Set environment variable to indicate native process mode
|
||||
cmd.Env = append(
|
||||
os.Environ(),
|
||||
fmt.Sprintf("%s=native", supervisor.EnvSubcomponent),
|
||||
fmt.Sprintf("%s=%s", "JETKVM_NATIVE_SOCKET", p.nativeUnixSocket),
|
||||
fmt.Sprintf("%s=%s", "JETKVM_VIDEO_STREAM_SOCKET", p.videoStreamUnixSocket),
|
||||
fmt.Sprintf("%s=%s", "JETKVM_NATIVE_SYSTEM_VERSION", p.options.SystemVersion),
|
||||
fmt.Sprintf("%s=%s", "JETKVM_NATIVE_APP_VERSION", p.options.AppVersion),
|
||||
fmt.Sprintf("%s=%d", "JETKVM_NATIVE_DISPLAY_ROTATION", p.options.DisplayRotation),
|
||||
fmt.Sprintf("%s=%f", "JETKVM_NATIVE_DEFAULT_QUALITY_FACTOR", p.options.DefaultQualityFactor),
|
||||
envArgs...,
|
||||
)
|
||||
// Wrap cmd to implement processCmd interface
|
||||
wrappedCmd := &cmdWrapper{Cmd: cmd}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
|
||||
"github.com/caarlos0/env/v11"
|
||||
"github.com/erikdubbelboer/gspt"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// Native Process
|
||||
|
|
@ -19,31 +18,24 @@ import (
|
|||
|
||||
// RunNativeProcess runs the native process mode
|
||||
func RunNativeProcess(binaryName string) {
|
||||
logger := *nativeLogger
|
||||
// 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 {
|
||||
var proxyOptions nativeProxyOptions
|
||||
if err := env.Parse(&proxyOptions); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to parse native options")
|
||||
}
|
||||
|
||||
// connect to video stream socket
|
||||
conn, err := net.Dial("unixpacket", proxyOptions.VideoStreamUnixSocket)
|
||||
if err != nil {
|
||||
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")
|
||||
|
||||
nativeOptions := proxyOptions.toNativeOptions()
|
||||
nativeOptions.OnVideoFrameReceived = func(frame []byte, duration time.Duration) {
|
||||
_, err := conn.Write(frame)
|
||||
if err != nil {
|
||||
|
|
@ -52,7 +44,7 @@ func RunNativeProcess(binaryName string) {
|
|||
}
|
||||
|
||||
// Create native instance
|
||||
nativeInstance := NewNative(nativeOptions)
|
||||
nativeInstance := NewNative(*nativeOptions)
|
||||
|
||||
// Start native instance
|
||||
if err := nativeInstance.Start(); err != nil {
|
||||
|
|
@ -64,14 +56,14 @@ func RunNativeProcess(binaryName string) {
|
|||
|
||||
logger.Info().Msg("starting gRPC server")
|
||||
// Start gRPC server
|
||||
server, lis, err := StartGRPCServer(grpcServer, fmt.Sprintf("@%v", socketPath), &logger)
|
||||
server, lis, err := StartGRPCServer(grpcServer, fmt.Sprintf("@%v", proxyOptions.CtrlUnixSocket), &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)
|
||||
fmt.Fprintf(os.Stdout, "%s\n", proxyOptions.CtrlUnixSocket)
|
||||
defer os.Stdout.Close()
|
||||
|
||||
// Set up signal handling
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ show_help() {
|
|||
echo " --skip-native-build Skip native build"
|
||||
echo " --disable-docker Disable docker build"
|
||||
echo " --enable-sync-trace Enable sync trace (do not use in release builds)"
|
||||
echo " --native-binary Build and deploy the native binary (FOR DEBUGGING ONLY)"
|
||||
echo " -i, --install Build for release and install the app"
|
||||
echo " --help Display this help message"
|
||||
echo
|
||||
|
|
@ -58,6 +59,7 @@ REMOTE_PATH="/userdata/jetkvm/bin"
|
|||
SKIP_UI_BUILD=false
|
||||
SKIP_UI_BUILD_RELEASE=0
|
||||
SKIP_NATIVE_BUILD=0
|
||||
BUILD_NATIVE_BINARY=false
|
||||
ENABLE_SYNC_TRACE=0
|
||||
RESET_USB_HID_DEVICE=false
|
||||
LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}"
|
||||
|
|
@ -113,6 +115,10 @@ while [[ $# -gt 0 ]]; do
|
|||
RUN_GO_TESTS=true
|
||||
shift
|
||||
;;
|
||||
--native-binary)
|
||||
BUILD_NATIVE_BINARY=true
|
||||
shift
|
||||
;;
|
||||
-i|--install)
|
||||
INSTALL_APP=true
|
||||
shift
|
||||
|
|
@ -141,6 +147,9 @@ fi
|
|||
# Check device connectivity before proceeding
|
||||
check_ping "${REMOTE_HOST}"
|
||||
check_ssh "${REMOTE_USER}" "${REMOTE_HOST}"
|
||||
function sshdev() {
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" $@
|
||||
}
|
||||
|
||||
# check if the current CPU architecture is x86_64
|
||||
if [ "$(uname -m)" != "x86_64" ]; then
|
||||
|
|
@ -152,6 +161,27 @@ if [ "$BUILD_IN_DOCKER" = true ]; then
|
|||
build_docker_image
|
||||
fi
|
||||
|
||||
if [ "$BUILD_NATIVE_BINARY" = true ]; then
|
||||
msg_info "▶ Building native binary"
|
||||
make build_native
|
||||
sshdev "killall -9 jetkvm_app jetkvm_app_debug jetkvm_native_debug || true"
|
||||
sshdev "cat > ${REMOTE_PATH}/jetkvm_native_debug" < internal/native/cgo/build/jknative-bin
|
||||
sshdev ash << EOF
|
||||
set -e
|
||||
|
||||
# Set the library path to include the directory where librockit.so is located
|
||||
export LD_LIBRARY_PATH=/oem/usr/lib:\$LD_LIBRARY_PATH
|
||||
|
||||
cd ${REMOTE_PATH}
|
||||
killall -9 jetkvm_app jetkvm_app_debug jetkvm_native_debug || true
|
||||
sleep 5
|
||||
echo 'V' > /dev/watchdog
|
||||
chmod +x jetkvm_native_debug
|
||||
./jetkvm_native_debug
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Build the development version on the host
|
||||
# When using `make build_release`, the frontend will be built regardless of the `SKIP_UI_BUILD` flag
|
||||
# check if static/index.html exists
|
||||
|
|
@ -176,10 +206,10 @@ if [ "$RUN_GO_TESTS" = true ]; then
|
|||
make build_dev_test
|
||||
|
||||
msg_info "▶ Copying device-tests.tar.gz to remote host"
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz
|
||||
sshdev "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz
|
||||
|
||||
msg_info "▶ Running go tests"
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" ash << 'EOF'
|
||||
sshdev ash << 'EOF'
|
||||
set -e
|
||||
TMP_DIR=$(mktemp -d)
|
||||
cd ${TMP_DIR}
|
||||
|
|
@ -222,10 +252,10 @@ then
|
|||
ENABLE_SYNC_TRACE=${ENABLE_SYNC_TRACE}
|
||||
|
||||
# Copy the binary to the remote host as if we were the OTA updater.
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
|
||||
sshdev "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app
|
||||
|
||||
# Reboot the device, the new app will be deployed by the startup process.
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "reboot"
|
||||
sshdev "reboot"
|
||||
else
|
||||
msg_info "▶ Building development binary"
|
||||
do_make build_dev \
|
||||
|
|
@ -234,21 +264,21 @@ else
|
|||
ENABLE_SYNC_TRACE=${ENABLE_SYNC_TRACE}
|
||||
|
||||
# Kill any existing instances of the application
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true"
|
||||
sshdev "killall jetkvm_app_debug || true"
|
||||
|
||||
# Copy the binary to the remote host
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app
|
||||
sshdev "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app
|
||||
|
||||
if [ "$RESET_USB_HID_DEVICE" = true ]; then
|
||||
msg_info "▶ Resetting USB HID device"
|
||||
msg_warn "The option has been deprecated and will be removed in a future version, as JetKVM will now reset USB gadget configuration when needed"
|
||||
# Remove the old USB gadget configuration
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
|
||||
sshdev "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*"
|
||||
sshdev "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC"
|
||||
fi
|
||||
|
||||
# Deploy and run the application on the remote host
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" ash << EOF
|
||||
sshdev ash << EOF
|
||||
set -e
|
||||
|
||||
# Set the library path to include the directory where librockit.so is located
|
||||
|
|
|
|||
Loading…
Reference in New Issue