mirror of https://github.com/jetkvm/kvm.git
wip: move cgo to separate process
This commit is contained in:
parent
5fb4c629dd
commit
ffc26ac4e7
16
cmd/main.go
16
cmd/main.go
|
|
@ -17,19 +17,35 @@ import (
|
|||
|
||||
const (
|
||||
envChildID = "JETKVM_CHILD_ID"
|
||||
envSubcomponent = "JETKVM_SUBCOMPONENT"
|
||||
errorDumpDir = "/userdata/jetkvm/crashdump"
|
||||
errorDumpLastFile = "last-crash.log"
|
||||
errorDumpTemplate = "jetkvm-%s.log"
|
||||
)
|
||||
|
||||
var (
|
||||
subcomponent string
|
||||
)
|
||||
|
||||
func program() {
|
||||
subcomponentOverride := os.Getenv(envSubcomponent)
|
||||
if subcomponentOverride != "" {
|
||||
subcomponent = subcomponentOverride
|
||||
}
|
||||
switch subcomponent {
|
||||
case "native":
|
||||
gspt.SetProcTitle(os.Args[0] + " [native]")
|
||||
kvm.RunNativeProcess()
|
||||
default:
|
||||
gspt.SetProcTitle(os.Args[0] + " [app]")
|
||||
kvm.Main()
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
versionPtr := flag.Bool("version", false, "print version and exit")
|
||||
versionJSONPtr := flag.Bool("version-json", false, "print version as json and exit")
|
||||
flag.StringVar(&subcomponent, "subcomponent", "", "subcomponent to run")
|
||||
flag.Parse()
|
||||
|
||||
if *versionPtr || *versionJSONPtr {
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -97,6 +97,9 @@ require (
|
|||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/grpc v1.76.0 // indirect
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
6
go.sum
6
go.sum
|
|
@ -226,6 +226,12 @@ golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
|||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
diff --git a/internal/native/cgo/video.c b/internal/native/cgo/video.c
|
||||
index 2a4a034..760621a 100644
|
||||
--- a/internal/native/cgo/video.c
|
||||
+++ b/internal/native/cgo/video.c
|
||||
@@ -354,6 +354,10 @@ bool detected_signal = false, streaming_flag = false, streaming_stopped = true;
|
||||
pthread_t *streaming_thread = NULL;
|
||||
pthread_mutex_t streaming_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
+// Diagnostic tracking for validation
|
||||
+static uint64_t last_close_time = 0;
|
||||
+static int consecutive_failures = 0;
|
||||
+
|
||||
bool get_streaming_flag()
|
||||
{
|
||||
log_info("getting streaming flag");
|
||||
@@ -395,6 +399,12 @@ void *run_video_stream(void *arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
+ // Log attempt to open with timing info
|
||||
+ RK_U64 time_since_close = last_close_time > 0 ? (get_us() - last_close_time) : 0;
|
||||
+ log_info("[DIAG] Attempting to open %s (time_since_last_close=%llu us)",
|
||||
+ VIDEO_DEV, time_since_close);
|
||||
+
|
||||
+ RK_U64 open_start_time = get_us();
|
||||
int video_dev_fd = open(VIDEO_DEV, O_RDWR);
|
||||
if (video_dev_fd < 0)
|
||||
{
|
||||
@@ -402,7 +412,9 @@ void *run_video_stream(void *arg)
|
||||
usleep(1000000);
|
||||
continue;
|
||||
}
|
||||
- log_info("opened video capture device %s", VIDEO_DEV);
|
||||
+ RK_U64 open_end_time = get_us();
|
||||
+ log_info("[DIAG] opened video capture device %s in %llu us",
|
||||
+ VIDEO_DEV, open_end_time - open_start_time);
|
||||
|
||||
uint32_t width = detected_width;
|
||||
uint32_t height = detected_height;
|
||||
@@ -414,14 +426,45 @@ void *run_video_stream(void *arg)
|
||||
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
||||
|
||||
+ // Probe device state before attempting format set
|
||||
+ struct v4l2_format query_fmt;
|
||||
+ memset(&query_fmt, 0, sizeof(query_fmt));
|
||||
+ query_fmt.type = type;
|
||||
+ int query_ret = ioctl(video_dev_fd, VIDIOC_G_FMT, &query_fmt);
|
||||
+ log_info("[DIAG] VIDIOC_G_FMT probe: ret=%d, errno=%d (%s)",
|
||||
+ query_ret, query_ret < 0 ? errno : 0,
|
||||
+ query_ret < 0 ? strerror(errno) : "OK");
|
||||
+
|
||||
+ RK_U64 set_fmt_start_time = get_us();
|
||||
+ log_info("[DIAG] Attempting VIDIOC_S_FMT: %ux%u, time_since_open=%llu us",
|
||||
+ width, height, set_fmt_start_time - open_end_time);
|
||||
+
|
||||
if (ioctl(video_dev_fd, VIDIOC_S_FMT, &fmt) < 0)
|
||||
{
|
||||
- log_error("Set format fail: %s", strerror(errno));
|
||||
+ RK_U64 failure_time = get_us();
|
||||
+ int saved_errno = errno;
|
||||
+ consecutive_failures++;
|
||||
+
|
||||
+ log_error("[DIAG] Set format fail: errno=%d (%s)", saved_errno, strerror(saved_errno));
|
||||
+ log_error("[DIAG] Failure context: consecutive_failures=%d, time_since_open=%llu us, "
|
||||
+ "time_since_last_close=%llu us, resolution=%ux%u, streaming_flag=%d",
|
||||
+ consecutive_failures,
|
||||
+ failure_time - open_end_time,
|
||||
+ last_close_time > 0 ? (open_start_time - last_close_time) : 0,
|
||||
+ width, height,
|
||||
+ streaming_flag);
|
||||
+
|
||||
usleep(100000); // Sleep for 100 milliseconds
|
||||
close(video_dev_fd);
|
||||
+ last_close_time = get_us();
|
||||
+ log_info("[DIAG] Closed device after format failure at %llu us", last_close_time);
|
||||
continue;
|
||||
}
|
||||
|
||||
+ // Success - reset failure counter
|
||||
+ log_info("[DIAG] VIDIOC_S_FMT succeeded (previous consecutive failures: %d)", consecutive_failures);
|
||||
+ consecutive_failures = 0;
|
||||
+
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
struct v4l2_requestbuffers req;
|
||||
@@ -601,9 +644,46 @@ void *run_video_stream(void *arg)
|
||||
}
|
||||
cleanup:
|
||||
log_info("cleaning up video capture device %s", VIDEO_DEV);
|
||||
- if (ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
+
|
||||
+ RK_U64 streamoff_start = get_us();
|
||||
+ log_info("[DIAG] Attempting VIDIOC_STREAMOFF");
|
||||
+
|
||||
+ int streamoff_ret = ioctl(video_dev_fd, VIDIOC_STREAMOFF, &type);
|
||||
+ RK_U64 streamoff_end = get_us();
|
||||
+
|
||||
+ if (streamoff_ret < 0)
|
||||
+ {
|
||||
+ log_error("[DIAG] VIDIOC_STREAMOFF failed: errno=%d (%s), duration=%llu us",
|
||||
+ errno, strerror(errno), streamoff_end - streamoff_start);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ log_info("[DIAG] VIDIOC_STREAMOFF succeeded in %llu us",
|
||||
+ streamoff_end - streamoff_start);
|
||||
+ }
|
||||
+
|
||||
+ // VALIDATION TEST: Explicitly free V4L2 buffer queue
|
||||
+ struct v4l2_requestbuffers req_free;
|
||||
+ memset(&req_free, 0, sizeof(req_free));
|
||||
+ req_free.count = 0; // Tell driver to free all buffers
|
||||
+ req_free.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
+ req_free.memory = V4L2_MEMORY_DMABUF;
|
||||
+
|
||||
+ RK_U64 reqbufs_start = get_us();
|
||||
+ log_info("[DIAG] VALIDATION: Calling VIDIOC_REQBUFS(count=0) to free buffer queue");
|
||||
+
|
||||
+ int reqbufs_ret = ioctl(video_dev_fd, VIDIOC_REQBUFS, &req_free);
|
||||
+ RK_U64 reqbufs_end = get_us();
|
||||
+
|
||||
+ if (reqbufs_ret < 0)
|
||||
+ {
|
||||
+ log_error("[DIAG] VALIDATION: REQBUFS(0) FAILED - errno=%d (%s), duration=%llu us",
|
||||
+ errno, strerror(errno), reqbufs_end - reqbufs_start);
|
||||
+ }
|
||||
+ else
|
||||
{
|
||||
- log_error("VIDIOC_STREAMOFF failed: %s", strerror(errno));
|
||||
+ log_info("[DIAG] VALIDATION: REQBUFS(0) SUCCEEDED - freed buffers in %llu us",
|
||||
+ reqbufs_end - reqbufs_start);
|
||||
}
|
||||
|
||||
venc_stop();
|
||||
@@ -617,9 +697,13 @@ void *run_video_stream(void *arg)
|
||||
}
|
||||
|
||||
log_info("closing video capture device %s", VIDEO_DEV);
|
||||
+ RK_U64 close_start = get_us();
|
||||
close(video_dev_fd);
|
||||
+ last_close_time = get_us();
|
||||
+ log_info("[DIAG] Device closed, took %llu us, timestamp=%llu",
|
||||
+ last_close_time - close_start, last_close_time);
|
||||
}
|
||||
-
|
||||
+
|
||||
log_info("video stream thread exiting");
|
||||
|
||||
streaming_stopped = true;
|
||||
@@ -648,7 +732,7 @@ void video_shutdown()
|
||||
RK_MPI_MB_DestroyPool(memPool);
|
||||
}
|
||||
log_info("Destroyed memory pool");
|
||||
-
|
||||
+
|
||||
pthread_mutex_destroy(&streaming_mutex);
|
||||
log_info("Destroyed streaming mutex");
|
||||
}
|
||||
@@ -665,14 +749,14 @@ void video_start_streaming()
|
||||
log_warn("video streaming already started");
|
||||
return;
|
||||
}
|
||||
-
|
||||
+
|
||||
pthread_t *new_thread = malloc(sizeof(pthread_t));
|
||||
if (new_thread == NULL)
|
||||
{
|
||||
log_error("Failed to allocate memory for streaming thread");
|
||||
return;
|
||||
}
|
||||
-
|
||||
+
|
||||
set_streaming_flag(true);
|
||||
int result = pthread_create(new_thread, NULL, run_video_stream, NULL);
|
||||
if (result != 0)
|
||||
@@ -682,7 +766,7 @@ void video_start_streaming()
|
||||
free(new_thread);
|
||||
return;
|
||||
}
|
||||
-
|
||||
+
|
||||
// Only set streaming_thread after successful creation
|
||||
streaming_thread = new_thread;
|
||||
}
|
||||
@@ -693,7 +777,7 @@ void video_stop_streaming()
|
||||
log_info("video streaming already stopped");
|
||||
return;
|
||||
}
|
||||
-
|
||||
+
|
||||
log_info("stopping video streaming");
|
||||
set_streaming_flag(false);
|
||||
|
||||
@@ -711,7 +795,7 @@ void video_stop_streaming()
|
||||
free(streaming_thread);
|
||||
streaming_thread = NULL;
|
||||
|
||||
- log_info("video streaming stopped");
|
||||
+ log_info("video streaming stopped");
|
||||
}
|
||||
|
||||
void video_restart_streaming()
|
||||
@@ -818,4 +902,4 @@ void video_set_quality_factor(float factor)
|
||||
|
||||
float video_get_quality_factor() {
|
||||
return quality_factor;
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
pb "github.com/jetkvm/kvm/internal/native/proto"
|
||||
)
|
||||
|
||||
// grpcServer wraps the Native instance and implements the gRPC service
|
||||
type grpcServer struct {
|
||||
pb.UnimplementedNativeServiceServer
|
||||
native *Native
|
||||
logger *zerolog.Logger
|
||||
eventChs []chan *pb.Event
|
||||
eventM sync.Mutex
|
||||
}
|
||||
|
||||
// NewGRPCServer creates a new gRPC server for the native service
|
||||
func NewGRPCServer(n *Native, logger *zerolog.Logger) *grpcServer {
|
||||
s := &grpcServer{
|
||||
native: n,
|
||||
logger: logger,
|
||||
eventChs: make([]chan *pb.Event, 0),
|
||||
}
|
||||
|
||||
// Store original callbacks and wrap them to also broadcast events
|
||||
originalVideoStateChange := n.onVideoStateChange
|
||||
originalIndevEvent := n.onIndevEvent
|
||||
originalRpcEvent := n.onRpcEvent
|
||||
originalVideoFrameReceived := n.onVideoFrameReceived
|
||||
|
||||
// Wrap callbacks to both call original and broadcast events
|
||||
n.onVideoStateChange = func(state VideoState) {
|
||||
if originalVideoStateChange != nil {
|
||||
originalVideoStateChange(state)
|
||||
}
|
||||
event := &pb.Event{
|
||||
Type: "video_state_change",
|
||||
VideoState: &pb.VideoState{
|
||||
Ready: state.Ready,
|
||||
Error: state.Error,
|
||||
Width: int32(state.Width),
|
||||
Height: int32(state.Height),
|
||||
FramePerSecond: state.FramePerSecond,
|
||||
},
|
||||
}
|
||||
s.broadcastEvent(event)
|
||||
}
|
||||
|
||||
n.onIndevEvent = func(event string) {
|
||||
if originalIndevEvent != nil {
|
||||
originalIndevEvent(event)
|
||||
}
|
||||
s.broadcastEvent(&pb.Event{
|
||||
Type: "indev_event",
|
||||
IndevEvent: event,
|
||||
})
|
||||
}
|
||||
|
||||
n.onRpcEvent = func(event string) {
|
||||
if originalRpcEvent != nil {
|
||||
originalRpcEvent(event)
|
||||
}
|
||||
s.broadcastEvent(&pb.Event{
|
||||
Type: "rpc_event",
|
||||
RpcEvent: event,
|
||||
})
|
||||
}
|
||||
|
||||
n.onVideoFrameReceived = func(frame []byte, duration time.Duration) {
|
||||
if originalVideoFrameReceived != nil {
|
||||
originalVideoFrameReceived(frame, duration)
|
||||
}
|
||||
s.broadcastEvent(&pb.Event{
|
||||
Type: "video_frame",
|
||||
VideoFrame: &pb.VideoFrame{
|
||||
Frame: frame,
|
||||
DurationNs: duration.Nanoseconds(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *grpcServer) broadcastEvent(event *pb.Event) {
|
||||
s.eventM.Lock()
|
||||
defer s.eventM.Unlock()
|
||||
|
||||
for _, ch := range s.eventChs {
|
||||
select {
|
||||
case ch <- event:
|
||||
default:
|
||||
// Channel full, skip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Video methods
|
||||
func (s *grpcServer) VideoSetSleepMode(ctx context.Context, req *pb.VideoSetSleepModeRequest) (*pb.Empty, error) {
|
||||
if err := s.native.VideoSetSleepMode(req.Enabled); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoGetSleepMode(ctx context.Context, req *pb.Empty) (*pb.VideoGetSleepModeResponse, error) {
|
||||
enabled, err := s.native.VideoGetSleepMode()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.VideoGetSleepModeResponse{Enabled: enabled}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoSleepModeSupported(ctx context.Context, req *pb.Empty) (*pb.VideoSleepModeSupportedResponse, error) {
|
||||
return &pb.VideoSleepModeSupportedResponse{Supported: s.native.VideoSleepModeSupported()}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoSetQualityFactor(ctx context.Context, req *pb.VideoSetQualityFactorRequest) (*pb.Empty, error) {
|
||||
if err := s.native.VideoSetQualityFactor(req.Factor); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoGetQualityFactor(ctx context.Context, req *pb.Empty) (*pb.VideoGetQualityFactorResponse, error) {
|
||||
factor, err := s.native.VideoGetQualityFactor()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.VideoGetQualityFactorResponse{Factor: factor}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoSetEDID(ctx context.Context, req *pb.VideoSetEDIDRequest) (*pb.Empty, error) {
|
||||
if err := s.native.VideoSetEDID(req.Edid); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoGetEDID(ctx context.Context, req *pb.Empty) (*pb.VideoGetEDIDResponse, error) {
|
||||
edid, err := s.native.VideoGetEDID()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.VideoGetEDIDResponse{Edid: edid}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoLogStatus(ctx context.Context, req *pb.Empty) (*pb.VideoLogStatusResponse, error) {
|
||||
logStatus, err := s.native.VideoLogStatus()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.VideoLogStatusResponse{Status: logStatus}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
||||
if err := s.native.VideoStop(); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) VideoStart(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
||||
if err := s.native.VideoStart(); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
// UI methods
|
||||
func (s *grpcServer) GetLVGLVersion(ctx context.Context, req *pb.Empty) (*pb.GetLVGLVersionResponse, error) {
|
||||
version, err := s.native.GetLVGLVersion()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.GetLVGLVersionResponse{Version: version}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjHide(ctx context.Context, req *pb.UIObjHideRequest) (*pb.UIObjHideResponse, error) {
|
||||
success, err := s.native.UIObjHide(req.ObjName)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjHideResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjShow(ctx context.Context, req *pb.UIObjShowRequest) (*pb.UIObjShowResponse, error) {
|
||||
success, err := s.native.UIObjShow(req.ObjName)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjShowResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UISetVar(ctx context.Context, req *pb.UISetVarRequest) (*pb.Empty, error) {
|
||||
s.native.UISetVar(req.Name, req.Value)
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIGetVar(ctx context.Context, req *pb.UIGetVarRequest) (*pb.UIGetVarResponse, error) {
|
||||
value := s.native.UIGetVar(req.Name)
|
||||
return &pb.UIGetVarResponse{Value: value}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjAddState(ctx context.Context, req *pb.UIObjAddStateRequest) (*pb.UIObjAddStateResponse, error) {
|
||||
success, err := s.native.UIObjAddState(req.ObjName, req.State)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjAddStateResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjClearState(ctx context.Context, req *pb.UIObjClearStateRequest) (*pb.UIObjClearStateResponse, error) {
|
||||
success, err := s.native.UIObjClearState(req.ObjName, req.State)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjClearStateResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjAddFlag(ctx context.Context, req *pb.UIObjAddFlagRequest) (*pb.UIObjAddFlagResponse, error) {
|
||||
success, err := s.native.UIObjAddFlag(req.ObjName, req.Flag)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjAddFlagResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjClearFlag(ctx context.Context, req *pb.UIObjClearFlagRequest) (*pb.UIObjClearFlagResponse, error) {
|
||||
success, err := s.native.UIObjClearFlag(req.ObjName, req.Flag)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjClearFlagResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjSetOpacity(ctx context.Context, req *pb.UIObjSetOpacityRequest) (*pb.UIObjSetOpacityResponse, error) {
|
||||
success, err := s.native.UIObjSetOpacity(req.ObjName, int(req.Opacity))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjSetOpacityResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjFadeIn(ctx context.Context, req *pb.UIObjFadeInRequest) (*pb.UIObjFadeInResponse, error) {
|
||||
success, err := s.native.UIObjFadeIn(req.ObjName, req.Duration)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjFadeInResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjFadeOut(ctx context.Context, req *pb.UIObjFadeOutRequest) (*pb.UIObjFadeOutResponse, error) {
|
||||
success, err := s.native.UIObjFadeOut(req.ObjName, req.Duration)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjFadeOutResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjSetLabelText(ctx context.Context, req *pb.UIObjSetLabelTextRequest) (*pb.UIObjSetLabelTextResponse, error) {
|
||||
success, err := s.native.UIObjSetLabelText(req.ObjName, req.Text)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjSetLabelTextResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UIObjSetImageSrc(ctx context.Context, req *pb.UIObjSetImageSrcRequest) (*pb.UIObjSetImageSrcResponse, error) {
|
||||
success, err := s.native.UIObjSetImageSrc(req.ObjName, req.Image)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.UIObjSetImageSrcResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DisplaySetRotation(ctx context.Context, req *pb.DisplaySetRotationRequest) (*pb.DisplaySetRotationResponse, error) {
|
||||
success, err := s.native.DisplaySetRotation(uint16(req.Rotation))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
return &pb.DisplaySetRotationResponse{Success: success}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UpdateLabelIfChanged(ctx context.Context, req *pb.UpdateLabelIfChangedRequest) (*pb.Empty, error) {
|
||||
s.native.UpdateLabelIfChanged(req.ObjName, req.NewText)
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) UpdateLabelAndChangeVisibility(ctx context.Context, req *pb.UpdateLabelAndChangeVisibilityRequest) (*pb.Empty, error) {
|
||||
s.native.UpdateLabelAndChangeVisibility(req.ObjName, req.NewText)
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) SwitchToScreenIf(ctx context.Context, req *pb.SwitchToScreenIfRequest) (*pb.Empty, error) {
|
||||
s.native.SwitchToScreenIf(req.ScreenName, req.ShouldSwitch)
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) SwitchToScreenIfDifferent(ctx context.Context, req *pb.SwitchToScreenIfDifferentRequest) (*pb.Empty, error) {
|
||||
s.native.SwitchToScreenIfDifferent(req.ScreenName)
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *grpcServer) DoNotUseThisIsForCrashTestingOnly(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
||||
s.native.DoNotUseThisIsForCrashTestingOnly()
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
// StreamEvents streams events from the native process
|
||||
func (s *grpcServer) StreamEvents(req *pb.Empty, stream pb.NativeService_StreamEventsServer) error {
|
||||
eventCh := make(chan *pb.Event, 100)
|
||||
|
||||
// Register this channel for events
|
||||
s.eventM.Lock()
|
||||
s.eventChs = append(s.eventChs, eventCh)
|
||||
s.eventM.Unlock()
|
||||
|
||||
// Unregister on exit
|
||||
defer func() {
|
||||
s.eventM.Lock()
|
||||
defer s.eventM.Unlock()
|
||||
for i, ch := range s.eventChs {
|
||||
if ch == eventCh {
|
||||
s.eventChs = append(s.eventChs[:i], s.eventChs[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
close(eventCh)
|
||||
}()
|
||||
|
||||
// Stream events
|
||||
for {
|
||||
select {
|
||||
case event := <-eventCh:
|
||||
if err := stream.Send(event); err != nil {
|
||||
return err
|
||||
}
|
||||
case <-stream.Context().Done():
|
||||
return stream.Context().Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StartGRPCServer starts the gRPC server on a Unix domain socket
|
||||
func StartGRPCServer(server *grpcServer, socketPath string, logger *zerolog.Logger) (*grpc.Server, net.Listener, error) {
|
||||
// Remove socket if it exists
|
||||
if _, err := os.Stat(socketPath); err == nil {
|
||||
if err := os.Remove(socketPath); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to remove existing socket: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(socketPath), 0755); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create socket directory: %w", err)
|
||||
}
|
||||
|
||||
lis, err := net.Listen("unix", socketPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to listen on socket: %w", err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer()
|
||||
pb.RegisterNativeServiceServer(s, server)
|
||||
|
||||
go func() {
|
||||
if err := s.Serve(lis); err != nil {
|
||||
logger.Error().Err(err).Msg("gRPC server error")
|
||||
}
|
||||
}()
|
||||
|
||||
logger.Info().Str("socket", socketPath).Msg("gRPC server started")
|
||||
return s, lis, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package native
|
||||
|
||||
// NativeInterface defines the interface that both Native and NativeProxy implement
|
||||
type NativeInterface interface {
|
||||
Start() error
|
||||
VideoSetSleepMode(enabled bool) error
|
||||
VideoGetSleepMode() (bool, error)
|
||||
VideoSleepModeSupported() bool
|
||||
VideoSetQualityFactor(factor float64) error
|
||||
VideoGetQualityFactor() (float64, error)
|
||||
VideoSetEDID(edid string) error
|
||||
VideoGetEDID() (string, error)
|
||||
VideoLogStatus() (string, error)
|
||||
VideoStop() error
|
||||
VideoStart() error
|
||||
GetLVGLVersion() (string, error)
|
||||
UIObjHide(objName string) (bool, error)
|
||||
UIObjShow(objName string) (bool, error)
|
||||
UISetVar(name string, value string)
|
||||
UIGetVar(name string) string
|
||||
UIObjAddState(objName string, state string) (bool, error)
|
||||
UIObjClearState(objName string, state string) (bool, error)
|
||||
UIObjAddFlag(objName string, flag string) (bool, error)
|
||||
UIObjClearFlag(objName string, flag string) (bool, error)
|
||||
UIObjSetOpacity(objName string, opacity int) (bool, error)
|
||||
UIObjFadeIn(objName string, duration uint32) (bool, error)
|
||||
UIObjFadeOut(objName string, duration uint32) (bool, error)
|
||||
UIObjSetLabelText(objName string, text string) (bool, error)
|
||||
UIObjSetImageSrc(objName string, image string) (bool, error)
|
||||
DisplaySetRotation(rotation uint16) (bool, error)
|
||||
UpdateLabelIfChanged(objName string, newText string)
|
||||
UpdateLabelAndChangeVisibility(objName string, newText string)
|
||||
SwitchToScreenIf(screenName string, shouldSwitch []string)
|
||||
SwitchToScreenIfDifferent(screenName string)
|
||||
DoNotUseThisIsForCrashTestingOnly()
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// Request represents a JSON-RPC request
|
||||
type Request struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id,omitempty"`
|
||||
Method string `json:"method"`
|
||||
Params json.RawMessage `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// Response represents a JSON-RPC response
|
||||
type Response struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
ID interface{} `json:"id,omitempty"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
Error *RPCError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RPCError represents a JSON-RPC error
|
||||
type RPCError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// Event represents a JSON-RPC notification/event
|
||||
type Event struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
Params map[string]interface{} `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// ProcessConfig is the configuration for the native process
|
||||
type ProcessConfig struct {
|
||||
Disable bool `json:"disable"`
|
||||
SystemVersion string `json:"system_version"` // Serialized as string
|
||||
AppVersion string `json:"app_version"` // Serialized as string
|
||||
DisplayRotation uint16 `json:"display_rotation"`
|
||||
DefaultQualityFactor float64 `json:"default_quality_factor"`
|
||||
}
|
||||
|
||||
// IPCClient handles communication with the native process
|
||||
type IPCClient struct {
|
||||
stdin io.WriteCloser
|
||||
stdout *bufio.Scanner
|
||||
logger *zerolog.Logger
|
||||
|
||||
requestID int64
|
||||
requestIDM sync.Mutex
|
||||
|
||||
pendingRequests map[interface{}]chan *Response
|
||||
pendingM sync.Mutex
|
||||
|
||||
eventHandlers map[string][]func(data interface{})
|
||||
eventM sync.RWMutex
|
||||
|
||||
readyCh chan struct{}
|
||||
ready bool
|
||||
|
||||
closed bool
|
||||
closeM sync.Mutex
|
||||
}
|
||||
|
||||
type processCmd interface {
|
||||
Start() error
|
||||
Wait() error
|
||||
GetProcess() interface {
|
||||
Kill() error
|
||||
Signal(sig interface{}) error
|
||||
}
|
||||
StdinPipe() (io.WriteCloser, error)
|
||||
StdoutPipe() (io.ReadCloser, error)
|
||||
StderrPipe() (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
func NewIPCClient(cmd processCmd, logger *zerolog.Logger) (*IPCClient, error) {
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get stdin pipe: %w", err)
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
stdin.Close()
|
||||
return nil, fmt.Errorf("failed to get stdout pipe: %w", err)
|
||||
}
|
||||
|
||||
client := &IPCClient{
|
||||
stdin: stdin,
|
||||
stdout: bufio.NewScanner(stdout),
|
||||
logger: logger,
|
||||
pendingRequests: make(map[interface{}]chan *Response),
|
||||
eventHandlers: make(map[string][]func(data interface{})),
|
||||
readyCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Start reading responses
|
||||
go client.readLoop()
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (c *IPCClient) readLoop() {
|
||||
for c.stdout.Scan() {
|
||||
line := c.stdout.Bytes()
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Try to parse as response
|
||||
var resp Response
|
||||
if err := json.Unmarshal(line, &resp); err == nil {
|
||||
// Check if it's a ready signal (result is "ready" and no ID)
|
||||
if resp.Result == "ready" && resp.ID == nil && !c.ready {
|
||||
c.ready = true
|
||||
close(c.readyCh)
|
||||
continue
|
||||
}
|
||||
if resp.Result != nil || resp.Error != nil {
|
||||
c.handleResponse(&resp)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse as event
|
||||
var event Event
|
||||
if err := json.Unmarshal(line, &event); err == nil && event.Method == "event" {
|
||||
c.handleEvent(&event)
|
||||
continue
|
||||
}
|
||||
|
||||
c.logger.Warn().Bytes("line", line).Msg("unexpected message from native process")
|
||||
}
|
||||
|
||||
c.closeM.Lock()
|
||||
if !c.closed {
|
||||
c.closed = true
|
||||
c.closeM.Unlock()
|
||||
c.logger.Warn().Msg("native process stdout closed")
|
||||
// Cancel all pending requests
|
||||
c.pendingM.Lock()
|
||||
for id, ch := range c.pendingRequests {
|
||||
close(ch)
|
||||
delete(c.pendingRequests, id)
|
||||
}
|
||||
c.pendingM.Unlock()
|
||||
} else {
|
||||
c.closeM.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *IPCClient) handleResponse(resp *Response) {
|
||||
c.pendingM.Lock()
|
||||
ch, ok := c.pendingRequests[resp.ID]
|
||||
if ok {
|
||||
delete(c.pendingRequests, resp.ID)
|
||||
}
|
||||
c.pendingM.Unlock()
|
||||
|
||||
if ok {
|
||||
select {
|
||||
case ch <- resp:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *IPCClient) handleEvent(event *Event) {
|
||||
if event.Method != "event" || event.Params == nil {
|
||||
return
|
||||
}
|
||||
|
||||
eventType, ok := event.Params["type"].(string)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
data := event.Params["data"]
|
||||
|
||||
c.eventM.RLock()
|
||||
handlers := c.eventHandlers[eventType]
|
||||
c.eventM.RUnlock()
|
||||
|
||||
for _, handler := range handlers {
|
||||
handler(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *IPCClient) Call(method string, params interface{}) (*Response, error) {
|
||||
c.closeM.Lock()
|
||||
if c.closed {
|
||||
c.closeM.Unlock()
|
||||
return nil, fmt.Errorf("client is closed")
|
||||
}
|
||||
c.closeM.Unlock()
|
||||
|
||||
c.requestIDM.Lock()
|
||||
c.requestID++
|
||||
id := c.requestID
|
||||
c.requestIDM.Unlock()
|
||||
|
||||
req := Request{
|
||||
JSONRPC: "2.0",
|
||||
ID: id,
|
||||
Method: method,
|
||||
}
|
||||
|
||||
if params != nil {
|
||||
paramsBytes, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal params: %w", err)
|
||||
}
|
||||
req.Params = paramsBytes
|
||||
}
|
||||
|
||||
ch := make(chan *Response, 1)
|
||||
c.pendingM.Lock()
|
||||
c.pendingRequests[id] = ch
|
||||
c.pendingM.Unlock()
|
||||
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
c.pendingM.Lock()
|
||||
delete(c.pendingRequests, id)
|
||||
c.pendingM.Unlock()
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
if _, err := c.stdin.Write(append(reqBytes, '\n')); err != nil {
|
||||
c.pendingM.Lock()
|
||||
delete(c.pendingRequests, id)
|
||||
c.pendingM.Unlock()
|
||||
return nil, fmt.Errorf("failed to write request: %w", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case resp := <-ch:
|
||||
if resp.Error != nil {
|
||||
return nil, fmt.Errorf("RPC error: %s (code: %d)", resp.Error.Message, resp.Error.Code)
|
||||
}
|
||||
return resp, nil
|
||||
case <-time.After(30 * time.Second):
|
||||
c.pendingM.Lock()
|
||||
delete(c.pendingRequests, id)
|
||||
c.pendingM.Unlock()
|
||||
return nil, fmt.Errorf("request timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *IPCClient) OnEvent(eventType string, handler func(data interface{})) {
|
||||
c.eventM.Lock()
|
||||
defer c.eventM.Unlock()
|
||||
c.eventHandlers[eventType] = append(c.eventHandlers[eventType], handler)
|
||||
}
|
||||
|
||||
func (c *IPCClient) WaitReady() error {
|
||||
select {
|
||||
case <-c.readyCh:
|
||||
return nil
|
||||
case <-time.After(10 * time.Second):
|
||||
return fmt.Errorf("timeout waiting for ready signal")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *IPCClient) Close() error {
|
||||
c.closeM.Lock()
|
||||
defer c.closeM.Unlock()
|
||||
if c.closed {
|
||||
return nil
|
||||
}
|
||||
c.closed = true
|
||||
|
||||
c.pendingM.Lock()
|
||||
for id, ch := range c.pendingRequests {
|
||||
close(ch)
|
||||
delete(c.pendingRequests, id)
|
||||
}
|
||||
c.pendingM.Unlock()
|
||||
|
||||
return c.stdin.Close()
|
||||
}
|
||||
|
||||
|
|
@ -94,11 +94,11 @@ func NewNative(opts NativeOptions) *Native {
|
|||
}
|
||||
}
|
||||
|
||||
func (n *Native) Start() {
|
||||
func (n *Native) Start() error {
|
||||
if n.disable {
|
||||
nativeLogger.Warn().Msg("native is disabled, skipping initialization")
|
||||
setCgoDisabled(true)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// set up singleton
|
||||
|
|
@ -117,9 +117,11 @@ func (n *Native) Start() {
|
|||
|
||||
if err := videoInit(n.defaultQualityFactor); err != nil {
|
||||
n.l.Error().Err(err).Msg("failed to initialize video")
|
||||
return err
|
||||
}
|
||||
|
||||
close(n.ready)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DoNotUseThisIsForCrashTestingOnly
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# Proto Files
|
||||
|
||||
This directory contains the Protocol Buffer definitions for the native service.
|
||||
|
||||
## Generating Code
|
||||
|
||||
To generate the Go code from the proto files, run:
|
||||
|
||||
```bash
|
||||
./scripts/generate_proto.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
protoc \
|
||||
--go_out=. \
|
||||
--go_opt=paths=source_relative \
|
||||
--go-grpc_out=. \
|
||||
--go-grpc_opt=paths=source_relative \
|
||||
internal/native/proto/native.proto
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `protoc` - Protocol Buffer compiler
|
||||
- `protoc-gen-go` - Go plugin for protoc (install with: `go install google.golang.org/protobuf/cmd/protoc-gen-go@latest`)
|
||||
- `protoc-gen-go-grpc` - gRPC Go plugin for protoc (install with: `go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest`)
|
||||
|
||||
## Note
|
||||
|
||||
The current `native.pb.go` and `native_grpc.pb.go` files are placeholder/stub files. They should be regenerated from `native.proto` using the commands above.
|
||||
|
||||
|
|
@ -0,0 +1,596 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// This file should be regenerated from native.proto using:
|
||||
// protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative internal/native/proto/native.proto
|
||||
//
|
||||
// For now, this is a minimal implementation to allow compilation.
|
||||
// TODO: Regenerate from proto file when protoc is available.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Empty struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *Empty) Reset() {
|
||||
*x = Empty{}
|
||||
}
|
||||
|
||||
func (x *Empty) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (*Empty) ProtoMessage() {}
|
||||
|
||||
func (x *Empty) ProtoReflect() protoreflect.Message {
|
||||
return nil // Stub
|
||||
}
|
||||
|
||||
type VideoState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Ready bool `protobuf:"varint,1,opt,name=ready,proto3" json:"ready,omitempty"`
|
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
|
||||
Width int32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"`
|
||||
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
|
||||
FramePerSecond float64 `protobuf:"fixed64,5,opt,name=frame_per_second,json=framePerSecond,proto3" json:"frame_per_second,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoState) Reset() {
|
||||
*x = VideoState{}
|
||||
}
|
||||
|
||||
func (x *VideoState) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (*VideoState) ProtoMessage() {}
|
||||
|
||||
func (x *VideoState) ProtoReflect() protoreflect.Message {
|
||||
return nil // Stub
|
||||
}
|
||||
|
||||
// Request/Response types - minimal implementations
|
||||
type VideoSetSleepModeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoSetSleepModeRequest) Reset() { *x = VideoSetSleepModeRequest{} }
|
||||
func (x *VideoSetSleepModeRequest) String() string { return "" }
|
||||
func (*VideoSetSleepModeRequest) ProtoMessage() {}
|
||||
func (x *VideoSetSleepModeRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoGetSleepModeResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoGetSleepModeResponse) Reset() { *x = VideoGetSleepModeResponse{} }
|
||||
func (x *VideoGetSleepModeResponse) String() string { return "" }
|
||||
func (*VideoGetSleepModeResponse) ProtoMessage() {}
|
||||
func (x *VideoGetSleepModeResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoSleepModeSupportedResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoSleepModeSupportedResponse) Reset() { *x = VideoSleepModeSupportedResponse{} }
|
||||
func (x *VideoSleepModeSupportedResponse) String() string { return "" }
|
||||
func (*VideoSleepModeSupportedResponse) ProtoMessage() {}
|
||||
func (x *VideoSleepModeSupportedResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoSetQualityFactorRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Factor float64 `protobuf:"fixed64,1,opt,name=factor,proto3" json:"factor,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoSetQualityFactorRequest) Reset() { *x = VideoSetQualityFactorRequest{} }
|
||||
func (x *VideoSetQualityFactorRequest) String() string { return "" }
|
||||
func (*VideoSetQualityFactorRequest) ProtoMessage() {}
|
||||
func (x *VideoSetQualityFactorRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoGetQualityFactorResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Factor float64 `protobuf:"fixed64,1,opt,name=factor,proto3" json:"factor,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoGetQualityFactorResponse) Reset() { *x = VideoGetQualityFactorResponse{} }
|
||||
func (x *VideoGetQualityFactorResponse) String() string { return "" }
|
||||
func (*VideoGetQualityFactorResponse) ProtoMessage() {}
|
||||
func (x *VideoGetQualityFactorResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoSetEDIDRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Edid string `protobuf:"bytes,1,opt,name=edid,proto3" json:"edid,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoSetEDIDRequest) Reset() { *x = VideoSetEDIDRequest{} }
|
||||
func (x *VideoSetEDIDRequest) String() string { return "" }
|
||||
func (*VideoSetEDIDRequest) ProtoMessage() {}
|
||||
func (x *VideoSetEDIDRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoGetEDIDResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Edid string `protobuf:"bytes,1,opt,name=edid,proto3" json:"edid,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoGetEDIDResponse) Reset() { *x = VideoGetEDIDResponse{} }
|
||||
func (x *VideoGetEDIDResponse) String() string { return "" }
|
||||
func (*VideoGetEDIDResponse) ProtoMessage() {}
|
||||
func (x *VideoGetEDIDResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoLogStatusResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoLogStatusResponse) Reset() { *x = VideoLogStatusResponse{} }
|
||||
func (x *VideoLogStatusResponse) String() string { return "" }
|
||||
func (*VideoLogStatusResponse) ProtoMessage() {}
|
||||
func (x *VideoLogStatusResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type GetLVGLVersionResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetLVGLVersionResponse) Reset() { *x = GetLVGLVersionResponse{} }
|
||||
func (x *GetLVGLVersionResponse) String() string { return "" }
|
||||
func (*GetLVGLVersionResponse) ProtoMessage() {}
|
||||
func (x *GetLVGLVersionResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
// UI message types
|
||||
type UIObjHideRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjHideRequest) Reset() { *x = UIObjHideRequest{} }
|
||||
func (x *UIObjHideRequest) String() string { return "" }
|
||||
func (*UIObjHideRequest) ProtoMessage() {}
|
||||
func (x *UIObjHideRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjHideResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjHideResponse) Reset() { *x = UIObjHideResponse{} }
|
||||
func (x *UIObjHideResponse) String() string { return "" }
|
||||
func (*UIObjHideResponse) ProtoMessage() {}
|
||||
func (x *UIObjHideResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjShowRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjShowRequest) Reset() { *x = UIObjShowRequest{} }
|
||||
func (x *UIObjShowRequest) String() string { return "" }
|
||||
func (*UIObjShowRequest) ProtoMessage() {}
|
||||
func (x *UIObjShowRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjShowResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjShowResponse) Reset() { *x = UIObjShowResponse{} }
|
||||
func (x *UIObjShowResponse) String() string { return "" }
|
||||
func (*UIObjShowResponse) ProtoMessage() {}
|
||||
func (x *UIObjShowResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UISetVarRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UISetVarRequest) Reset() { *x = UISetVarRequest{} }
|
||||
func (x *UISetVarRequest) String() string { return "" }
|
||||
func (*UISetVarRequest) ProtoMessage() {}
|
||||
func (x *UISetVarRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIGetVarRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIGetVarRequest) Reset() { *x = UIGetVarRequest{} }
|
||||
func (x *UIGetVarRequest) String() string { return "" }
|
||||
func (*UIGetVarRequest) ProtoMessage() {}
|
||||
func (x *UIGetVarRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIGetVarResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIGetVarResponse) Reset() { *x = UIGetVarResponse{} }
|
||||
func (x *UIGetVarResponse) String() string { return "" }
|
||||
func (*UIGetVarResponse) ProtoMessage() {}
|
||||
func (x *UIGetVarResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
// Additional UI types - abbreviated for brevity, follow same pattern
|
||||
type UIObjAddStateRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjAddStateRequest) Reset() { *x = UIObjAddStateRequest{} }
|
||||
func (x *UIObjAddStateRequest) String() string { return "" }
|
||||
func (*UIObjAddStateRequest) ProtoMessage() {}
|
||||
func (x *UIObjAddStateRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjAddStateResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjAddStateResponse) Reset() { *x = UIObjAddStateResponse{} }
|
||||
func (x *UIObjAddStateResponse) String() string { return "" }
|
||||
func (*UIObjAddStateResponse) ProtoMessage() {}
|
||||
func (x *UIObjAddStateResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
// Event types
|
||||
type Event struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
// oneof data - using separate fields for now
|
||||
VideoState *VideoState `protobuf:"bytes,2,opt,name=video_state,json=videoState,proto3" json:"video_state,omitempty"`
|
||||
IndevEvent string `protobuf:"bytes,3,opt,name=indev_event,json=indevEvent,proto3" json:"indev_event,omitempty"`
|
||||
RpcEvent string `protobuf:"bytes,4,opt,name=rpc_event,json=rpcEvent,proto3" json:"rpc_event,omitempty"`
|
||||
VideoFrame *VideoFrame `protobuf:"bytes,5,opt,name=video_frame,json=videoFrame,proto3" json:"video_frame,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Event) Reset() { *x = Event{} }
|
||||
func (x *Event) String() string { return "" }
|
||||
func (*Event) ProtoMessage() {}
|
||||
func (x *Event) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type VideoFrame struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Frame []byte `protobuf:"bytes,1,opt,name=frame,proto3" json:"frame,omitempty"`
|
||||
DurationNs int64 `protobuf:"varint,2,opt,name=duration_ns,json=durationNs,proto3" json:"duration_ns,omitempty"`
|
||||
}
|
||||
|
||||
func (x *VideoFrame) Reset() { *x = VideoFrame{} }
|
||||
func (x *VideoFrame) String() string { return "" }
|
||||
func (*VideoFrame) ProtoMessage() {}
|
||||
func (x *VideoFrame) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
// Additional request/response types - following same pattern
|
||||
// (Abbreviated - all follow the same structure)
|
||||
type UIObjClearStateRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjClearStateRequest) Reset() { *x = UIObjClearStateRequest{} }
|
||||
func (x *UIObjClearStateRequest) String() string { return "" }
|
||||
func (*UIObjClearStateRequest) ProtoMessage() {}
|
||||
func (x *UIObjClearStateRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjClearStateResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjClearStateResponse) Reset() { *x = UIObjClearStateResponse{} }
|
||||
func (x *UIObjClearStateResponse) String() string { return "" }
|
||||
func (*UIObjClearStateResponse) ProtoMessage() {}
|
||||
func (x *UIObjClearStateResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
// Remaining types follow same pattern - creating minimal stubs
|
||||
// TODO: Regenerate from proto for complete implementation
|
||||
|
||||
type UIObjAddFlagRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Flag string `protobuf:"bytes,2,opt,name=flag,proto3" json:"flag,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjAddFlagRequest) Reset() { *x = UIObjAddFlagRequest{} }
|
||||
func (x *UIObjAddFlagRequest) String() string { return "" }
|
||||
func (*UIObjAddFlagRequest) ProtoMessage() {}
|
||||
func (x *UIObjAddFlagRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjAddFlagResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjAddFlagResponse) Reset() { *x = UIObjAddFlagResponse{} }
|
||||
func (x *UIObjAddFlagResponse) String() string { return "" }
|
||||
func (*UIObjAddFlagResponse) ProtoMessage() {}
|
||||
func (x *UIObjAddFlagResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjClearFlagRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Flag string `protobuf:"bytes,2,opt,name=flag,proto3" json:"flag,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjClearFlagRequest) Reset() { *x = UIObjClearFlagRequest{} }
|
||||
func (x *UIObjClearFlagRequest) String() string { return "" }
|
||||
func (*UIObjClearFlagRequest) ProtoMessage() {}
|
||||
func (x *UIObjClearFlagRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjClearFlagResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjClearFlagResponse) Reset() { *x = UIObjClearFlagResponse{} }
|
||||
func (x *UIObjClearFlagResponse) String() string { return "" }
|
||||
func (*UIObjClearFlagResponse) ProtoMessage() {}
|
||||
func (x *UIObjClearFlagResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetOpacityRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Opacity int32 `protobuf:"varint,2,opt,name=opacity,proto3" json:"opacity,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetOpacityRequest) Reset() { *x = UIObjSetOpacityRequest{} }
|
||||
func (x *UIObjSetOpacityRequest) String() string { return "" }
|
||||
func (*UIObjSetOpacityRequest) ProtoMessage() {}
|
||||
func (x *UIObjSetOpacityRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetOpacityResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetOpacityResponse) Reset() { *x = UIObjSetOpacityResponse{} }
|
||||
func (x *UIObjSetOpacityResponse) String() string { return "" }
|
||||
func (*UIObjSetOpacityResponse) ProtoMessage() {}
|
||||
func (x *UIObjSetOpacityResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjFadeInRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Duration uint32 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjFadeInRequest) Reset() { *x = UIObjFadeInRequest{} }
|
||||
func (x *UIObjFadeInRequest) String() string { return "" }
|
||||
func (*UIObjFadeInRequest) ProtoMessage() {}
|
||||
func (x *UIObjFadeInRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjFadeInResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjFadeInResponse) Reset() { *x = UIObjFadeInResponse{} }
|
||||
func (x *UIObjFadeInResponse) String() string { return "" }
|
||||
func (*UIObjFadeInResponse) ProtoMessage() {}
|
||||
func (x *UIObjFadeInResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjFadeOutRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Duration uint32 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjFadeOutRequest) Reset() { *x = UIObjFadeOutRequest{} }
|
||||
func (x *UIObjFadeOutRequest) String() string { return "" }
|
||||
func (*UIObjFadeOutRequest) ProtoMessage() {}
|
||||
func (x *UIObjFadeOutRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjFadeOutResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjFadeOutResponse) Reset() { *x = UIObjFadeOutResponse{} }
|
||||
func (x *UIObjFadeOutResponse) String() string { return "" }
|
||||
func (*UIObjFadeOutResponse) ProtoMessage() {}
|
||||
func (x *UIObjFadeOutResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetLabelTextRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetLabelTextRequest) Reset() { *x = UIObjSetLabelTextRequest{} }
|
||||
func (x *UIObjSetLabelTextRequest) String() string { return "" }
|
||||
func (*UIObjSetLabelTextRequest) ProtoMessage() {}
|
||||
func (x *UIObjSetLabelTextRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetLabelTextResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetLabelTextResponse) Reset() { *x = UIObjSetLabelTextResponse{} }
|
||||
func (x *UIObjSetLabelTextResponse) String() string { return "" }
|
||||
func (*UIObjSetLabelTextResponse) ProtoMessage() {}
|
||||
func (x *UIObjSetLabelTextResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetImageSrcRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetImageSrcRequest) Reset() { *x = UIObjSetImageSrcRequest{} }
|
||||
func (x *UIObjSetImageSrcRequest) String() string { return "" }
|
||||
func (*UIObjSetImageSrcRequest) ProtoMessage() {}
|
||||
func (x *UIObjSetImageSrcRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UIObjSetImageSrcResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UIObjSetImageSrcResponse) Reset() { *x = UIObjSetImageSrcResponse{} }
|
||||
func (x *UIObjSetImageSrcResponse) String() string { return "" }
|
||||
func (*UIObjSetImageSrcResponse) ProtoMessage() {}
|
||||
func (x *UIObjSetImageSrcResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type DisplaySetRotationRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Rotation uint32 `protobuf:"varint,1,opt,name=rotation,proto3" json:"rotation,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DisplaySetRotationRequest) Reset() { *x = DisplaySetRotationRequest{} }
|
||||
func (x *DisplaySetRotationRequest) String() string { return "" }
|
||||
func (*DisplaySetRotationRequest) ProtoMessage() {}
|
||||
func (x *DisplaySetRotationRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type DisplaySetRotationResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DisplaySetRotationResponse) Reset() { *x = DisplaySetRotationResponse{} }
|
||||
func (x *DisplaySetRotationResponse) String() string { return "" }
|
||||
func (*DisplaySetRotationResponse) ProtoMessage() {}
|
||||
func (x *DisplaySetRotationResponse) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UpdateLabelIfChangedRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
NewText string `protobuf:"bytes,2,opt,name=new_text,json=newText,proto3" json:"new_text,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateLabelIfChangedRequest) Reset() { *x = UpdateLabelIfChangedRequest{} }
|
||||
func (x *UpdateLabelIfChangedRequest) String() string { return "" }
|
||||
func (*UpdateLabelIfChangedRequest) ProtoMessage() {}
|
||||
func (x *UpdateLabelIfChangedRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type UpdateLabelAndChangeVisibilityRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ObjName string `protobuf:"bytes,1,opt,name=obj_name,json=objName,proto3" json:"obj_name,omitempty"`
|
||||
NewText string `protobuf:"bytes,2,opt,name=new_text,json=newText,proto3" json:"new_text,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateLabelAndChangeVisibilityRequest) Reset() { *x = UpdateLabelAndChangeVisibilityRequest{} }
|
||||
func (x *UpdateLabelAndChangeVisibilityRequest) String() string { return "" }
|
||||
func (*UpdateLabelAndChangeVisibilityRequest) ProtoMessage() {}
|
||||
func (x *UpdateLabelAndChangeVisibilityRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type SwitchToScreenIfRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ScreenName string `protobuf:"bytes,1,opt,name=screen_name,json=screenName,proto3" json:"screen_name,omitempty"`
|
||||
ShouldSwitch []string `protobuf:"bytes,2,rep,name=should_switch,json=shouldSwitch,proto3" json:"should_switch,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SwitchToScreenIfRequest) Reset() { *x = SwitchToScreenIfRequest{} }
|
||||
func (x *SwitchToScreenIfRequest) String() string { return "" }
|
||||
func (*SwitchToScreenIfRequest) ProtoMessage() {}
|
||||
func (x *SwitchToScreenIfRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
||||
type SwitchToScreenIfDifferentRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
ScreenName string `protobuf:"bytes,1,opt,name=screen_name,json=screenName,proto3" json:"screen_name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SwitchToScreenIfDifferentRequest) Reset() { *x = SwitchToScreenIfDifferentRequest{} }
|
||||
func (x *SwitchToScreenIfDifferentRequest) String() string { return "" }
|
||||
func (*SwitchToScreenIfDifferentRequest) ProtoMessage() {}
|
||||
func (x *SwitchToScreenIfDifferentRequest) ProtoReflect() protoreflect.Message { return nil }
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package native;
|
||||
|
||||
option go_package = "github.com/jetkvm/kvm/internal/native/proto";
|
||||
|
||||
// NativeService provides methods to interact with the native layer
|
||||
service NativeService {
|
||||
// Init
|
||||
rpc Init(InitRequest) returns (InitResponse);
|
||||
|
||||
// Video methods
|
||||
rpc VideoSetSleepMode(VideoSetSleepModeRequest) returns (Empty);
|
||||
rpc VideoGetSleepMode(Empty) returns (VideoGetSleepModeResponse);
|
||||
rpc VideoSleepModeSupported(Empty) returns (VideoSleepModeSupportedResponse);
|
||||
rpc VideoSetQualityFactor(VideoSetQualityFactorRequest) returns (Empty);
|
||||
rpc VideoGetQualityFactor(Empty) returns (VideoGetQualityFactorResponse);
|
||||
rpc VideoSetEDID(VideoSetEDIDRequest) returns (Empty);
|
||||
rpc VideoGetEDID(Empty) returns (VideoGetEDIDResponse);
|
||||
rpc VideoLogStatus(Empty) returns (VideoLogStatusResponse);
|
||||
rpc VideoStop(Empty) returns (Empty);
|
||||
rpc VideoStart(Empty) returns (Empty);
|
||||
|
||||
// UI methods
|
||||
rpc GetLVGLVersion(Empty) returns (GetLVGLVersionResponse);
|
||||
rpc UIObjHide(UIObjHideRequest) returns (UIObjHideResponse);
|
||||
rpc UIObjShow(UIObjShowRequest) returns (UIObjShowResponse);
|
||||
rpc UISetVar(UISetVarRequest) returns (Empty);
|
||||
rpc UIGetVar(UIGetVarRequest) returns (UIGetVarResponse);
|
||||
rpc UIObjAddState(UIObjAddStateRequest) returns (UIObjAddStateResponse);
|
||||
rpc UIObjClearState(UIObjClearStateRequest) returns (UIObjClearStateResponse);
|
||||
rpc UIObjAddFlag(UIObjAddFlagRequest) returns (UIObjAddFlagResponse);
|
||||
rpc UIObjClearFlag(UIObjClearFlagRequest) returns (UIObjClearFlagResponse);
|
||||
rpc UIObjSetOpacity(UIObjSetOpacityRequest) returns (UIObjSetOpacityResponse);
|
||||
rpc UIObjFadeIn(UIObjFadeInRequest) returns (UIObjFadeInResponse);
|
||||
rpc UIObjFadeOut(UIObjFadeOutRequest) returns (UIObjFadeOutResponse);
|
||||
rpc UIObjSetLabelText(UIObjSetLabelTextRequest) returns (UIObjSetLabelTextResponse);
|
||||
rpc UIObjSetImageSrc(UIObjSetImageSrcRequest) returns (UIObjSetImageSrcResponse);
|
||||
rpc DisplaySetRotation(DisplaySetRotationRequest) returns (DisplaySetRotationResponse);
|
||||
rpc UpdateLabelIfChanged(UpdateLabelIfChangedRequest) returns (Empty);
|
||||
rpc UpdateLabelAndChangeVisibility(UpdateLabelAndChangeVisibilityRequest) returns (Empty);
|
||||
rpc SwitchToScreenIf(SwitchToScreenIfRequest) returns (Empty);
|
||||
rpc SwitchToScreenIfDifferent(SwitchToScreenIfDifferentRequest) returns (Empty);
|
||||
|
||||
// Testing
|
||||
rpc DoNotUseThisIsForCrashTestingOnly(Empty) returns (Empty);
|
||||
|
||||
// Events stream
|
||||
rpc StreamEvents(Empty) returns (stream Event);
|
||||
}
|
||||
|
||||
// Messages
|
||||
message Empty {}
|
||||
|
||||
message InitRequest {
|
||||
string system_version = 1;
|
||||
string app_version = 2;
|
||||
uint32 display_rotation = 3;
|
||||
double default_quality_factor = 4;
|
||||
}
|
||||
|
||||
message InitResponse {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message VideoState {
|
||||
bool ready = 1;
|
||||
string error = 2;
|
||||
int32 width = 3;
|
||||
int32 height = 4;
|
||||
double frame_per_second = 5;
|
||||
}
|
||||
|
||||
message VideoSetSleepModeRequest {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
message VideoGetSleepModeResponse {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
message VideoSleepModeSupportedResponse {
|
||||
bool supported = 1;
|
||||
}
|
||||
|
||||
message VideoSetQualityFactorRequest {
|
||||
double factor = 1;
|
||||
}
|
||||
|
||||
message VideoGetQualityFactorResponse {
|
||||
double factor = 1;
|
||||
}
|
||||
|
||||
message VideoSetEDIDRequest {
|
||||
string edid = 1;
|
||||
}
|
||||
|
||||
message VideoGetEDIDResponse {
|
||||
string edid = 1;
|
||||
}
|
||||
|
||||
message VideoLogStatusResponse {
|
||||
string status = 1;
|
||||
}
|
||||
|
||||
message GetLVGLVersionResponse {
|
||||
string version = 1;
|
||||
}
|
||||
|
||||
message UIObjHideRequest {
|
||||
string obj_name = 1;
|
||||
}
|
||||
|
||||
message UIObjHideResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjShowRequest {
|
||||
string obj_name = 1;
|
||||
}
|
||||
|
||||
message UIObjShowResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UISetVarRequest {
|
||||
string name = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message UIGetVarRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message UIGetVarResponse {
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
message UIObjAddStateRequest {
|
||||
string obj_name = 1;
|
||||
string state = 2;
|
||||
}
|
||||
|
||||
message UIObjAddStateResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjClearStateRequest {
|
||||
string obj_name = 1;
|
||||
string state = 2;
|
||||
}
|
||||
|
||||
message UIObjClearStateResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjAddFlagRequest {
|
||||
string obj_name = 1;
|
||||
string flag = 2;
|
||||
}
|
||||
|
||||
message UIObjAddFlagResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjClearFlagRequest {
|
||||
string obj_name = 1;
|
||||
string flag = 2;
|
||||
}
|
||||
|
||||
message UIObjClearFlagResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjSetOpacityRequest {
|
||||
string obj_name = 1;
|
||||
int32 opacity = 2;
|
||||
}
|
||||
|
||||
message UIObjSetOpacityResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjFadeInRequest {
|
||||
string obj_name = 1;
|
||||
uint32 duration = 2;
|
||||
}
|
||||
|
||||
message UIObjFadeInResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjFadeOutRequest {
|
||||
string obj_name = 1;
|
||||
uint32 duration = 2;
|
||||
}
|
||||
|
||||
message UIObjFadeOutResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjSetLabelTextRequest {
|
||||
string obj_name = 1;
|
||||
string text = 2;
|
||||
}
|
||||
|
||||
message UIObjSetLabelTextResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UIObjSetImageSrcRequest {
|
||||
string obj_name = 1;
|
||||
string image = 2;
|
||||
}
|
||||
|
||||
message UIObjSetImageSrcResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DisplaySetRotationRequest {
|
||||
uint32 rotation = 1;
|
||||
}
|
||||
|
||||
message DisplaySetRotationResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message UpdateLabelIfChangedRequest {
|
||||
string obj_name = 1;
|
||||
string new_text = 2;
|
||||
}
|
||||
|
||||
message UpdateLabelAndChangeVisibilityRequest {
|
||||
string obj_name = 1;
|
||||
string new_text = 2;
|
||||
}
|
||||
|
||||
message SwitchToScreenIfRequest {
|
||||
string screen_name = 1;
|
||||
repeated string should_switch = 2;
|
||||
}
|
||||
|
||||
message SwitchToScreenIfDifferentRequest {
|
||||
string screen_name = 1;
|
||||
}
|
||||
|
||||
message Event {
|
||||
string type = 1;
|
||||
oneof data {
|
||||
VideoState video_state = 2;
|
||||
string indev_event = 3;
|
||||
string rpc_event = 4;
|
||||
VideoFrame video_frame = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message VideoFrame {
|
||||
bytes frame = 1;
|
||||
int64 duration_ns = 2;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,492 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// This is a placeholder file. Run: protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative internal/native/proto/native.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// NativeServiceClient is the client API for NativeService service.
|
||||
type NativeServiceClient interface {
|
||||
// Video methods
|
||||
VideoSetSleepMode(ctx context.Context, in *VideoSetSleepModeRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
VideoGetSleepMode(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetSleepModeResponse, error)
|
||||
VideoSleepModeSupported(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoSleepModeSupportedResponse, error)
|
||||
VideoSetQualityFactor(ctx context.Context, in *VideoSetQualityFactorRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
VideoGetQualityFactor(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetQualityFactorResponse, error)
|
||||
VideoSetEDID(ctx context.Context, in *VideoSetEDIDRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
VideoGetEDID(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetEDIDResponse, error)
|
||||
VideoLogStatus(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoLogStatusResponse, error)
|
||||
VideoStop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
|
||||
VideoStart(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
|
||||
// UI methods
|
||||
GetLVGLVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetLVGLVersionResponse, error)
|
||||
UIObjHide(ctx context.Context, in *UIObjHideRequest, opts ...grpc.CallOption) (*UIObjHideResponse, error)
|
||||
UIObjShow(ctx context.Context, in *UIObjShowRequest, opts ...grpc.CallOption) (*UIObjShowResponse, error)
|
||||
UISetVar(ctx context.Context, in *UISetVarRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
UIGetVar(ctx context.Context, in *UIGetVarRequest, opts ...grpc.CallOption) (*UIGetVarResponse, error)
|
||||
UIObjAddState(ctx context.Context, in *UIObjAddStateRequest, opts ...grpc.CallOption) (*UIObjAddStateResponse, error)
|
||||
UIObjClearState(ctx context.Context, in *UIObjClearStateRequest, opts ...grpc.CallOption) (*UIObjClearStateResponse, error)
|
||||
UIObjAddFlag(ctx context.Context, in *UIObjAddFlagRequest, opts ...grpc.CallOption) (*UIObjAddFlagResponse, error)
|
||||
UIObjClearFlag(ctx context.Context, in *UIObjClearFlagRequest, opts ...grpc.CallOption) (*UIObjClearFlagResponse, error)
|
||||
UIObjSetOpacity(ctx context.Context, in *UIObjSetOpacityRequest, opts ...grpc.CallOption) (*UIObjSetOpacityResponse, error)
|
||||
UIObjFadeIn(ctx context.Context, in *UIObjFadeInRequest, opts ...grpc.CallOption) (*UIObjFadeInResponse, error)
|
||||
UIObjFadeOut(ctx context.Context, in *UIObjFadeOutRequest, opts ...grpc.CallOption) (*UIObjFadeOutResponse, error)
|
||||
UIObjSetLabelText(ctx context.Context, in *UIObjSetLabelTextRequest, opts ...grpc.CallOption) (*UIObjSetLabelTextResponse, error)
|
||||
UIObjSetImageSrc(ctx context.Context, in *UIObjSetImageSrcRequest, opts ...grpc.CallOption) (*UIObjSetImageSrcResponse, error)
|
||||
DisplaySetRotation(ctx context.Context, in *DisplaySetRotationRequest, opts ...grpc.CallOption) (*DisplaySetRotationResponse, error)
|
||||
UpdateLabelIfChanged(ctx context.Context, in *UpdateLabelIfChangedRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
UpdateLabelAndChangeVisibility(ctx context.Context, in *UpdateLabelAndChangeVisibilityRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
SwitchToScreenIf(ctx context.Context, in *SwitchToScreenIfRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
SwitchToScreenIfDifferent(ctx context.Context, in *SwitchToScreenIfDifferentRequest, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Testing
|
||||
DoNotUseThisIsForCrashTestingOnly(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Events stream
|
||||
StreamEvents(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NativeService_StreamEventsClient, error)
|
||||
}
|
||||
|
||||
type nativeServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewNativeServiceClient(cc grpc.ClientConnInterface) NativeServiceClient {
|
||||
return &nativeServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoSetSleepMode(ctx context.Context, in *VideoSetSleepModeRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoSetSleepMode", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoGetSleepMode(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetSleepModeResponse, error) {
|
||||
out := new(VideoGetSleepModeResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoGetSleepMode", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoSleepModeSupported(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoSleepModeSupportedResponse, error) {
|
||||
out := new(VideoSleepModeSupportedResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoSleepModeSupported", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoSetQualityFactor(ctx context.Context, in *VideoSetQualityFactorRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoSetQualityFactor", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoGetQualityFactor(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetQualityFactorResponse, error) {
|
||||
out := new(VideoGetQualityFactorResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoGetQualityFactor", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoSetEDID(ctx context.Context, in *VideoSetEDIDRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoSetEDID", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoGetEDID(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetEDIDResponse, error) {
|
||||
out := new(VideoGetEDIDResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoGetEDID", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoLogStatus(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoLogStatusResponse, error) {
|
||||
out := new(VideoLogStatusResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoLogStatus", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoStop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoStop", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) VideoStart(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/VideoStart", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) GetLVGLVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetLVGLVersionResponse, error) {
|
||||
out := new(GetLVGLVersionResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/GetLVGLVersion", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjHide(ctx context.Context, in *UIObjHideRequest, opts ...grpc.CallOption) (*UIObjHideResponse, error) {
|
||||
out := new(UIObjHideResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjHide", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjShow(ctx context.Context, in *UIObjShowRequest, opts ...grpc.CallOption) (*UIObjShowResponse, error) {
|
||||
out := new(UIObjShowResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjShow", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UISetVar(ctx context.Context, in *UISetVarRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UISetVar", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIGetVar(ctx context.Context, in *UIGetVarRequest, opts ...grpc.CallOption) (*UIGetVarResponse, error) {
|
||||
out := new(UIGetVarResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIGetVar", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjAddState(ctx context.Context, in *UIObjAddStateRequest, opts ...grpc.CallOption) (*UIObjAddStateResponse, error) {
|
||||
out := new(UIObjAddStateResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjAddState", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjClearState(ctx context.Context, in *UIObjClearStateRequest, opts ...grpc.CallOption) (*UIObjClearStateResponse, error) {
|
||||
out := new(UIObjClearStateResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjClearState", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjAddFlag(ctx context.Context, in *UIObjAddFlagRequest, opts ...grpc.CallOption) (*UIObjAddFlagResponse, error) {
|
||||
out := new(UIObjAddFlagResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjAddFlag", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjClearFlag(ctx context.Context, in *UIObjClearFlagRequest, opts ...grpc.CallOption) (*UIObjClearFlagResponse, error) {
|
||||
out := new(UIObjClearFlagResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjClearFlag", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjSetOpacity(ctx context.Context, in *UIObjSetOpacityRequest, opts ...grpc.CallOption) (*UIObjSetOpacityResponse, error) {
|
||||
out := new(UIObjSetOpacityResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjSetOpacity", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjFadeIn(ctx context.Context, in *UIObjFadeInRequest, opts ...grpc.CallOption) (*UIObjFadeInResponse, error) {
|
||||
out := new(UIObjFadeInResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjFadeIn", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjFadeOut(ctx context.Context, in *UIObjFadeOutRequest, opts ...grpc.CallOption) (*UIObjFadeOutResponse, error) {
|
||||
out := new(UIObjFadeOutResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjFadeOut", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjSetLabelText(ctx context.Context, in *UIObjSetLabelTextRequest, opts ...grpc.CallOption) (*UIObjSetLabelTextResponse, error) {
|
||||
out := new(UIObjSetLabelTextResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjSetLabelText", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UIObjSetImageSrc(ctx context.Context, in *UIObjSetImageSrcRequest, opts ...grpc.CallOption) (*UIObjSetImageSrcResponse, error) {
|
||||
out := new(UIObjSetImageSrcResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UIObjSetImageSrc", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) DisplaySetRotation(ctx context.Context, in *DisplaySetRotationRequest, opts ...grpc.CallOption) (*DisplaySetRotationResponse, error) {
|
||||
out := new(DisplaySetRotationResponse)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/DisplaySetRotation", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UpdateLabelIfChanged(ctx context.Context, in *UpdateLabelIfChangedRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UpdateLabelIfChanged", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) UpdateLabelAndChangeVisibility(ctx context.Context, in *UpdateLabelAndChangeVisibilityRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/UpdateLabelAndChangeVisibility", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) SwitchToScreenIf(ctx context.Context, in *SwitchToScreenIfRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/SwitchToScreenIf", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) SwitchToScreenIfDifferent(ctx context.Context, in *SwitchToScreenIfDifferentRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/SwitchToScreenIfDifferent", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) DoNotUseThisIsForCrashTestingOnly(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/native.NativeService/DoNotUseThisIsForCrashTestingOnly", in, out, opts...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *nativeServiceClient) StreamEvents(ctx context.Context, in *Empty, opts ...grpc.CallOption) (NativeService_StreamEventsClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &NativeService_ServiceDesc.Streams[0], "/native.NativeService/StreamEvents", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &nativeServiceStreamEventsClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type NativeService_StreamEventsClient interface {
|
||||
Recv() (*Event, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type nativeServiceStreamEventsClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *nativeServiceStreamEventsClient) Recv() (*Event, error) {
|
||||
m := new(Event)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// NativeServiceServer is the server API for NativeService service.
|
||||
type NativeServiceServer interface {
|
||||
// Video methods
|
||||
VideoSetSleepMode(context.Context, *VideoSetSleepModeRequest) (*Empty, error)
|
||||
VideoGetSleepMode(context.Context, *Empty) (*VideoGetSleepModeResponse, error)
|
||||
VideoSleepModeSupported(context.Context, *Empty) (*VideoSleepModeSupportedResponse, error)
|
||||
VideoSetQualityFactor(context.Context, *VideoSetQualityFactorRequest) (*Empty, error)
|
||||
VideoGetQualityFactor(context.Context, *Empty) (*VideoGetQualityFactorResponse, error)
|
||||
VideoSetEDID(context.Context, *VideoSetEDIDRequest) (*Empty, error)
|
||||
VideoGetEDID(context.Context, *Empty) (*VideoGetEDIDResponse, error)
|
||||
VideoLogStatus(context.Context, *Empty) (*VideoLogStatusResponse, error)
|
||||
VideoStop(context.Context, *Empty) (*Empty, error)
|
||||
VideoStart(context.Context, *Empty) (*Empty, error)
|
||||
// UI methods
|
||||
GetLVGLVersion(context.Context, *Empty) (*GetLVGLVersionResponse, error)
|
||||
UIObjHide(context.Context, *UIObjHideRequest) (*UIObjHideResponse, error)
|
||||
UIObjShow(context.Context, *UIObjShowRequest) (*UIObjShowResponse, error)
|
||||
UISetVar(context.Context, *UISetVarRequest) (*Empty, error)
|
||||
UIGetVar(context.Context, *UIGetVarRequest) (*UIGetVarResponse, error)
|
||||
UIObjAddState(context.Context, *UIObjAddStateRequest) (*UIObjAddStateResponse, error)
|
||||
UIObjClearState(context.Context, *UIObjClearStateRequest) (*UIObjClearStateResponse, error)
|
||||
UIObjAddFlag(context.Context, *UIObjAddFlagRequest) (*UIObjAddFlagResponse, error)
|
||||
UIObjClearFlag(context.Context, *UIObjClearFlagRequest) (*UIObjClearFlagResponse, error)
|
||||
UIObjSetOpacity(context.Context, *UIObjSetOpacityRequest) (*UIObjSetOpacityResponse, error)
|
||||
UIObjFadeIn(context.Context, *UIObjFadeInRequest) (*UIObjFadeInResponse, error)
|
||||
UIObjFadeOut(context.Context, *UIObjFadeOutRequest) (*UIObjFadeOutResponse, error)
|
||||
UIObjSetLabelText(context.Context, *UIObjSetLabelTextRequest) (*UIObjSetLabelTextResponse, error)
|
||||
UIObjSetImageSrc(context.Context, *UIObjSetImageSrcRequest) (*UIObjSetImageSrcResponse, error)
|
||||
DisplaySetRotation(context.Context, *DisplaySetRotationRequest) (*DisplaySetRotationResponse, error)
|
||||
UpdateLabelIfChanged(context.Context, *UpdateLabelIfChangedRequest) (*Empty, error)
|
||||
UpdateLabelAndChangeVisibility(context.Context, *UpdateLabelAndChangeVisibilityRequest) (*Empty, error)
|
||||
SwitchToScreenIf(context.Context, *SwitchToScreenIfRequest) (*Empty, error)
|
||||
SwitchToScreenIfDifferent(context.Context, *SwitchToScreenIfDifferentRequest) (*Empty, error)
|
||||
// Testing
|
||||
DoNotUseThisIsForCrashTestingOnly(context.Context, *Empty) (*Empty, error)
|
||||
// Events stream
|
||||
StreamEvents(*Empty, NativeService_StreamEventsServer) error
|
||||
mustEmbedUnimplementedNativeServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedNativeServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedNativeServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoSetSleepMode(context.Context, *VideoSetSleepModeRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoSetSleepMode not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoGetSleepMode(context.Context, *Empty) (*VideoGetSleepModeResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoGetSleepMode not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoSleepModeSupported(context.Context, *Empty) (*VideoSleepModeSupportedResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoSleepModeSupported not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoSetQualityFactor(context.Context, *VideoSetQualityFactorRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoSetQualityFactor not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoGetQualityFactor(context.Context, *Empty) (*VideoGetQualityFactorResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoGetQualityFactor not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoSetEDID(context.Context, *VideoSetEDIDRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoSetEDID not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoGetEDID(context.Context, *Empty) (*VideoGetEDIDResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoGetEDID not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoLogStatus(context.Context, *Empty) (*VideoLogStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoLogStatus not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoStop(context.Context, *Empty) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoStop not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) VideoStart(context.Context, *Empty) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method VideoStart not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) GetLVGLVersion(context.Context, *Empty) (*GetLVGLVersionResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetLVGLVersion not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjHide(context.Context, *UIObjHideRequest) (*UIObjHideResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjHide not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjShow(context.Context, *UIObjShowRequest) (*UIObjShowResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjShow not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UISetVar(context.Context, *UISetVarRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UISetVar not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIGetVar(context.Context, *UIGetVarRequest) (*UIGetVarResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIGetVar not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjAddState(context.Context, *UIObjAddStateRequest) (*UIObjAddStateResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjAddState not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjClearState(context.Context, *UIObjClearStateRequest) (*UIObjClearStateResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjClearState not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjAddFlag(context.Context, *UIObjAddFlagRequest) (*UIObjAddFlagResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjAddFlag not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjClearFlag(context.Context, *UIObjClearFlagRequest) (*UIObjClearFlagResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjClearFlag not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjSetOpacity(context.Context, *UIObjSetOpacityRequest) (*UIObjSetOpacityResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjSetOpacity not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjFadeIn(context.Context, *UIObjFadeInRequest) (*UIObjFadeInResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjFadeIn not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjFadeOut(context.Context, *UIObjFadeOutRequest) (*UIObjFadeOutResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjFadeOut not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjSetLabelText(context.Context, *UIObjSetLabelTextRequest) (*UIObjSetLabelTextResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjSetLabelText not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UIObjSetImageSrc(context.Context, *UIObjSetImageSrcRequest) (*UIObjSetImageSrcResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UIObjSetImageSrc not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) DisplaySetRotation(context.Context, *DisplaySetRotationRequest) (*DisplaySetRotationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DisplaySetRotation not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UpdateLabelIfChanged(context.Context, *UpdateLabelIfChangedRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateLabelIfChanged not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) UpdateLabelAndChangeVisibility(context.Context, *UpdateLabelAndChangeVisibilityRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateLabelAndChangeVisibility not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) SwitchToScreenIf(context.Context, *SwitchToScreenIfRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SwitchToScreenIf not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) SwitchToScreenIfDifferent(context.Context, *SwitchToScreenIfDifferentRequest) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SwitchToScreenIfDifferent not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) DoNotUseThisIsForCrashTestingOnly(context.Context, *Empty) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DoNotUseThisIsForCrashTestingOnly not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) StreamEvents(*Empty, NativeService_StreamEventsServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamEvents not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedNativeServiceServer) mustEmbedUnimplementedNativeServiceServer() {}
|
||||
|
||||
// UnsafeNativeServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to NativeServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeNativeServiceServer interface {
|
||||
mustEmbedUnimplementedNativeServiceServer()
|
||||
}
|
||||
|
||||
func RegisterNativeServiceServer(s grpc.ServiceRegistrar, srv NativeServiceServer) {
|
||||
s.RegisterService(&NativeService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
type NativeService_StreamEventsServer interface {
|
||||
Send(*Event) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type nativeServiceStreamEventsServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *nativeServiceStreamEventsServer) Send(m *Event) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
// NativeService_ServiceDesc is the grpc.ServiceDesc for NativeService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var NativeService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "native.NativeService",
|
||||
HandlerType: (*NativeServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "VideoSetSleepMode",
|
||||
Handler: nil, // Will be set by RegisterNativeServiceServer
|
||||
},
|
||||
// Additional methods will be registered here
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "StreamEvents",
|
||||
Handler: nil, // Will be set by RegisterNativeServiceServer
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "native.proto",
|
||||
}
|
||||
|
|
@ -0,0 +1,682 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/jetkvm/kvm/internal/supervisor"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// cmdWrapper wraps exec.Cmd to implement processCmd interface
|
||||
type cmdWrapper struct {
|
||||
*exec.Cmd
|
||||
}
|
||||
|
||||
func (c *cmdWrapper) GetProcess() interface {
|
||||
Kill() error
|
||||
Signal(sig interface{}) error
|
||||
} {
|
||||
return &processWrapper{Process: c.Cmd.Process}
|
||||
}
|
||||
|
||||
type processWrapper struct {
|
||||
*os.Process
|
||||
}
|
||||
|
||||
func (p *processWrapper) Signal(sig interface{}) error {
|
||||
if sig == nil {
|
||||
// Check if process is alive by sending signal 0
|
||||
return p.Process.Signal(os.Signal(syscall.Signal(0)))
|
||||
}
|
||||
if s, ok := sig.(os.Signal); ok {
|
||||
return p.Process.Signal(s)
|
||||
}
|
||||
return fmt.Errorf("invalid signal type")
|
||||
}
|
||||
|
||||
// NativeProxy is a proxy that communicates with a separate native process
|
||||
type NativeProxy struct {
|
||||
client *IPCClient
|
||||
cmd *exec.Cmd
|
||||
wrapped *cmdWrapper
|
||||
logger *zerolog.Logger
|
||||
ready chan struct{}
|
||||
restartM sync.Mutex
|
||||
stopped bool
|
||||
opts NativeProxyOptions
|
||||
binaryPath string
|
||||
configJSON []byte
|
||||
processWait chan error
|
||||
}
|
||||
|
||||
// NativeProxyOptions are options for creating a NativeProxy
|
||||
type NativeProxyOptions struct {
|
||||
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)
|
||||
OnRpcEvent func(event string)
|
||||
Logger *zerolog.Logger
|
||||
}
|
||||
|
||||
// NewNativeProxy creates a new NativeProxy that spawns a separate process
|
||||
func NewNativeProxy(opts NativeProxyOptions) (*NativeProxy, error) {
|
||||
if opts.Logger == nil {
|
||||
opts.Logger = nativeLogger
|
||||
}
|
||||
|
||||
// Get the current executable path to spawn itself
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get executable path: %w", err)
|
||||
}
|
||||
binaryPath := exePath
|
||||
|
||||
config := ProcessConfig{
|
||||
Disable: opts.Disable,
|
||||
SystemVersion: "",
|
||||
AppVersion: "",
|
||||
DisplayRotation: opts.DisplayRotation,
|
||||
DefaultQualityFactor: opts.DefaultQualityFactor,
|
||||
}
|
||||
if opts.SystemVersion != nil {
|
||||
config.SystemVersion = opts.SystemVersion.String()
|
||||
}
|
||||
if opts.AppVersion != nil {
|
||||
config.AppVersion = opts.AppVersion.String()
|
||||
}
|
||||
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal config: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(binaryPath, string(configJSON))
|
||||
cmd.Stderr = os.Stderr // Forward stderr to parent
|
||||
// Set environment variable to indicate native process mode
|
||||
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=native", supervisor.EnvSubcomponent))
|
||||
|
||||
// Wrap cmd to implement processCmd interface
|
||||
wrappedCmd := &cmdWrapper{Cmd: cmd}
|
||||
|
||||
client, err := NewIPCClient(wrappedCmd, opts.Logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create IPC client: %w", err)
|
||||
}
|
||||
|
||||
proxy := &NativeProxy{
|
||||
client: client,
|
||||
cmd: cmd,
|
||||
wrapped: wrappedCmd,
|
||||
logger: opts.Logger,
|
||||
ready: make(chan struct{}),
|
||||
opts: opts,
|
||||
binaryPath: binaryPath,
|
||||
configJSON: configJSON,
|
||||
processWait: make(chan error, 1),
|
||||
}
|
||||
|
||||
// Set up event handlers
|
||||
proxy.setupEventHandlers(client)
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
// Start starts the native process
|
||||
func (p *NativeProxy) Start() error {
|
||||
p.restartM.Lock()
|
||||
defer p.restartM.Unlock()
|
||||
|
||||
if p.stopped {
|
||||
return fmt.Errorf("proxy is stopped")
|
||||
}
|
||||
|
||||
if err := p.cmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start native process: %w", err)
|
||||
}
|
||||
|
||||
// Wait for ready signal from the native process
|
||||
if err := p.client.WaitReady(); err != nil {
|
||||
// Clean up if ready failed
|
||||
if p.cmd.Process != nil {
|
||||
_ = p.cmd.Process.Kill()
|
||||
_ = p.cmd.Wait()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Start monitoring process for crashes
|
||||
go p.monitorProcess()
|
||||
|
||||
close(p.ready)
|
||||
return nil
|
||||
}
|
||||
|
||||
// monitorProcess monitors the native process and restarts it if it crashes
|
||||
func (p *NativeProxy) monitorProcess() {
|
||||
for {
|
||||
p.restartM.Lock()
|
||||
cmd := p.cmd
|
||||
stopped := p.stopped
|
||||
p.restartM.Unlock()
|
||||
|
||||
if stopped {
|
||||
return
|
||||
}
|
||||
|
||||
if cmd == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := cmd.Wait()
|
||||
select {
|
||||
case p.processWait <- err:
|
||||
default:
|
||||
}
|
||||
|
||||
p.restartM.Lock()
|
||||
if p.stopped {
|
||||
p.restartM.Unlock()
|
||||
return
|
||||
}
|
||||
p.restartM.Unlock()
|
||||
|
||||
p.logger.Warn().Err(err).Msg("native process exited, restarting...")
|
||||
|
||||
// Wait a bit before restarting
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Restart the process
|
||||
if err := p.restartProcess(); err != nil {
|
||||
p.logger.Error().Err(err).Msg("failed to restart native process")
|
||||
// Wait longer before retrying
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restartProcess restarts the native process
|
||||
func (p *NativeProxy) restartProcess() error {
|
||||
p.restartM.Lock()
|
||||
defer p.restartM.Unlock()
|
||||
|
||||
if p.stopped {
|
||||
return fmt.Errorf("proxy is stopped")
|
||||
}
|
||||
|
||||
// Create new command
|
||||
cmd := exec.Command(p.binaryPath, string(p.configJSON))
|
||||
cmd.Stderr = os.Stderr
|
||||
// Set environment variable to indicate native process mode
|
||||
cmd.Env = append(os.Environ(), "JETKVM_NATIVE_PROCESS=1")
|
||||
|
||||
// Wrap cmd to implement processCmd interface
|
||||
wrappedCmd := &cmdWrapper{Cmd: cmd}
|
||||
|
||||
// Close old client
|
||||
if p.client != nil {
|
||||
_ = p.client.Close()
|
||||
}
|
||||
|
||||
// Create new client
|
||||
client, err := NewIPCClient(wrappedCmd, p.logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create IPC client: %w", err)
|
||||
}
|
||||
|
||||
// Set up event handlers again
|
||||
p.setupEventHandlers(client)
|
||||
|
||||
// Start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start native process: %w", err)
|
||||
}
|
||||
|
||||
// Wait for ready
|
||||
if err := client.WaitReady(); err != nil {
|
||||
if cmd.Process != nil {
|
||||
_ = cmd.Process.Kill()
|
||||
_ = cmd.Wait()
|
||||
}
|
||||
return fmt.Errorf("timeout waiting for ready: %w", err)
|
||||
}
|
||||
|
||||
p.cmd = cmd
|
||||
p.wrapped = wrappedCmd
|
||||
p.client = client
|
||||
|
||||
p.logger.Info().Msg("native process restarted successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) setupEventHandlers(client *IPCClient) {
|
||||
if p.opts.OnVideoStateChange != nil {
|
||||
client.OnEvent("video_state_change", func(data interface{}) {
|
||||
dataBytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
p.logger.Warn().Err(err).Msg("failed to marshal video state event")
|
||||
return
|
||||
}
|
||||
var state VideoState
|
||||
if err := json.Unmarshal(dataBytes, &state); err != nil {
|
||||
p.logger.Warn().Err(err).Msg("failed to unmarshal video state event")
|
||||
return
|
||||
}
|
||||
p.opts.OnVideoStateChange(state)
|
||||
})
|
||||
}
|
||||
|
||||
if p.opts.OnIndevEvent != nil {
|
||||
client.OnEvent("indev_event", func(data interface{}) {
|
||||
if event, ok := data.(string); ok {
|
||||
p.opts.OnIndevEvent(event)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if p.opts.OnRpcEvent != nil {
|
||||
client.OnEvent("rpc_event", func(data interface{}) {
|
||||
if event, ok := data.(string); ok {
|
||||
p.opts.OnRpcEvent(event)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if p.opts.OnVideoFrameReceived != nil {
|
||||
client.OnEvent("video_frame", func(data interface{}) {
|
||||
dataMap, ok := data.(map[string]interface{})
|
||||
if !ok {
|
||||
p.logger.Warn().Msg("invalid video frame event data")
|
||||
return
|
||||
}
|
||||
|
||||
frameData, ok := dataMap["frame"].([]interface{})
|
||||
if !ok {
|
||||
p.logger.Warn().Msg("invalid frame data in event")
|
||||
return
|
||||
}
|
||||
|
||||
frame := make([]byte, len(frameData))
|
||||
for i, v := range frameData {
|
||||
if b, ok := v.(float64); ok {
|
||||
frame[i] = byte(b)
|
||||
}
|
||||
}
|
||||
|
||||
durationNs, ok := dataMap["duration"].(float64)
|
||||
if !ok {
|
||||
p.logger.Warn().Msg("invalid duration in event")
|
||||
return
|
||||
}
|
||||
|
||||
p.opts.OnVideoFrameReceived(frame, time.Duration(durationNs))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the native process
|
||||
func (p *NativeProxy) Stop() error {
|
||||
p.restartM.Lock()
|
||||
defer p.restartM.Unlock()
|
||||
|
||||
p.stopped = true
|
||||
|
||||
if err := p.client.Close(); err != nil {
|
||||
p.logger.Warn().Err(err).Msg("failed to close IPC client")
|
||||
}
|
||||
|
||||
if p.cmd.Process != nil {
|
||||
if err := p.cmd.Process.Kill(); err != nil {
|
||||
return fmt.Errorf("failed to kill native process: %w", err)
|
||||
}
|
||||
_ = p.cmd.Wait()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implement all Native methods by forwarding to IPC
|
||||
|
||||
func (p *NativeProxy) VideoSetSleepMode(enabled bool) error {
|
||||
_, err := p.client.Call("VideoSetSleepMode", map[string]interface{}{
|
||||
"enabled": enabled,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoGetSleepMode() (bool, error) {
|
||||
resp, err := p.client.Call("VideoGetSleepMode", nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoSleepModeSupported() bool {
|
||||
resp, err := p.client.Call("VideoSleepModeSupported", nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoSetQualityFactor(factor float64) error {
|
||||
_, err := p.client.Call("VideoSetQualityFactor", map[string]interface{}{
|
||||
"factor": factor,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoGetQualityFactor() (float64, error) {
|
||||
resp, err := p.client.Call("VideoGetQualityFactor", nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
result, ok := resp.Result.(float64)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoSetEDID(edid string) error {
|
||||
_, err := p.client.Call("VideoSetEDID", map[string]interface{}{
|
||||
"edid": edid,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoGetEDID() (string, error) {
|
||||
resp, err := p.client.Call("VideoGetEDID", nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, ok := resp.Result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoLogStatus() (string, error) {
|
||||
resp, err := p.client.Call("VideoLogStatus", nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, ok := resp.Result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoStop() error {
|
||||
_, err := p.client.Call("VideoStop", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *NativeProxy) VideoStart() error {
|
||||
_, err := p.client.Call("VideoStart", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *NativeProxy) GetLVGLVersion() (string, error) {
|
||||
resp, err := p.client.Call("GetLVGLVersion", nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, ok := resp.Result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjHide(objName string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjHide", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjShow(objName string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjShow", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UISetVar(name string, value string) {
|
||||
_, _ = p.client.Call("UISetVar", map[string]interface{}{
|
||||
"name": name,
|
||||
"value": value,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIGetVar(name string) string {
|
||||
resp, err := p.client.Call("UIGetVar", map[string]interface{}{
|
||||
"name": name,
|
||||
})
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
result, ok := resp.Result.(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjAddState(objName string, state string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjAddState", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"state": state,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjClearState(objName string, state string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjClearState", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"state": state,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjAddFlag(objName string, flag string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjAddFlag", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"flag": flag,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjClearFlag(objName string, flag string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjClearFlag", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"flag": flag,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjSetOpacity(objName string, opacity int) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjSetOpacity", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"opacity": opacity,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjFadeIn(objName string, duration uint32) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjFadeIn", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"duration": duration,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjFadeOut(objName string, duration uint32) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjFadeOut", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"duration": duration,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjSetLabelText(objName string, text string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjSetLabelText", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"text": text,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UIObjSetImageSrc(objName string, image string) (bool, error) {
|
||||
resp, err := p.client.Call("UIObjSetImageSrc", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"image": image,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) DisplaySetRotation(rotation uint16) (bool, error) {
|
||||
resp, err := p.client.Call("DisplaySetRotation", map[string]interface{}{
|
||||
"rotation": rotation,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, ok := resp.Result.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid response type")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UpdateLabelIfChanged(objName string, newText string) {
|
||||
_, _ = p.client.Call("UpdateLabelIfChanged", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"new_text": newText,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *NativeProxy) UpdateLabelAndChangeVisibility(objName string, newText string) {
|
||||
_, _ = p.client.Call("UpdateLabelAndChangeVisibility", map[string]interface{}{
|
||||
"obj_name": objName,
|
||||
"new_text": newText,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *NativeProxy) SwitchToScreenIf(screenName string, shouldSwitch []string) {
|
||||
_, _ = p.client.Call("SwitchToScreenIf", map[string]interface{}{
|
||||
"screen_name": screenName,
|
||||
"should_switch": shouldSwitch,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *NativeProxy) SwitchToScreenIfDifferent(screenName string) {
|
||||
_, _ = p.client.Call("SwitchToScreenIfDifferent", map[string]interface{}{
|
||||
"screen_name": screenName,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *NativeProxy) DoNotUseThisIsForCrashTestingOnly() {
|
||||
_, _ = p.client.Call("DoNotUseThisIsForCrashTestingOnly", nil)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package supervisor
|
||||
|
||||
const (
|
||||
EnvChildID = "JETKVM_CHILD_ID" // The child ID is the version of the app that is running
|
||||
EnvSubcomponent = "JETKVM_SUBCOMPONENT" // The subcomponent is the component that is running
|
||||
ErrorDumpDir = "/userdata/jetkvm/crashdump" // The error dump directory is the directory where the error dumps are stored
|
||||
ErrorDumpLastFile = "last-crash.log" // The error dump last file is the last error dump file
|
||||
ErrorDumpTemplate = "jetkvm-%s.log" // The error dump template is the template for the error dump file
|
||||
)
|
||||
13
native.go
13
native.go
|
|
@ -11,17 +11,19 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
nativeInstance *native.Native
|
||||
nativeInstance native.NativeInterface
|
||||
nativeCmdLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
func initNative(systemVersion *semver.Version, appVersion *semver.Version) {
|
||||
nativeInstance = native.NewNative(native.NativeOptions{
|
||||
var err error
|
||||
nativeInstance, err = native.NewNativeProxy(native.NativeProxyOptions{
|
||||
Disable: failsafeModeActive,
|
||||
SystemVersion: systemVersion,
|
||||
AppVersion: appVersion,
|
||||
DisplayRotation: config.GetDisplayRotation(),
|
||||
DefaultQualityFactor: config.VideoQualityFactor,
|
||||
Logger: nativeLogger,
|
||||
OnVideoStateChange: func(state native.VideoState) {
|
||||
lastVideoState = state
|
||||
triggerVideoStateUpdate()
|
||||
|
|
@ -63,8 +65,13 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) {
|
|||
}
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
nativeLogger.Fatal().Err(err).Msg("failed to create native proxy")
|
||||
}
|
||||
|
||||
nativeInstance.Start()
|
||||
if err := nativeInstance.Start(); err != nil {
|
||||
nativeLogger.Fatal().Err(err).Msg("failed to start native proxy")
|
||||
}
|
||||
go func() {
|
||||
if err := nativeInstance.VideoSetEDID(config.EdidString); err != nil {
|
||||
nativeLogger.Warn().Err(err).Msg("error setting EDID")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,528 @@
|
|||
package kvm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/jetkvm/kvm/internal/native"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// RunNativeProcess runs the native process mode
|
||||
func RunNativeProcess() {
|
||||
// Initialize logger
|
||||
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
|
||||
|
||||
// Parse command line arguments (config is passed as first arg)
|
||||
if len(os.Args) < 2 {
|
||||
logger.Fatal().Msg("usage: native process requires config_json argument")
|
||||
}
|
||||
|
||||
var config native.ProcessConfig
|
||||
if err := json.Unmarshal([]byte(os.Args[1]), &config); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to parse config")
|
||||
}
|
||||
|
||||
// Parse version strings
|
||||
var systemVersion *semver.Version
|
||||
if config.SystemVersion != "" {
|
||||
v, err := semver.NewVersion(config.SystemVersion)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Str("version", config.SystemVersion).Msg("failed to parse system version")
|
||||
} else {
|
||||
systemVersion = v
|
||||
}
|
||||
}
|
||||
|
||||
var appVersion *semver.Version
|
||||
if config.AppVersion != "" {
|
||||
v, err := semver.NewVersion(config.AppVersion)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Str("version", config.AppVersion).Msg("failed to parse app version")
|
||||
} else {
|
||||
appVersion = v
|
||||
}
|
||||
}
|
||||
|
||||
// Create native instance
|
||||
nativeInstance := native.NewNative(native.NativeOptions{
|
||||
Disable: config.Disable,
|
||||
SystemVersion: systemVersion,
|
||||
AppVersion: appVersion,
|
||||
DisplayRotation: config.DisplayRotation,
|
||||
DefaultQualityFactor: config.DefaultQualityFactor,
|
||||
OnVideoStateChange: func(state native.VideoState) {
|
||||
sendEvent("video_state_change", state)
|
||||
},
|
||||
OnIndevEvent: func(event string) {
|
||||
sendEvent("indev_event", event)
|
||||
},
|
||||
OnRpcEvent: func(event string) {
|
||||
sendEvent("rpc_event", event)
|
||||
},
|
||||
OnVideoFrameReceived: func(frame []byte, duration time.Duration) {
|
||||
sendEvent("video_frame", map[string]interface{}{
|
||||
"frame": frame,
|
||||
"duration": duration.Nanoseconds(),
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
// Start native instance
|
||||
if err := nativeInstance.Start(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to start native instance")
|
||||
}
|
||||
|
||||
// Create gRPC server
|
||||
grpcServer := native.NewGRPCServer(nativeInstance, &logger)
|
||||
|
||||
// Determine socket path
|
||||
socketPath := os.Getenv("JETKVM_NATIVE_SOCKET")
|
||||
if socketPath == "" {
|
||||
// Default to a socket in /tmp
|
||||
socketPath = filepath.Join("/tmp", fmt.Sprintf("jetkvm-native-%d.sock", os.Getpid()))
|
||||
}
|
||||
|
||||
// Start gRPC server
|
||||
server, lis, err := native.StartGRPCServer(grpcServer, socketPath, &logger)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to start gRPC server")
|
||||
}
|
||||
|
||||
// Signal that we're ready by writing socket path to stdout (for parent to read)
|
||||
fmt.Fprintf(os.Stdout, "%s\n", socketPath)
|
||||
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")
|
||||
}
|
||||
|
||||
// All JSON-RPC handlers have been removed - now using gRPC
|
||||
case "VideoSetSleepMode":
|
||||
var params struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
err = n.VideoSetSleepMode(params.Enabled)
|
||||
|
||||
case "VideoGetSleepMode":
|
||||
var result bool
|
||||
result, err = n.VideoGetSleepMode()
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "VideoSleepModeSupported":
|
||||
result = n.VideoSleepModeSupported()
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
|
||||
case "VideoSetQualityFactor":
|
||||
var params struct {
|
||||
Factor float64 `json:"factor"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
err = n.VideoSetQualityFactor(params.Factor)
|
||||
|
||||
case "VideoGetQualityFactor":
|
||||
var result float64
|
||||
result, err = n.VideoGetQualityFactor()
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "VideoSetEDID":
|
||||
var params struct {
|
||||
EDID string `json:"edid"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
err = n.VideoSetEDID(params.EDID)
|
||||
|
||||
case "VideoGetEDID":
|
||||
var result string
|
||||
result, err = n.VideoGetEDID()
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "VideoLogStatus":
|
||||
var result string
|
||||
result, err = n.VideoLogStatus()
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "VideoStop":
|
||||
err = n.VideoStop()
|
||||
|
||||
case "VideoStart":
|
||||
err = n.VideoStart()
|
||||
|
||||
case "GetLVGLVersion":
|
||||
var result string
|
||||
result, err = n.GetLVGLVersion()
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjHide":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjHide(params.ObjName)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjShow":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjShow(params.ObjName)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UISetVar":
|
||||
var params struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
n.UISetVar(params.Name, params.Value)
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
case "UIGetVar":
|
||||
var params struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
result = n.UIGetVar(params.Name)
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
|
||||
case "UIObjAddState":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjAddState(params.ObjName, params.State)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjClearState":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjClearState(params.ObjName, params.State)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjAddFlag":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Flag string `json:"flag"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjAddFlag(params.ObjName, params.Flag)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjClearFlag":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Flag string `json:"flag"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjClearFlag(params.ObjName, params.Flag)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjSetOpacity":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Opacity int `json:"opacity"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjSetOpacity(params.ObjName, params.Opacity)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjFadeIn":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Duration uint32 `json:"duration"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjFadeIn(params.ObjName, params.Duration)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjFadeOut":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Duration uint32 `json:"duration"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjFadeOut(params.ObjName, params.Duration)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjSetLabelText":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjSetLabelText(params.ObjName, params.Text)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UIObjSetImageSrc":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
Image string `json:"image"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.UIObjSetImageSrc(params.ObjName, params.Image)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "DisplaySetRotation":
|
||||
var params struct {
|
||||
Rotation uint16 `json:"rotation"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
var result bool
|
||||
result, err = n.DisplaySetRotation(params.Rotation)
|
||||
if err == nil {
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
return
|
||||
}
|
||||
|
||||
case "UpdateLabelIfChanged":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
NewText string `json:"new_text"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
n.UpdateLabelIfChanged(params.ObjName, params.NewText)
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
case "UpdateLabelAndChangeVisibility":
|
||||
var params struct {
|
||||
ObjName string `json:"obj_name"`
|
||||
NewText string `json:"new_text"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
n.UpdateLabelAndChangeVisibility(params.ObjName, params.NewText)
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
case "SwitchToScreenIf":
|
||||
var params struct {
|
||||
ScreenName string `json:"screen_name"`
|
||||
ShouldSwitch []string `json:"should_switch"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
n.SwitchToScreenIf(params.ScreenName, params.ShouldSwitch)
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
case "SwitchToScreenIfDifferent":
|
||||
var params struct {
|
||||
ScreenName string `json:"screen_name"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
sendError(encoder, req.ID, -32602, "Invalid params", nil)
|
||||
return
|
||||
}
|
||||
n.SwitchToScreenIfDifferent(params.ScreenName)
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
case "DoNotUseThisIsForCrashTestingOnly":
|
||||
n.DoNotUseThisIsForCrashTestingOnly()
|
||||
sendResponse(encoder, req.ID, "result", nil)
|
||||
return
|
||||
|
||||
default:
|
||||
sendError(encoder, req.ID, -32601, fmt.Sprintf("Method not found: %s", req.Method), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
sendError(encoder, req.ID, -32000, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
sendResponse(encoder, req.ID, "result", result)
|
||||
}
|
||||
|
||||
func sendResponse(encoder *json.Encoder, id interface{}, key string, result interface{}) {
|
||||
response := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
key: result,
|
||||
}
|
||||
if id != nil {
|
||||
response["id"] = id
|
||||
}
|
||||
if err := encoder.Encode(response); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to send response: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendError(encoder *json.Encoder, id interface{}, code int, message string, data interface{}) {
|
||||
response := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"error": map[string]interface{}{
|
||||
"code": code,
|
||||
"message": message,
|
||||
},
|
||||
}
|
||||
if id != nil {
|
||||
response["id"] = id
|
||||
}
|
||||
if data != nil {
|
||||
response["error"].(map[string]interface{})["data"] = data
|
||||
}
|
||||
if err := encoder.Encode(response); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to send error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendEvent(eventType string, data interface{}) {
|
||||
event := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "event",
|
||||
"params": map[string]interface{}{
|
||||
"type": eventType,
|
||||
"data": data,
|
||||
},
|
||||
}
|
||||
encoder := json.NewEncoder(os.Stdout)
|
||||
if err := encoder.Encode(event); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to send event: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
# Generate gRPC code from proto files
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Check if protoc is installed
|
||||
if ! command -v protoc &> /dev/null; then
|
||||
echo "Error: protoc is not installed"
|
||||
echo "Install it with:"
|
||||
echo " apt-get install protobuf-compiler # Debian/Ubuntu"
|
||||
echo " brew install protobuf # macOS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if protoc-gen-go is installed
|
||||
if ! command -v protoc-gen-go &> /dev/null; then
|
||||
echo "Error: protoc-gen-go is not installed"
|
||||
echo "Install it with: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if protoc-gen-go-grpc is installed
|
||||
if ! command -v protoc-gen-go-grpc &> /dev/null; then
|
||||
echo "Error: protoc-gen-go-grpc is not installed"
|
||||
echo "Install it with: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate code
|
||||
echo "Generating gRPC code from proto files..."
|
||||
protoc \
|
||||
--go_out=. \
|
||||
--go_opt=paths=source_relative \
|
||||
--go-grpc_out=. \
|
||||
--go-grpc_opt=paths=source_relative \
|
||||
internal/native/proto/native.proto
|
||||
|
||||
echo "Done!"
|
||||
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
#!/bin/bash
|
||||
set -eE
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))")
|
||||
source ${SCRIPT_PATH}/build_utils.sh
|
||||
|
||||
# Function to display help message
|
||||
show_help() {
|
||||
echo "Usage: $0 [options] -v <version>"
|
||||
echo
|
||||
echo "Required:"
|
||||
echo " --app-version <version> App version to release"
|
||||
echo " --system-version <version> System version to release"
|
||||
echo
|
||||
echo "Optional:"
|
||||
echo " -u, --user <remote_user> Remote username (default: root)"
|
||||
echo " --run-go-tests Run go tests"
|
||||
echo " --run-go-tests-only Run go tests and exit"
|
||||
echo " --skip-ui-build Skip frontend/UI build"
|
||||
echo " --skip-native-build Skip native build"
|
||||
echo " --disable-docker Disable docker build"
|
||||
echo " -i, --install Build for release and install the app"
|
||||
echo " --help Display this help message"
|
||||
echo
|
||||
echo "Example:"
|
||||
echo " $0 --system-version 0.2.6"
|
||||
}
|
||||
|
||||
|
||||
BUILD_VERSION=$1
|
||||
R2_PATH="r2://jetkvm-update/system"
|
||||
PACK_BIN_PATH="./tools/linux/Linux_Pack_Firmware"
|
||||
UNPACK_BIN="${PACK_BIN_PATH}/mk-update_unpack.sh"
|
||||
|
||||
# Create temporary directory for downloads
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
msg_ok "Created temporary directory: $TEMP_DIR"
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
if [ -d "$TEMP_DIR" ]; then
|
||||
msg_info "Cleaning up temporary directory: $TEMP_DIR"
|
||||
rm -rf "$TEMP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# Set trap to cleanup on exit
|
||||
# trap cleanup EXIT
|
||||
|
||||
mkdir -p ${TEMP_DIR}/extracted-update
|
||||
${UNPACK_BIN} -i update.img -o ${TEMP_DIR}/extracted-update
|
||||
|
||||
exit 0
|
||||
# Check if the version already exists
|
||||
if rclone lsf $R2_PATH/$BUILD_VERSION/ | grep -q .; then
|
||||
msg_err "Error: Version $BUILD_VERSION already exists in the remote storage."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the version exists in the github
|
||||
RELEASE_URL="https://api.github.com/repos/jetkvm/rv1106-system/releases/tags/v$BUILD_VERSION"
|
||||
|
||||
# Download the release JSON
|
||||
RELEASE_JSON=$(curl -s $RELEASE_URL)
|
||||
|
||||
# Check if the release has assets we need
|
||||
if echo $RELEASE_JSON | jq -e '.assets | length == 0' > /dev/null; then
|
||||
msg_err "Error: Version $BUILD_VERSION does not have assets we need."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function get_file_by_name() {
|
||||
local file_name=$1
|
||||
local file_url=$(echo $RELEASE_JSON | jq -r ".assets[] | select(.name == \"$file_name\") | .browser_download_url")
|
||||
if [ -z "$file_url" ]; then
|
||||
msg_err "Error: File $file_name not found in the release."
|
||||
exit 1
|
||||
fi
|
||||
local digest=$(echo $RELEASE_JSON | jq -r ".assets[] | select(.name == \"$file_name\") | .digest")
|
||||
local temp_file_path="$TEMP_DIR/$file_name"
|
||||
|
||||
msg_info "Downloading $file_name: $file_url"
|
||||
|
||||
# Download the file to temporary directory
|
||||
curl -L -o "$temp_file_path" "$file_url"
|
||||
|
||||
# Verify digest if available
|
||||
if [ "$digest" != "null" ] && [ -n "$digest" ]; then
|
||||
msg_info "Verifying digest for $file_name ..."
|
||||
local calculated_digest=$(sha256sum "$temp_file_path" | cut -d' ' -f1)
|
||||
# Strip "sha256:" prefix if present
|
||||
local expected_digest=$(echo "$digest" | sed 's/^sha256://')
|
||||
if [ "$calculated_digest" != "$expected_digest" ]; then
|
||||
msg_err "🙅 Digest verification failed for $file_name"
|
||||
msg_info "Expected: $expected_digest"
|
||||
msg_info "Calculated: $calculated_digest"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
msg_warn "Warning: No digest available for $file_name, skipping verification"
|
||||
fi
|
||||
|
||||
msg_ok "✅ $file_name downloaded and verified."
|
||||
}
|
||||
|
||||
get_file_by_name "update_ota.tar"
|
||||
get_file_by_name "update.img"
|
||||
|
||||
strings -d bin/jetkvm_app | grep -x '0.4.8'
|
||||
|
||||
# Ask for confirmation
|
||||
msg_info "Do you want to continue with the release? (y/n)"
|
||||
read -n 1 -s -r -p "Press y to continue, any other key to exit"
|
||||
echo -ne "\n"
|
||||
if [ "$REPLY" != "y" ]; then
|
||||
msg_err "🙅 Release cancelled."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg_info "Releasing $BUILD_VERSION..."
|
||||
|
||||
sha256sum $TEMP_DIR/update_ota.tar | awk '{print $1}' > $TEMP_DIR/update_ota.tar.sha256
|
||||
sha256sum $TEMP_DIR/update.img | awk '{print $1}' > $TEMP_DIR/update.img.sha256
|
||||
|
||||
# Check if the version already exists
|
||||
msg_info "Copying to $R2_PATH/$BUILD_VERSION/"
|
||||
|
||||
rclone copyto --progress $TEMP_DIR/update_ota.tar $R2_PATH/$BUILD_VERSION/system.tar
|
||||
rclone copyto --progress $TEMP_DIR/update_ota.tar.sha256 $R2_PATH/$BUILD_VERSION/system.tar.sha256
|
||||
rclone copyto --progress $TEMP_DIR/update.img $R2_PATH/$BUILD_VERSION/update.img
|
||||
rclone copyto --progress $TEMP_DIR/update.img.sha256 $R2_PATH/$BUILD_VERSION/update.img.sha256
|
||||
|
||||
msg_ok "✅ $BUILD_VERSION released."
|
||||
Loading…
Reference in New Issue