mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +02:00
⭐ feat: protobuf input messaging (#165)
Replace json protocol by protobuf generate protobuf files with `bun buf generate` or just `buf generate` - [x] Implement all datatypes with proto files - [x] Map to ts types or use the generated proto types directly with: - [x] web frontend - [x] relay - [x] runner - [ ] final performance test (to be done when CI builds new images) --------- Co-authored-by: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
This commit is contained in:
654
Cargo.lock
generated
654
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
buf.gen.yaml
Normal file
17
buf.gen.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
version: v2
|
||||||
|
inputs:
|
||||||
|
- directory: protobufs
|
||||||
|
plugins:
|
||||||
|
# TypeScript (frontend)
|
||||||
|
- remote: buf.build/bufbuild/es
|
||||||
|
out: packages/input/src/proto
|
||||||
|
opt: target=ts
|
||||||
|
|
||||||
|
# Golang (relay)
|
||||||
|
- remote: buf.build/protocolbuffers/go
|
||||||
|
out: packages/relay/internal/proto
|
||||||
|
opt: paths=source_relative
|
||||||
|
|
||||||
|
# Rust (nestri-server)
|
||||||
|
- remote: buf.build/community/neoeinstein-prost
|
||||||
|
out: packages/server/src/proto
|
||||||
@@ -5,5 +5,13 @@
|
|||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@bufbuild/buf": "^1.50.0",
|
||||||
|
"@bufbuild/protoc-gen-es": "^2.2.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@bufbuild/protobuf": "^2.2.3",
|
||||||
|
"protobuf": "^0.11.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
import {type Input} from "./types"
|
|
||||||
import {keyCodeToLinuxEventCode} from "./codes"
|
import {keyCodeToLinuxEventCode} from "./codes"
|
||||||
import {MessageInput, encodeMessage} from "./messages";
|
|
||||||
import {WebRTCStream} from "./webrtc-stream";
|
import {WebRTCStream} from "./webrtc-stream";
|
||||||
import {LatencyTracker} from "./latency";
|
import {LatencyTracker} from "./latency";
|
||||||
|
import {ProtoLatencyTracker, ProtoTimestampEntry} from "./proto/latency_tracker_pb";
|
||||||
|
import {timestampFromDate} from "@bufbuild/protobuf/wkt";
|
||||||
|
import {ProtoMessageBase, ProtoMessageInput, ProtoMessageInputSchema} from "./proto/messages_pb";
|
||||||
|
import {
|
||||||
|
ProtoInput,
|
||||||
|
ProtoInputSchema,
|
||||||
|
ProtoKeyDownSchema,
|
||||||
|
ProtoKeyUpSchema,
|
||||||
|
ProtoMouseMoveSchema
|
||||||
|
} from "./proto/types_pb";
|
||||||
|
import {create, toBinary} from "@bufbuild/protobuf";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
webrtc: WebRTCStream;
|
webrtc: WebRTCStream;
|
||||||
@@ -15,19 +24,31 @@ export class Keyboard {
|
|||||||
protected connected!: boolean;
|
protected connected!: boolean;
|
||||||
|
|
||||||
// Store references to event listeners
|
// Store references to event listeners
|
||||||
private keydownListener: (e: KeyboardEvent) => void;
|
private readonly keydownListener: (e: KeyboardEvent) => void;
|
||||||
private keyupListener: (e: KeyboardEvent) => void;
|
private readonly keyupListener: (e: KeyboardEvent) => void;
|
||||||
|
|
||||||
constructor({webrtc, canvas}: Props) {
|
constructor({webrtc, canvas}: Props) {
|
||||||
this.wrtc = webrtc;
|
this.wrtc = webrtc;
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.keydownListener = this.createKeyboardListener("keydown", (e: any) => ({
|
this.keydownListener = this.createKeyboardListener((e: any) => create(ProtoInputSchema, {
|
||||||
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "keyDown",
|
||||||
|
value: create(ProtoKeyDownSchema, {
|
||||||
type: "KeyDown",
|
type: "KeyDown",
|
||||||
key: this.keyToVirtualKeyCode(e.code)
|
key: this.keyToVirtualKeyCode(e.code)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
this.keyupListener = this.createKeyboardListener("keyup", (e: any) => ({
|
this.keyupListener = this.createKeyboardListener((e: any) => create(ProtoInputSchema, {
|
||||||
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "keyUp",
|
||||||
|
value: create(ProtoKeyUpSchema, {
|
||||||
type: "KeyUp",
|
type: "KeyUp",
|
||||||
key: this.keyToVirtualKeyCode(e.code)
|
key: this.keyToVirtualKeyCode(e.code)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
this.run()
|
this.run()
|
||||||
}
|
}
|
||||||
@@ -59,7 +80,7 @@ export class Keyboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create and return mouse listeners
|
// Helper function to create and return mouse listeners
|
||||||
private createKeyboardListener(type: string, dataCreator: (e: Event) => Partial<Input>): (e: Event) => void {
|
private createKeyboardListener(dataCreator: (e: Event) => ProtoInput): (e: Event) => void {
|
||||||
return (e: Event) => {
|
return (e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -67,18 +88,34 @@ export class Keyboard {
|
|||||||
if ((e as any).repeat)
|
if ((e as any).repeat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const data = dataCreator(e as any); // type assertion because of the way dataCreator is used
|
const data = dataCreator(e as any);
|
||||||
const dataString = JSON.stringify({...data, type} as Input);
|
|
||||||
|
|
||||||
// Latency tracking
|
// Latency tracking
|
||||||
const tracker = new LatencyTracker("input-keyboard");
|
const tracker = new LatencyTracker("input-keyboard");
|
||||||
tracker.addTimestamp("client_send");
|
tracker.addTimestamp("client_send");
|
||||||
const message: MessageInput = {
|
const protoTracker: ProtoLatencyTracker = {
|
||||||
payload_type: "input",
|
$typeName: "proto.ProtoLatencyTracker",
|
||||||
data: dataString,
|
sequenceId: tracker.sequence_id,
|
||||||
latency: tracker,
|
timestamps: [],
|
||||||
};
|
};
|
||||||
this.wrtc.sendBinary(encodeMessage(message));
|
for (const t of tracker.timestamps) {
|
||||||
|
protoTracker.timestamps.push({
|
||||||
|
$typeName: "proto.ProtoTimestampEntry",
|
||||||
|
stage: t.stage,
|
||||||
|
time: timestampFromDate(t.time),
|
||||||
|
} as ProtoTimestampEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const message: ProtoMessageInput = {
|
||||||
|
$typeName: "proto.ProtoMessageInput",
|
||||||
|
messageBase: {
|
||||||
|
$typeName: "proto.ProtoMessageBase",
|
||||||
|
payloadType: "input",
|
||||||
|
latency: protoTracker,
|
||||||
|
} as ProtoMessageBase,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
this.wrtc.sendBinary(toBinary(ProtoMessageInputSchema, message));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ type TimestampEntry = {
|
|||||||
export class LatencyTracker {
|
export class LatencyTracker {
|
||||||
sequence_id: string;
|
sequence_id: string;
|
||||||
timestamps: TimestampEntry[];
|
timestamps: TimestampEntry[];
|
||||||
metadata?: Record<string, any>;
|
|
||||||
|
|
||||||
constructor(sequence_id: string, timestamps: TimestampEntry[] = [], metadata: Record<string, any> = {}) {
|
constructor(sequence_id: string, timestamps: TimestampEntry[] = []) {
|
||||||
this.sequence_id = sequence_id;
|
this.sequence_id = sequence_id;
|
||||||
this.timestamps = timestamps;
|
this.timestamps = timestamps;
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addTimestamp(stage: string): void {
|
addTimestamp(stage: string): void {
|
||||||
@@ -40,7 +38,6 @@ export class LatencyTracker {
|
|||||||
// Fill nanoseconds with zeros to match the expected format
|
// Fill nanoseconds with zeros to match the expected format
|
||||||
time: entry.time.toISOString().replace(/\.(\d+)Z$/, ".$1000000Z"),
|
time: entry.time.toISOString().replace(/\.(\d+)Z$/, ".$1000000Z"),
|
||||||
})),
|
})),
|
||||||
metadata: this.metadata,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +46,6 @@ export class LatencyTracker {
|
|||||||
stage: ts.stage,
|
stage: ts.stage,
|
||||||
time: new Date(ts.time),
|
time: new Date(ts.time),
|
||||||
}));
|
}));
|
||||||
return new LatencyTracker(json.sequence_id, timestamps, json.metadata);
|
return new LatencyTracker(json.sequence_id, timestamps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
import {gzip, ungzip} from "pako";
|
|
||||||
import {LatencyTracker} from "./latency";
|
import {LatencyTracker} from "./latency";
|
||||||
|
|
||||||
export interface MessageBase {
|
export interface MessageBase {
|
||||||
payload_type: string;
|
payload_type: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessageInput extends MessageBase {
|
|
||||||
payload_type: "input";
|
|
||||||
data: string;
|
|
||||||
latency?: LatencyTracker;
|
latency?: LatencyTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,33 +35,3 @@ export interface MessageAnswer extends MessageBase {
|
|||||||
payload_type: "answer";
|
payload_type: "answer";
|
||||||
answer_type: AnswerType;
|
answer_type: AnswerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function blobToUint8Array(blob: Blob): Promise<Uint8Array> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onloadend = () => {
|
|
||||||
const arrayBuffer = reader.result as ArrayBuffer;
|
|
||||||
resolve(new Uint8Array(arrayBuffer));
|
|
||||||
};
|
|
||||||
reader.onerror = reject;
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function encodeMessage<T>(message: T): Uint8Array {
|
|
||||||
// Convert the message to JSON string
|
|
||||||
const json = JSON.stringify(message);
|
|
||||||
// Compress the JSON string using gzip
|
|
||||||
return gzip(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function decodeMessage<T>(data: Blob): Promise<T> {
|
|
||||||
// Convert the Blob to Uint8Array
|
|
||||||
const array = await blobToUint8Array(data);
|
|
||||||
// Decompress the gzip data
|
|
||||||
const decompressed = ungzip(array);
|
|
||||||
// Convert the Uint8Array to JSON string
|
|
||||||
const json = new TextDecoder().decode(decompressed);
|
|
||||||
// Parse the JSON string
|
|
||||||
return JSON.parse(json);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import {type Input} from "./types"
|
|
||||||
import {mouseButtonToLinuxEventCode} from "./codes"
|
|
||||||
import {MessageInput, encodeMessage} from "./messages";
|
|
||||||
import {WebRTCStream} from "./webrtc-stream";
|
import {WebRTCStream} from "./webrtc-stream";
|
||||||
import {LatencyTracker} from "./latency";
|
import {LatencyTracker} from "./latency";
|
||||||
|
import {ProtoMessageInput, ProtoMessageBase, ProtoMessageInputSchema} from "./proto/messages_pb";
|
||||||
|
import {
|
||||||
|
ProtoInput, ProtoInputSchema,
|
||||||
|
ProtoMouseKeyDown, ProtoMouseKeyDownSchema,
|
||||||
|
ProtoMouseKeyUp, ProtoMouseKeyUpSchema,
|
||||||
|
ProtoMouseMove,
|
||||||
|
ProtoMouseMoveSchema,
|
||||||
|
ProtoMouseWheel, ProtoMouseWheelSchema
|
||||||
|
} from "./proto/types_pb";
|
||||||
|
import {mouseButtonToLinuxEventCode} from "./codes";
|
||||||
|
import {ProtoLatencyTracker, ProtoTimestampEntry} from "./proto/latency_tracker_pb";
|
||||||
|
import {create, toBinary} from "@bufbuild/protobuf";
|
||||||
|
import {timestampFromDate} from "@bufbuild/protobuf/wkt";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
webrtc: WebRTCStream;
|
webrtc: WebRTCStream;
|
||||||
@@ -15,33 +25,56 @@ export class Mouse {
|
|||||||
protected connected!: boolean;
|
protected connected!: boolean;
|
||||||
|
|
||||||
// Store references to event listeners
|
// Store references to event listeners
|
||||||
private mousemoveListener: (e: MouseEvent) => void;
|
private readonly mousemoveListener: (e: MouseEvent) => void;
|
||||||
private mousedownListener: (e: MouseEvent) => void;
|
private readonly mousedownListener: (e: MouseEvent) => void;
|
||||||
private mouseupListener: (e: MouseEvent) => void;
|
private readonly mouseupListener: (e: MouseEvent) => void;
|
||||||
private mousewheelListener: (e: WheelEvent) => void;
|
private readonly mousewheelListener: (e: WheelEvent) => void;
|
||||||
|
|
||||||
constructor({webrtc, canvas}: Props) {
|
constructor({webrtc, canvas}: Props) {
|
||||||
this.wrtc = webrtc;
|
this.wrtc = webrtc;
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
|
||||||
this.mousemoveListener = this.createMouseListener("mousemove", (e: any) => ({
|
this.mousemoveListener = this.createMouseListener((e: any) => create(ProtoInputSchema, {
|
||||||
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "mouseMove",
|
||||||
|
value: create(ProtoMouseMoveSchema, {
|
||||||
type: "MouseMove",
|
type: "MouseMove",
|
||||||
x: e.movementX,
|
x: e.movementX,
|
||||||
y: e.movementY
|
y: e.movementY
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
this.mousedownListener = this.createMouseListener("mousedown", (e: any) => ({
|
this.mousedownListener = this.createMouseListener((e: any) => create(ProtoInputSchema, {
|
||||||
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "mouseKeyDown",
|
||||||
|
value: create(ProtoMouseKeyDownSchema, {
|
||||||
type: "MouseKeyDown",
|
type: "MouseKeyDown",
|
||||||
key: this.keyToVirtualKeyCode(e.button)
|
key: this.keyToVirtualKeyCode(e.button)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
this.mouseupListener = this.createMouseListener((e: any) => create(ProtoInputSchema, {
|
||||||
this.mouseupListener = this.createMouseListener("mouseup", (e: any) => ({
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "mouseKeyUp",
|
||||||
|
value: create(ProtoMouseKeyUpSchema, {
|
||||||
type: "MouseKeyUp",
|
type: "MouseKeyUp",
|
||||||
key: this.keyToVirtualKeyCode(e.button)
|
key: this.keyToVirtualKeyCode(e.button)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
this.mousewheelListener = this.createMouseListener("wheel", (e: any) => ({
|
this.mousewheelListener = this.createMouseListener((e: any) => create(ProtoInputSchema, {
|
||||||
|
$typeName: "proto.ProtoInput",
|
||||||
|
inputType: {
|
||||||
|
case: "mouseWheel",
|
||||||
|
value: create(ProtoMouseWheelSchema, {
|
||||||
type: "MouseWheel",
|
type: "MouseWheel",
|
||||||
x: e.deltaX,
|
x: e.deltaX,
|
||||||
y: e.deltaY
|
y: e.deltaY
|
||||||
|
}),
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.run()
|
this.run()
|
||||||
@@ -81,22 +114,38 @@ export class Mouse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create and return mouse listeners
|
// Helper function to create and return mouse listeners
|
||||||
private createMouseListener(type: string, dataCreator: (e: Event) => Partial<Input>): (e: Event) => void {
|
private createMouseListener(dataCreator: (e: Event) => ProtoInput): (e: Event) => void {
|
||||||
return (e: Event) => {
|
return (e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const data = dataCreator(e as any); // type assertion because of the way dataCreator is used
|
const data = dataCreator(e as any);
|
||||||
const dataString = JSON.stringify({...data, type} as Input);
|
|
||||||
|
|
||||||
// Latency tracking
|
// Latency tracking
|
||||||
const tracker = new LatencyTracker("input-mouse");
|
const tracker = new LatencyTracker("input-mouse");
|
||||||
tracker.addTimestamp("client_send");
|
tracker.addTimestamp("client_send");
|
||||||
const message: MessageInput = {
|
const protoTracker: ProtoLatencyTracker = {
|
||||||
payload_type: "input",
|
$typeName: "proto.ProtoLatencyTracker",
|
||||||
data: dataString,
|
sequenceId: tracker.sequence_id,
|
||||||
latency: tracker,
|
timestamps: [],
|
||||||
};
|
};
|
||||||
this.wrtc.sendBinary(encodeMessage(message));
|
for (const t of tracker.timestamps) {
|
||||||
|
protoTracker.timestamps.push({
|
||||||
|
$typeName: "proto.ProtoTimestampEntry",
|
||||||
|
stage: t.stage,
|
||||||
|
time: timestampFromDate(t.time),
|
||||||
|
} as ProtoTimestampEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const message: ProtoMessageInput = {
|
||||||
|
$typeName: "proto.ProtoMessageInput",
|
||||||
|
messageBase: {
|
||||||
|
$typeName: "proto.ProtoMessageBase",
|
||||||
|
payloadType: "input",
|
||||||
|
latency: protoTracker,
|
||||||
|
} as ProtoMessageBase,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
this.wrtc.sendBinary(toBinary(ProtoMessageInputSchema, message));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
packages/input/src/proto/latency_tracker_pb.ts
Normal file
60
packages/input/src/proto/latency_tracker_pb.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// @generated by protoc-gen-es v2.2.3 with parameter "target=ts"
|
||||||
|
// @generated from file latency_tracker.proto (package proto, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import type { Timestamp } from "@bufbuild/protobuf/wkt";
|
||||||
|
import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt";
|
||||||
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the file latency_tracker.proto.
|
||||||
|
*/
|
||||||
|
export const file_latency_tracker: GenFile = /*@__PURE__*/
|
||||||
|
fileDesc("ChVsYXRlbmN5X3RyYWNrZXIucHJvdG8SBXByb3RvIk4KE1Byb3RvVGltZXN0YW1wRW50cnkSDQoFc3RhZ2UYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAiWgoTUHJvdG9MYXRlbmN5VHJhY2tlchITCgtzZXF1ZW5jZV9pZBgBIAEoCRIuCgp0aW1lc3RhbXBzGAIgAygLMhoucHJvdG8uUHJvdG9UaW1lc3RhbXBFbnRyeUIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z", [file_google_protobuf_timestamp]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message proto.ProtoTimestampEntry
|
||||||
|
*/
|
||||||
|
export type ProtoTimestampEntry = Message<"proto.ProtoTimestampEntry"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: string stage = 1;
|
||||||
|
*/
|
||||||
|
stage: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: google.protobuf.Timestamp time = 2;
|
||||||
|
*/
|
||||||
|
time?: Timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoTimestampEntry.
|
||||||
|
* Use `create(ProtoTimestampEntrySchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoTimestampEntrySchema: GenMessage<ProtoTimestampEntry> = /*@__PURE__*/
|
||||||
|
messageDesc(file_latency_tracker, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message proto.ProtoLatencyTracker
|
||||||
|
*/
|
||||||
|
export type ProtoLatencyTracker = Message<"proto.ProtoLatencyTracker"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: string sequence_id = 1;
|
||||||
|
*/
|
||||||
|
sequenceId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: repeated proto.ProtoTimestampEntry timestamps = 2;
|
||||||
|
*/
|
||||||
|
timestamps: ProtoTimestampEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoLatencyTracker.
|
||||||
|
* Use `create(ProtoLatencyTrackerSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoLatencyTrackerSchema: GenMessage<ProtoLatencyTracker> = /*@__PURE__*/
|
||||||
|
messageDesc(file_latency_tracker, 1);
|
||||||
|
|
||||||
62
packages/input/src/proto/messages_pb.ts
Normal file
62
packages/input/src/proto/messages_pb.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// @generated by protoc-gen-es v2.2.3 with parameter "target=ts"
|
||||||
|
// @generated from file messages.proto (package proto, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import type { ProtoInput } from "./types_pb";
|
||||||
|
import { file_types } from "./types_pb";
|
||||||
|
import type { ProtoLatencyTracker } from "./latency_tracker_pb";
|
||||||
|
import { file_latency_tracker } from "./latency_tracker_pb";
|
||||||
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the file messages.proto.
|
||||||
|
*/
|
||||||
|
export const file_messages: GenFile = /*@__PURE__*/
|
||||||
|
fileDesc("Cg5tZXNzYWdlcy5wcm90bxIFcHJvdG8iVQoQUHJvdG9NZXNzYWdlQmFzZRIUCgxwYXlsb2FkX3R5cGUYASABKAkSKwoHbGF0ZW5jeRgCIAEoCzIaLnByb3RvLlByb3RvTGF0ZW5jeVRyYWNrZXIiYwoRUHJvdG9NZXNzYWdlSW5wdXQSLQoMbWVzc2FnZV9iYXNlGAEgASgLMhcucHJvdG8uUHJvdG9NZXNzYWdlQmFzZRIfCgRkYXRhGAIgASgLMhEucHJvdG8uUHJvdG9JbnB1dEIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z", [file_types, file_latency_tracker]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message proto.ProtoMessageBase
|
||||||
|
*/
|
||||||
|
export type ProtoMessageBase = Message<"proto.ProtoMessageBase"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: string payload_type = 1;
|
||||||
|
*/
|
||||||
|
payloadType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoLatencyTracker latency = 2;
|
||||||
|
*/
|
||||||
|
latency?: ProtoLatencyTracker;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMessageBase.
|
||||||
|
* Use `create(ProtoMessageBaseSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMessageBaseSchema: GenMessage<ProtoMessageBase> = /*@__PURE__*/
|
||||||
|
messageDesc(file_messages, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message proto.ProtoMessageInput
|
||||||
|
*/
|
||||||
|
export type ProtoMessageInput = Message<"proto.ProtoMessageInput"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMessageBase message_base = 1;
|
||||||
|
*/
|
||||||
|
messageBase?: ProtoMessageBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoInput data = 2;
|
||||||
|
*/
|
||||||
|
data?: ProtoInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMessageInput.
|
||||||
|
* Use `create(ProtoMessageInputSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMessageInputSchema: GenMessage<ProtoMessageInput> = /*@__PURE__*/
|
||||||
|
messageDesc(file_messages, 1);
|
||||||
|
|
||||||
272
packages/input/src/proto/types_pb.ts
Normal file
272
packages/input/src/proto/types_pb.ts
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// @generated by protoc-gen-es v2.2.3 with parameter "target=ts"
|
||||||
|
// @generated from file types.proto (package proto, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
|
||||||
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the file types.proto.
|
||||||
|
*/
|
||||||
|
export const file_types: GenFile = /*@__PURE__*/
|
||||||
|
fileDesc("Cgt0eXBlcy5wcm90bxIFcHJvdG8iNAoOUHJvdG9Nb3VzZU1vdmUSDAoEdHlwZRgBIAEoCRIJCgF4GAIgASgFEgkKAXkYAyABKAUiNwoRUHJvdG9Nb3VzZU1vdmVBYnMSDAoEdHlwZRgBIAEoCRIJCgF4GAIgASgFEgkKAXkYAyABKAUiNQoPUHJvdG9Nb3VzZVdoZWVsEgwKBHR5cGUYASABKAkSCQoBeBgCIAEoBRIJCgF5GAMgASgFIi4KEVByb3RvTW91c2VLZXlEb3duEgwKBHR5cGUYASABKAkSCwoDa2V5GAIgASgFIiwKD1Byb3RvTW91c2VLZXlVcBIMCgR0eXBlGAEgASgJEgsKA2tleRgCIAEoBSIpCgxQcm90b0tleURvd24SDAoEdHlwZRgBIAEoCRILCgNrZXkYAiABKAUiJwoKUHJvdG9LZXlVcBIMCgR0eXBlGAEgASgJEgsKA2tleRgCIAEoBSLcAgoKUHJvdG9JbnB1dBIrCgptb3VzZV9tb3ZlGAEgASgLMhUucHJvdG8uUHJvdG9Nb3VzZU1vdmVIABIyCg5tb3VzZV9tb3ZlX2FicxgCIAEoCzIYLnByb3RvLlByb3RvTW91c2VNb3ZlQWJzSAASLQoLbW91c2Vfd2hlZWwYAyABKAsyFi5wcm90by5Qcm90b01vdXNlV2hlZWxIABIyCg5tb3VzZV9rZXlfZG93bhgEIAEoCzIYLnByb3RvLlByb3RvTW91c2VLZXlEb3duSAASLgoMbW91c2Vfa2V5X3VwGAUgASgLMhYucHJvdG8uUHJvdG9Nb3VzZUtleVVwSAASJwoIa2V5X2Rvd24YBiABKAsyEy5wcm90by5Qcm90b0tleURvd25IABIjCgZrZXlfdXAYByABKAsyES5wcm90by5Qcm90b0tleVVwSABCDAoKaW5wdXRfdHlwZUIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseMove message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoMouseMove
|
||||||
|
*/
|
||||||
|
export type ProtoMouseMove = Message<"proto.ProtoMouseMove"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "MouseMove"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 x = 2;
|
||||||
|
*/
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 y = 3;
|
||||||
|
*/
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMouseMove.
|
||||||
|
* Use `create(ProtoMouseMoveSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMouseMoveSchema: GenMessage<ProtoMouseMove> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseMoveAbs message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoMouseMoveAbs
|
||||||
|
*/
|
||||||
|
export type ProtoMouseMoveAbs = Message<"proto.ProtoMouseMoveAbs"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "MouseMoveAbs"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 x = 2;
|
||||||
|
*/
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 y = 3;
|
||||||
|
*/
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMouseMoveAbs.
|
||||||
|
* Use `create(ProtoMouseMoveAbsSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMouseMoveAbsSchema: GenMessage<ProtoMouseMoveAbs> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseWheel message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoMouseWheel
|
||||||
|
*/
|
||||||
|
export type ProtoMouseWheel = Message<"proto.ProtoMouseWheel"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "MouseWheel"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 x = 2;
|
||||||
|
*/
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 y = 3;
|
||||||
|
*/
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMouseWheel.
|
||||||
|
* Use `create(ProtoMouseWheelSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMouseWheelSchema: GenMessage<ProtoMouseWheel> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseKeyDown message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoMouseKeyDown
|
||||||
|
*/
|
||||||
|
export type ProtoMouseKeyDown = Message<"proto.ProtoMouseKeyDown"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "MouseKeyDown"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 key = 2;
|
||||||
|
*/
|
||||||
|
key: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMouseKeyDown.
|
||||||
|
* Use `create(ProtoMouseKeyDownSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMouseKeyDownSchema: GenMessage<ProtoMouseKeyDown> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseKeyUp message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoMouseKeyUp
|
||||||
|
*/
|
||||||
|
export type ProtoMouseKeyUp = Message<"proto.ProtoMouseKeyUp"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "MouseKeyUp"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 key = 2;
|
||||||
|
*/
|
||||||
|
key: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoMouseKeyUp.
|
||||||
|
* Use `create(ProtoMouseKeyUpSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoMouseKeyUpSchema: GenMessage<ProtoMouseKeyUp> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KeyDown message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoKeyDown
|
||||||
|
*/
|
||||||
|
export type ProtoKeyDown = Message<"proto.ProtoKeyDown"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "KeyDown"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 key = 2;
|
||||||
|
*/
|
||||||
|
key: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoKeyDown.
|
||||||
|
* Use `create(ProtoKeyDownSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoKeyDownSchema: GenMessage<ProtoKeyDown> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KeyUp message
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoKeyUp
|
||||||
|
*/
|
||||||
|
export type ProtoKeyUp = Message<"proto.ProtoKeyUp"> & {
|
||||||
|
/**
|
||||||
|
* Fixed value "KeyUp"
|
||||||
|
*
|
||||||
|
* @generated from field: string type = 1;
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 key = 2;
|
||||||
|
*/
|
||||||
|
key: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoKeyUp.
|
||||||
|
* Use `create(ProtoKeyUpSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoKeyUpSchema: GenMessage<ProtoKeyUp> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all Input types
|
||||||
|
*
|
||||||
|
* @generated from message proto.ProtoInput
|
||||||
|
*/
|
||||||
|
export type ProtoInput = Message<"proto.ProtoInput"> & {
|
||||||
|
/**
|
||||||
|
* @generated from oneof proto.ProtoInput.input_type
|
||||||
|
*/
|
||||||
|
inputType: {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMouseMove mouse_move = 1;
|
||||||
|
*/
|
||||||
|
value: ProtoMouseMove;
|
||||||
|
case: "mouseMove";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMouseMoveAbs mouse_move_abs = 2;
|
||||||
|
*/
|
||||||
|
value: ProtoMouseMoveAbs;
|
||||||
|
case: "mouseMoveAbs";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMouseWheel mouse_wheel = 3;
|
||||||
|
*/
|
||||||
|
value: ProtoMouseWheel;
|
||||||
|
case: "mouseWheel";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMouseKeyDown mouse_key_down = 4;
|
||||||
|
*/
|
||||||
|
value: ProtoMouseKeyDown;
|
||||||
|
case: "mouseKeyDown";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoMouseKeyUp mouse_key_up = 5;
|
||||||
|
*/
|
||||||
|
value: ProtoMouseKeyUp;
|
||||||
|
case: "mouseKeyUp";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoKeyDown key_down = 6;
|
||||||
|
*/
|
||||||
|
value: ProtoKeyDown;
|
||||||
|
case: "keyDown";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: proto.ProtoKeyUp key_up = 7;
|
||||||
|
*/
|
||||||
|
value: ProtoKeyUp;
|
||||||
|
case: "keyUp";
|
||||||
|
} | { case: undefined; value?: undefined };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message proto.ProtoInput.
|
||||||
|
* Use `create(ProtoInputSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ProtoInputSchema: GenMessage<ProtoInput> = /*@__PURE__*/
|
||||||
|
messageDesc(file_types, 7);
|
||||||
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
interface BaseInput {
|
|
||||||
timestamp?: number; // Add a timestamp for better context (optional)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MouseMove extends BaseInput {
|
|
||||||
type: "MouseMove";
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MouseMoveAbs extends BaseInput {
|
|
||||||
type: "MouseMoveAbs";
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MouseWheel extends BaseInput {
|
|
||||||
type: "MouseWheel";
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MouseKeyDown extends BaseInput {
|
|
||||||
type: "MouseKeyDown";
|
|
||||||
key: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MouseKeyUp extends BaseInput {
|
|
||||||
type: "MouseKeyUp";
|
|
||||||
key: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface KeyDown extends BaseInput {
|
|
||||||
type: "KeyDown";
|
|
||||||
key: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface KeyUp extends BaseInput {
|
|
||||||
type: "KeyUp";
|
|
||||||
key: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export type Input =
|
|
||||||
| MouseMove
|
|
||||||
| MouseMoveAbs
|
|
||||||
| MouseWheel
|
|
||||||
| MouseKeyDown
|
|
||||||
| MouseKeyUp
|
|
||||||
| KeyDown
|
|
||||||
| KeyUp;
|
|
||||||
|
|
||||||
@@ -6,8 +6,6 @@ import {
|
|||||||
MessageAnswer,
|
MessageAnswer,
|
||||||
JoinerType,
|
JoinerType,
|
||||||
AnswerType,
|
AnswerType,
|
||||||
decodeMessage,
|
|
||||||
encodeMessage
|
|
||||||
} from "./messages";
|
} from "./messages";
|
||||||
|
|
||||||
export class WebRTCStream {
|
export class WebRTCStream {
|
||||||
@@ -40,16 +38,16 @@ export class WebRTCStream {
|
|||||||
payload_type: "join",
|
payload_type: "join",
|
||||||
joiner_type: JoinerType.JoinerClient
|
joiner_type: JoinerType.JoinerClient
|
||||||
};
|
};
|
||||||
this._ws!.send(encodeMessage(joinMessage));
|
this._ws!.send(JSON.stringify(joinMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
let iceHolder: RTCIceCandidateInit[] = [];
|
let iceHolder: RTCIceCandidateInit[] = [];
|
||||||
|
|
||||||
this._ws.onmessage = async (e) => {
|
this._ws.onmessage = async (e) => {
|
||||||
// allow only binary
|
// allow only JSON
|
||||||
if (typeof e.data !== "object") return;
|
if (typeof e.data === "object") return;
|
||||||
if (!e.data) return;
|
if (!e.data) return;
|
||||||
const message = await decodeMessage<MessageBase>(e.data);
|
const message = JSON.parse(e.data) as MessageBase;
|
||||||
switch (message.payload_type) {
|
switch (message.payload_type) {
|
||||||
case "sdp":
|
case "sdp":
|
||||||
if (!this._pc) {
|
if (!this._pc) {
|
||||||
@@ -63,7 +61,7 @@ export class WebRTCStream {
|
|||||||
// Force stereo in Chromium browsers
|
// Force stereo in Chromium browsers
|
||||||
answer.sdp = this.forceOpusStereo(answer.sdp!);
|
answer.sdp = this.forceOpusStereo(answer.sdp!);
|
||||||
await this._pc!.setLocalDescription(answer);
|
await this._pc!.setLocalDescription(answer);
|
||||||
this._ws!.send(encodeMessage({
|
this._ws!.send(JSON.stringify({
|
||||||
payload_type: "sdp",
|
payload_type: "sdp",
|
||||||
sdp: answer
|
sdp: answer
|
||||||
}));
|
}));
|
||||||
@@ -154,7 +152,7 @@ export class WebRTCStream {
|
|||||||
payload_type: "ice",
|
payload_type: "ice",
|
||||||
candidate: e.candidate
|
candidate: e.candidate
|
||||||
};
|
};
|
||||||
this._ws!.send(encodeMessage(message));
|
this._ws!.send(JSON.stringify(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,26 +6,27 @@ require (
|
|||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/pion/interceptor v0.1.37
|
github.com/pion/interceptor v0.1.37
|
||||||
github.com/pion/webrtc/v4 v4.0.2
|
github.com/pion/webrtc/v4 v4.0.8
|
||||||
|
google.golang.org/protobuf v1.36.4
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/pion/datachannel v1.5.9 // indirect
|
github.com/pion/datachannel v1.5.10 // indirect
|
||||||
github.com/pion/dtls/v3 v3.0.4 // indirect
|
github.com/pion/dtls/v3 v3.0.4 // indirect
|
||||||
github.com/pion/ice/v4 v4.0.2 // indirect
|
github.com/pion/ice/v4 v4.0.5 // indirect
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.3 // indirect
|
||||||
github.com/pion/mdns/v2 v2.0.7 // indirect
|
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
github.com/pion/rtcp v1.2.14 // indirect
|
github.com/pion/rtcp v1.2.15 // indirect
|
||||||
github.com/pion/rtp v1.8.9 // indirect
|
github.com/pion/rtp v1.8.11 // indirect
|
||||||
github.com/pion/sctp v1.8.34 // indirect
|
github.com/pion/sctp v1.8.35 // indirect
|
||||||
github.com/pion/sdp/v3 v3.0.9 // indirect
|
github.com/pion/sdp/v3 v3.0.10 // indirect
|
||||||
github.com/pion/srtp/v3 v3.0.4 // indirect
|
github.com/pion/srtp/v3 v3.0.4 // indirect
|
||||||
github.com/pion/stun/v3 v3.0.0 // indirect
|
github.com/pion/stun/v3 v3.0.0 // indirect
|
||||||
github.com/pion/transport/v3 v3.0.7 // indirect
|
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||||
github.com/pion/turn/v4 v4.0.0 // indirect
|
github.com/pion/turn/v4 v4.0.0 // indirect
|
||||||
github.com/wlynxg/anet v0.0.5 // indirect
|
github.com/wlynxg/anet v0.0.5 // indirect
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
golang.org/x/crypto v0.32.0 // indirect
|
||||||
golang.org/x/net v0.31.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA=
|
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
|
||||||
github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE=
|
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
|
||||||
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
|
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
|
||||||
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
|
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
|
||||||
github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s=
|
github.com/pion/ice/v4 v4.0.5 h1:6awVfa1jg9YsI9/Lep4TG/o3kwS1Oayr5b8xz50ibJ8=
|
||||||
github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg=
|
github.com/pion/ice/v4 v4.0.5/go.mod h1:JJaoEIxUIlGDA9gaRZbwXYqI3j6VG/QchpjX+QmwN6A=
|
||||||
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
|
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
|
||||||
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
|
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
|
||||||
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
|
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
|
||||||
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
|
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||||
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
|
||||||
github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
|
github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk=
|
||||||
github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4=
|
||||||
github.com/pion/sctp v1.8.34 h1:rCuD3m53i0oGxCSp7FLQKvqVx0Nf5AUAHhMRXTTQjBc=
|
github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA=
|
||||||
github.com/pion/sctp v1.8.34/go.mod h1:yWkCClkXlzVW7BXfI2PjrUGBwUI0CjXJBkhLt+sdo4U=
|
github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg=
|
||||||
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
|
github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA=
|
||||||
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
|
github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
|
||||||
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
|
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
|
||||||
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
|
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
|
||||||
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
|
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
|
||||||
@@ -35,28 +36,23 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1
|
|||||||
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
|
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
|
||||||
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
|
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
|
||||||
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
|
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
|
||||||
github.com/pion/webrtc/v4 v4.0.2 h1:fBwm5/hqSUybrCWl0DDBSTDrpbkcgkqpeLmXw9CsBQA=
|
github.com/pion/webrtc/v4 v4.0.8 h1:T1ZmnT9qxIJIt4d8XoiMOBrTClGHDDXNg9e/fh018Qc=
|
||||||
github.com/pion/webrtc/v4 v4.0.2/go.mod h1:moylBT2A4dNoEaYBCdV1nThM3TLwRHzWszIG+eSPaqQ=
|
github.com/pion/webrtc/v4 v4.0.8/go.mod h1:HHBeUVBAC+j4ZFnYhovEFStF02Arb1EyD4G7e7HBTJw=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
|
||||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||||
|
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -2,20 +2,22 @@ package relay
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
"log"
|
"log"
|
||||||
|
gen "relay/internal/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NestriDataChannel is a custom data channel with callbacks
|
// NestriDataChannel is a custom data channel with callbacks
|
||||||
type NestriDataChannel struct {
|
type NestriDataChannel struct {
|
||||||
*webrtc.DataChannel
|
*webrtc.DataChannel
|
||||||
binaryCallbacks map[string]OnMessageCallback // MessageBase type -> callback
|
callbacks map[string]OnMessageCallback // MessageBase type -> callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNestriDataChannel creates a new NestriDataChannel from *webrtc.DataChannel
|
// NewNestriDataChannel creates a new NestriDataChannel from *webrtc.DataChannel
|
||||||
func NewNestriDataChannel(dc *webrtc.DataChannel) *NestriDataChannel {
|
func NewNestriDataChannel(dc *webrtc.DataChannel) *NestriDataChannel {
|
||||||
ndc := &NestriDataChannel{
|
ndc := &NestriDataChannel{
|
||||||
DataChannel: dc,
|
DataChannel: dc,
|
||||||
binaryCallbacks: make(map[string]OnMessageCallback),
|
callbacks: make(map[string]OnMessageCallback),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for incoming messages
|
// Handler for incoming messages
|
||||||
@@ -26,14 +28,14 @@ func NewNestriDataChannel(dc *webrtc.DataChannel) *NestriDataChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decode message
|
// Decode message
|
||||||
var base MessageBase
|
var base gen.ProtoMessageInput
|
||||||
if err := DecodeMessage(msg.Data, &base); err != nil {
|
if err := proto.Unmarshal(msg.Data, &base); err != nil {
|
||||||
log.Printf("Failed to decode binary DataChannel message, reason: %s\n", err)
|
log.Printf("Failed to decode binary DataChannel message, reason: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle message type callback
|
// Handle message type callback
|
||||||
if callback, ok := ndc.binaryCallbacks[base.PayloadType]; ok {
|
if callback, ok := ndc.callbacks["input"]; ok {
|
||||||
go callback(msg.Data)
|
go callback(msg.Data)
|
||||||
} // TODO: Log unknown message type?
|
} // TODO: Log unknown message type?
|
||||||
})
|
})
|
||||||
@@ -48,16 +50,16 @@ func (ndc *NestriDataChannel) SendBinary(data []byte) error {
|
|||||||
|
|
||||||
// RegisterMessageCallback registers a callback for a given binary message type
|
// RegisterMessageCallback registers a callback for a given binary message type
|
||||||
func (ndc *NestriDataChannel) RegisterMessageCallback(msgType string, callback OnMessageCallback) {
|
func (ndc *NestriDataChannel) RegisterMessageCallback(msgType string, callback OnMessageCallback) {
|
||||||
if ndc.binaryCallbacks == nil {
|
if ndc.callbacks == nil {
|
||||||
ndc.binaryCallbacks = make(map[string]OnMessageCallback)
|
ndc.callbacks = make(map[string]OnMessageCallback)
|
||||||
}
|
}
|
||||||
ndc.binaryCallbacks[msgType] = callback
|
ndc.callbacks[msgType] = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnregisterMessageCallback removes the callback for a given binary message type
|
// UnregisterMessageCallback removes the callback for a given binary message type
|
||||||
func (ndc *NestriDataChannel) UnregisterMessageCallback(msgType string) {
|
func (ndc *NestriDataChannel) UnregisterMessageCallback(msgType string) {
|
||||||
if ndc.binaryCallbacks != nil {
|
if ndc.callbacks != nil {
|
||||||
delete(ndc.binaryCallbacks, msgType)
|
delete(ndc.callbacks, msgType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package relay
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
"log"
|
"log"
|
||||||
|
gen "relay/internal/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func participantHandler(participant *Participant, room *Room) {
|
func participantHandler(participant *Participant, room *Room) {
|
||||||
@@ -54,15 +57,22 @@ func participantHandler(participant *Participant, room *Room) {
|
|||||||
if room.DataChannel != nil {
|
if room.DataChannel != nil {
|
||||||
// If debug mode, decode and add our timestamp, otherwise just send to room
|
// If debug mode, decode and add our timestamp, otherwise just send to room
|
||||||
if GetFlags().Debug {
|
if GetFlags().Debug {
|
||||||
var inputMsg MessageInput
|
var inputMsg gen.ProtoMessageInput
|
||||||
if err = DecodeMessage(data, &inputMsg); err != nil {
|
if err = proto.Unmarshal(data, &inputMsg); err != nil {
|
||||||
log.Printf("Failed to decode input message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
log.Printf("Failed to decode input message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inputMsg.LatencyTracker.AddTimestamp("relay_to_node")
|
|
||||||
// Encode and send
|
protoLat := inputMsg.GetMessageBase().GetLatency()
|
||||||
if data, err = EncodeMessage(inputMsg); err != nil {
|
if protoLat != nil {
|
||||||
log.Printf("Failed to encode input message for participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
lat := LatencyTrackerFromProto(protoLat)
|
||||||
|
lat.AddTimestamp("relay_to_node")
|
||||||
|
protoLat = lat.ToProto()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal and send
|
||||||
|
if data, err = proto.Marshal(&inputMsg); err != nil {
|
||||||
|
log.Printf("Failed to marshal input message for participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = room.DataChannel.SendBinary(data); err != nil {
|
if err = room.DataChannel.SendBinary(data); err != nil {
|
||||||
@@ -94,7 +104,7 @@ func participantHandler(participant *Participant, room *Room) {
|
|||||||
// ICE callback
|
// ICE callback
|
||||||
participant.WebSocket.RegisterMessageCallback("ice", func(data []byte) {
|
participant.WebSocket.RegisterMessageCallback("ice", func(data []byte) {
|
||||||
var iceMsg MessageICECandidate
|
var iceMsg MessageICECandidate
|
||||||
if err = DecodeMessage(data, &iceMsg); err != nil {
|
if err = json.Unmarshal(data, &iceMsg); err != nil {
|
||||||
log.Printf("Failed to decode ICE message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
log.Printf("Failed to decode ICE message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -120,7 +130,7 @@ func participantHandler(participant *Participant, room *Room) {
|
|||||||
// SDP answer callback
|
// SDP answer callback
|
||||||
participant.WebSocket.RegisterMessageCallback("sdp", func(data []byte) {
|
participant.WebSocket.RegisterMessageCallback("sdp", func(data []byte) {
|
||||||
var sdpMsg MessageSDP
|
var sdpMsg MessageSDP
|
||||||
if err = DecodeMessage(data, &sdpMsg); err != nil {
|
if err = json.Unmarshal(data, &sdpMsg); err != nil {
|
||||||
log.Printf("Failed to decode SDP message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
log.Printf("Failed to decode SDP message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -130,7 +140,7 @@ func participantHandler(participant *Participant, room *Room) {
|
|||||||
// Log callback
|
// Log callback
|
||||||
participant.WebSocket.RegisterMessageCallback("log", func(data []byte) {
|
participant.WebSocket.RegisterMessageCallback("log", func(data []byte) {
|
||||||
var logMsg MessageLog
|
var logMsg MessageLog
|
||||||
if err = DecodeMessage(data, &logMsg); err != nil {
|
if err = json.Unmarshal(data, &logMsg); err != nil {
|
||||||
log.Printf("Failed to decode log message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
log.Printf("Failed to decode log message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package relay
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -81,7 +82,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Assign message handler for join request
|
// Assign message handler for join request
|
||||||
ws.RegisterMessageCallback("join", func(data []byte) {
|
ws.RegisterMessageCallback("join", func(data []byte) {
|
||||||
var joinMsg MessageJoin
|
var joinMsg MessageJoin
|
||||||
if err = DecodeMessage(data, &joinMsg); err != nil {
|
if err = json.Unmarshal(data, &joinMsg); err != nil {
|
||||||
log.Printf("Failed to decode join message: %s\n", err)
|
log.Printf("Failed to decode join message: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package relay
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
@@ -134,7 +135,7 @@ func ingestHandler(room *Room) {
|
|||||||
// ICE callback
|
// ICE callback
|
||||||
room.WebSocket.RegisterMessageCallback("ice", func(data []byte) {
|
room.WebSocket.RegisterMessageCallback("ice", func(data []byte) {
|
||||||
var iceMsg MessageICECandidate
|
var iceMsg MessageICECandidate
|
||||||
if err = DecodeMessage(data, &iceMsg); err != nil {
|
if err = json.Unmarshal(data, &iceMsg); err != nil {
|
||||||
log.Printf("Failed to decode ICE candidate message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
log.Printf("Failed to decode ICE candidate message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ func ingestHandler(room *Room) {
|
|||||||
// SDP offer callback
|
// SDP offer callback
|
||||||
room.WebSocket.RegisterMessageCallback("sdp", func(data []byte) {
|
room.WebSocket.RegisterMessageCallback("sdp", func(data []byte) {
|
||||||
var sdpMsg MessageSDP
|
var sdpMsg MessageSDP
|
||||||
if err = DecodeMessage(data, &sdpMsg); err != nil {
|
if err = json.Unmarshal(data, &sdpMsg); err != nil {
|
||||||
log.Printf("Failed to decode SDP message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
log.Printf("Failed to decode SDP message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -182,7 +183,7 @@ func ingestHandler(room *Room) {
|
|||||||
// Log callback
|
// Log callback
|
||||||
room.WebSocket.RegisterMessageCallback("log", func(data []byte) {
|
room.WebSocket.RegisterMessageCallback("log", func(data []byte) {
|
||||||
var logMsg MessageLog
|
var logMsg MessageLog
|
||||||
if err = DecodeMessage(data, &logMsg); err != nil {
|
if err = json.Unmarshal(data, &logMsg); err != nil {
|
||||||
log.Printf("Failed to decode log message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
log.Printf("Failed to decode log message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -192,7 +193,7 @@ func ingestHandler(room *Room) {
|
|||||||
// Metrics callback
|
// Metrics callback
|
||||||
room.WebSocket.RegisterMessageCallback("metrics", func(data []byte) {
|
room.WebSocket.RegisterMessageCallback("metrics", func(data []byte) {
|
||||||
var metricsMsg MessageMetrics
|
var metricsMsg MessageMetrics
|
||||||
if err = DecodeMessage(data, &metricsMsg); err != nil {
|
if err = json.Unmarshal(data, &metricsMsg); err != nil {
|
||||||
log.Printf("Failed to decode metrics message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
log.Printf("Failed to decode metrics message from ingest for room: '%s' - reason: %s\n", room.Name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package relay
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
gen "relay/internal/proto"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TimestampEntry struct {
|
type TimestampEntry struct {
|
||||||
Stage string `json:"stage"`
|
Stage string `json:"stage"`
|
||||||
Time string `json:"time"` // ISO 8601 string
|
Time time.Time `json:"time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatencyTracker provides a generic structure for measuring time taken at various stages in message processing.
|
// LatencyTracker provides a generic structure for measuring time taken at various stages in message processing.
|
||||||
@@ -15,7 +17,6 @@ type TimestampEntry struct {
|
|||||||
type LatencyTracker struct {
|
type LatencyTracker struct {
|
||||||
SequenceID string `json:"sequence_id"`
|
SequenceID string `json:"sequence_id"`
|
||||||
Timestamps []TimestampEntry `json:"timestamps"`
|
Timestamps []TimestampEntry `json:"timestamps"`
|
||||||
Metadata map[string]string `json:"metadata,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLatencyTracker initializes a new LatencyTracker with the given sequence ID
|
// NewLatencyTracker initializes a new LatencyTracker with the given sequence ID
|
||||||
@@ -23,7 +24,6 @@ func NewLatencyTracker(sequenceID string) *LatencyTracker {
|
|||||||
return &LatencyTracker{
|
return &LatencyTracker{
|
||||||
SequenceID: sequenceID,
|
SequenceID: sequenceID,
|
||||||
Timestamps: make([]TimestampEntry, 0),
|
Timestamps: make([]TimestampEntry, 0),
|
||||||
Metadata: make(map[string]string),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ func (lt *LatencyTracker) AddTimestamp(stage string) {
|
|||||||
lt.Timestamps = append(lt.Timestamps, TimestampEntry{
|
lt.Timestamps = append(lt.Timestamps, TimestampEntry{
|
||||||
Stage: stage,
|
Stage: stage,
|
||||||
// Ensure extremely precise UTC RFC3339 timestamps (down to nanoseconds)
|
// Ensure extremely precise UTC RFC3339 timestamps (down to nanoseconds)
|
||||||
Time: time.Now().UTC().Format(time.RFC3339Nano),
|
Time: time.Now().UTC(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,15 +44,11 @@ func (lt *LatencyTracker) TotalLatency() (int64, error) {
|
|||||||
|
|
||||||
var earliest, latest time.Time
|
var earliest, latest time.Time
|
||||||
for _, ts := range lt.Timestamps {
|
for _, ts := range lt.Timestamps {
|
||||||
t, err := time.Parse(time.RFC3339, ts.Time)
|
if earliest.IsZero() || ts.Time.Before(earliest) {
|
||||||
if err != nil {
|
earliest = ts.Time
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
if earliest.IsZero() || t.Before(earliest) {
|
if latest.IsZero() || ts.Time.After(latest) {
|
||||||
earliest = t
|
latest = ts.Time
|
||||||
}
|
|
||||||
if latest.IsZero() || t.After(latest) {
|
|
||||||
latest = t
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,14 +63,13 @@ func (lt *LatencyTracker) PainPoints(threshold time.Duration) []string {
|
|||||||
|
|
||||||
for _, ts := range lt.Timestamps {
|
for _, ts := range lt.Timestamps {
|
||||||
stage := ts.Stage
|
stage := ts.Stage
|
||||||
t := ts.Time
|
|
||||||
if lastStage == "" {
|
if lastStage == "" {
|
||||||
lastStage = stage
|
lastStage = stage
|
||||||
lastTime, _ = time.Parse(time.RFC3339, t)
|
lastTime = ts.Time
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTime, _ := time.Parse(time.RFC3339, t)
|
currentTime := ts.Time
|
||||||
if currentTime.Sub(lastTime) > threshold {
|
if currentTime.Sub(lastTime) > threshold {
|
||||||
painPoints = append(painPoints, fmt.Sprintf("%s -> %s", lastStage, stage))
|
painPoints = append(painPoints, fmt.Sprintf("%s -> %s", lastStage, stage))
|
||||||
}
|
}
|
||||||
@@ -87,7 +82,7 @@ func (lt *LatencyTracker) PainPoints(threshold time.Duration) []string {
|
|||||||
|
|
||||||
// StageLatency calculates the time taken between two specific stages.
|
// StageLatency calculates the time taken between two specific stages.
|
||||||
func (lt *LatencyTracker) StageLatency(startStage, endStage string) (time.Duration, error) {
|
func (lt *LatencyTracker) StageLatency(startStage, endStage string) (time.Duration, error) {
|
||||||
startTime, endTime := "", ""
|
var startTime, endTime time.Time
|
||||||
for _, ts := range lt.Timestamps {
|
for _, ts := range lt.Timestamps {
|
||||||
if ts.Stage == startStage {
|
if ts.Stage == startStage {
|
||||||
startTime = ts.Time
|
startTime = ts.Time
|
||||||
@@ -97,18 +92,41 @@ func (lt *LatencyTracker) StageLatency(startStage, endStage string) (time.Durati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if startTime == "" || endTime == "" {
|
/*if startTime == "" || endTime == "" {
|
||||||
return 0, fmt.Errorf("missing timestamps for stages: %s -> %s", startStage, endStage)
|
return 0, fmt.Errorf("missing timestamps for stages: %s -> %s", startStage, endStage)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return endTime.Sub(startTime), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
start, err := time.Parse(time.RFC3339, startTime)
|
func LatencyTrackerFromProto(protolt *gen.ProtoLatencyTracker) *LatencyTracker {
|
||||||
if err != nil {
|
ret := &LatencyTracker{
|
||||||
return 0, err
|
SequenceID: protolt.GetSequenceId(),
|
||||||
}
|
Timestamps: make([]TimestampEntry, 0),
|
||||||
end, err := time.Parse(time.RFC3339, endTime)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return end.Sub(start), nil
|
for _, ts := range protolt.GetTimestamps() {
|
||||||
|
ret.Timestamps = append(ret.Timestamps, TimestampEntry{
|
||||||
|
Stage: ts.GetStage(),
|
||||||
|
Time: ts.GetTime().AsTime(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lt *LatencyTracker) ToProto() *gen.ProtoLatencyTracker {
|
||||||
|
ret := &gen.ProtoLatencyTracker{
|
||||||
|
SequenceId: lt.SequenceID,
|
||||||
|
Timestamps: make([]*gen.ProtoTimestampEntry, len(lt.Timestamps)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, timestamp := range lt.Timestamps {
|
||||||
|
ret.Timestamps[i] = &gen.ProtoTimestampEntry{
|
||||||
|
Stage: timestamp.Stage,
|
||||||
|
Time: timestamppb.New(timestamp.Time),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,17 @@
|
|||||||
package relay
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnMessageCallback is a callback for binary messages of given type
|
// OnMessageCallback is a callback for messages of given type
|
||||||
type OnMessageCallback func(data []byte)
|
type OnMessageCallback func(data []byte)
|
||||||
|
|
||||||
// MessageBase is the base type for WS/DC messages.
|
// MessageBase is the base type for WS/DC messages.
|
||||||
type MessageBase struct {
|
type MessageBase struct {
|
||||||
PayloadType string `json:"payload_type"`
|
PayloadType string `json:"payload_type"`
|
||||||
LatencyTracker LatencyTracker `json:"latency_tracker,omitempty"`
|
Latency *LatencyTracker `json:"latency,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
// MessageInput represents an input message.
|
|
||||||
type MessageInput struct {
|
|
||||||
MessageBase
|
|
||||||
Data string `json:"data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageLog represents a log message.
|
// MessageLog represents a log message.
|
||||||
@@ -93,50 +83,6 @@ type MessageAnswer struct {
|
|||||||
AnswerType AnswerType `json:"answer_type"`
|
AnswerType AnswerType `json:"answer_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeMessage encodes a message to be sent with gzip compression
|
|
||||||
func EncodeMessage(msg interface{}) ([]byte, error) {
|
|
||||||
// Marshal the message to JSON
|
|
||||||
data, err := json.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to encode message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gzip compress the JSON
|
|
||||||
var compressedData bytes.Buffer
|
|
||||||
writer := gzip.NewWriter(&compressedData)
|
|
||||||
_, err = writer.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to compress message: %w", err)
|
|
||||||
}
|
|
||||||
if err := writer.Close(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to finalize compression: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return compressedData.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeMessage decodes a message received with gzip decompression
|
|
||||||
func DecodeMessage(data []byte, target interface{}) error {
|
|
||||||
// Gzip decompress the data
|
|
||||||
reader, err := gzip.NewReader(bytes.NewReader(data))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to initialize decompression: %w", err)
|
|
||||||
}
|
|
||||||
defer func(reader *gzip.Reader) {
|
|
||||||
if err = reader.Close(); err != nil {
|
|
||||||
fmt.Printf("failed to close reader: %v\n", err)
|
|
||||||
}
|
|
||||||
}(reader)
|
|
||||||
|
|
||||||
// Decode the JSON
|
|
||||||
err = json.NewDecoder(reader).Decode(target)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to decode message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendLogMessageWS sends a log message to the given WebSocket connection.
|
// SendLogMessageWS sends a log message to the given WebSocket connection.
|
||||||
func (ws *SafeWebSocket) SendLogMessageWS(level, message string) error {
|
func (ws *SafeWebSocket) SendLogMessageWS(level, message string) error {
|
||||||
msg := MessageLog{
|
msg := MessageLog{
|
||||||
@@ -145,12 +91,7 @@ func (ws *SafeWebSocket) SendLogMessageWS(level, message string) error {
|
|||||||
Message: message,
|
Message: message,
|
||||||
Time: time.Now().Format(time.RFC3339),
|
Time: time.Now().Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
encoded, err := EncodeMessage(msg)
|
return ws.SendJSON(msg)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode log message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ws.SendBinary(encoded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMetricsMessageWS sends a metrics message to the given WebSocket connection.
|
// SendMetricsMessageWS sends a metrics message to the given WebSocket connection.
|
||||||
@@ -162,12 +103,7 @@ func (ws *SafeWebSocket) SendMetricsMessageWS(usageCPU, usageMemory float64, upt
|
|||||||
Uptime: uptime,
|
Uptime: uptime,
|
||||||
PipelineLatency: pipelineLatency,
|
PipelineLatency: pipelineLatency,
|
||||||
}
|
}
|
||||||
encoded, err := EncodeMessage(msg)
|
return ws.SendJSON(msg)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode metrics message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ws.SendBinary(encoded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendICECandidateMessageWS sends an ICE candidate message to the given WebSocket connection.
|
// SendICECandidateMessageWS sends an ICE candidate message to the given WebSocket connection.
|
||||||
@@ -176,12 +112,7 @@ func (ws *SafeWebSocket) SendICECandidateMessageWS(candidate webrtc.ICECandidate
|
|||||||
MessageBase: MessageBase{PayloadType: "ice"},
|
MessageBase: MessageBase{PayloadType: "ice"},
|
||||||
Candidate: candidate,
|
Candidate: candidate,
|
||||||
}
|
}
|
||||||
encoded, err := EncodeMessage(msg)
|
return ws.SendJSON(msg)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode ICE candidate message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ws.SendBinary(encoded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendSDPMessageWS sends an SDP message to the given WebSocket connection.
|
// SendSDPMessageWS sends an SDP message to the given WebSocket connection.
|
||||||
@@ -190,12 +121,7 @@ func (ws *SafeWebSocket) SendSDPMessageWS(sdp webrtc.SessionDescription) error {
|
|||||||
MessageBase: MessageBase{PayloadType: "sdp"},
|
MessageBase: MessageBase{PayloadType: "sdp"},
|
||||||
SDP: sdp,
|
SDP: sdp,
|
||||||
}
|
}
|
||||||
encoded, err := EncodeMessage(msg)
|
return ws.SendJSON(msg)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode SDP message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ws.SendBinary(encoded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendAnswerMessageWS sends an answer message to the given WebSocket connection.
|
// SendAnswerMessageWS sends an answer message to the given WebSocket connection.
|
||||||
@@ -204,24 +130,5 @@ func (ws *SafeWebSocket) SendAnswerMessageWS(answer AnswerType) error {
|
|||||||
MessageBase: MessageBase{PayloadType: "answer"},
|
MessageBase: MessageBase{PayloadType: "answer"},
|
||||||
AnswerType: answer,
|
AnswerType: answer,
|
||||||
}
|
}
|
||||||
encoded, err := EncodeMessage(msg)
|
return ws.SendJSON(msg)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode answer message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ws.SendBinary(encoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendInputMessageDC sends an input message to the given DataChannel connection.
|
|
||||||
func (ndc *NestriDataChannel) SendInputMessageDC(data string) error {
|
|
||||||
msg := MessageInput{
|
|
||||||
MessageBase: MessageBase{PayloadType: "input"},
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
encoded, err := EncodeMessage(msg)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode input message: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ndc.SendBinary(encoded)
|
|
||||||
}
|
}
|
||||||
|
|||||||
203
packages/relay/internal/proto/latency_tracker.pb.go
Normal file
203
packages/relay/internal/proto/latency_tracker.pb.go
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.4
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: latency_tracker.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProtoTimestampEntry struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Stage string `protobuf:"bytes,1,opt,name=stage,proto3" json:"stage,omitempty"`
|
||||||
|
Time *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=time,proto3" json:"time,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoTimestampEntry) Reset() {
|
||||||
|
*x = ProtoTimestampEntry{}
|
||||||
|
mi := &file_latency_tracker_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoTimestampEntry) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoTimestampEntry) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoTimestampEntry) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_latency_tracker_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoTimestampEntry.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoTimestampEntry) Descriptor() ([]byte, []int) {
|
||||||
|
return file_latency_tracker_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoTimestampEntry) GetStage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Stage
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoTimestampEntry) GetTime() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.Time
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoLatencyTracker struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
SequenceId string `protobuf:"bytes,1,opt,name=sequence_id,json=sequenceId,proto3" json:"sequence_id,omitempty"`
|
||||||
|
Timestamps []*ProtoTimestampEntry `protobuf:"bytes,2,rep,name=timestamps,proto3" json:"timestamps,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoLatencyTracker) Reset() {
|
||||||
|
*x = ProtoLatencyTracker{}
|
||||||
|
mi := &file_latency_tracker_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoLatencyTracker) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoLatencyTracker) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoLatencyTracker) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_latency_tracker_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoLatencyTracker.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoLatencyTracker) Descriptor() ([]byte, []int) {
|
||||||
|
return file_latency_tracker_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoLatencyTracker) GetSequenceId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.SequenceId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoLatencyTracker) GetTimestamps() []*ProtoTimestampEntry {
|
||||||
|
if x != nil {
|
||||||
|
return x.Timestamps
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_latency_tracker_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_latency_tracker_proto_rawDesc = string([]byte{
|
||||||
|
0x0a, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x65,
|
||||||
|
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
|
||||||
|
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||||
|
0x5b, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||||
|
0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x04,
|
||||||
|
0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
|
||||||
|
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
|
||||||
|
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x72, 0x0a, 0x13,
|
||||||
|
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x54, 0x72, 0x61, 0x63,
|
||||||
|
0x6b, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f,
|
||||||
|
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e,
|
||||||
|
0x63, 0x65, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||||
|
0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x45,
|
||||||
|
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73,
|
||||||
|
0x42, 0x16, 0x5a, 0x14, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
|
0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
})
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_latency_tracker_proto_rawDescOnce sync.Once
|
||||||
|
file_latency_tracker_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_latency_tracker_proto_rawDescGZIP() []byte {
|
||||||
|
file_latency_tracker_proto_rawDescOnce.Do(func() {
|
||||||
|
file_latency_tracker_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_latency_tracker_proto_rawDesc), len(file_latency_tracker_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_latency_tracker_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_latency_tracker_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_latency_tracker_proto_goTypes = []any{
|
||||||
|
(*ProtoTimestampEntry)(nil), // 0: proto.ProtoTimestampEntry
|
||||||
|
(*ProtoLatencyTracker)(nil), // 1: proto.ProtoLatencyTracker
|
||||||
|
(*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
|
||||||
|
}
|
||||||
|
var file_latency_tracker_proto_depIdxs = []int32{
|
||||||
|
2, // 0: proto.ProtoTimestampEntry.time:type_name -> google.protobuf.Timestamp
|
||||||
|
0, // 1: proto.ProtoLatencyTracker.timestamps:type_name -> proto.ProtoTimestampEntry
|
||||||
|
2, // [2:2] is the sub-list for method output_type
|
||||||
|
2, // [2:2] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_latency_tracker_proto_init() }
|
||||||
|
func file_latency_tracker_proto_init() {
|
||||||
|
if File_latency_tracker_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_latency_tracker_proto_rawDesc), len(file_latency_tracker_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_latency_tracker_proto_goTypes,
|
||||||
|
DependencyIndexes: file_latency_tracker_proto_depIdxs,
|
||||||
|
MessageInfos: file_latency_tracker_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_latency_tracker_proto = out.File
|
||||||
|
file_latency_tracker_proto_goTypes = nil
|
||||||
|
file_latency_tracker_proto_depIdxs = nil
|
||||||
|
}
|
||||||
207
packages/relay/internal/proto/messages.pb.go
Normal file
207
packages/relay/internal/proto/messages.pb.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.4
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: messages.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProtoMessageBase struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
PayloadType string `protobuf:"bytes,1,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"`
|
||||||
|
Latency *ProtoLatencyTracker `protobuf:"bytes,2,opt,name=latency,proto3" json:"latency,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageBase) Reset() {
|
||||||
|
*x = ProtoMessageBase{}
|
||||||
|
mi := &file_messages_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageBase) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMessageBase) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMessageBase) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMessageBase.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMessageBase) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageBase) GetPayloadType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.PayloadType
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageBase) GetLatency() *ProtoLatencyTracker {
|
||||||
|
if x != nil {
|
||||||
|
return x.Latency
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoMessageInput struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
MessageBase *ProtoMessageBase `protobuf:"bytes,1,opt,name=message_base,json=messageBase,proto3" json:"message_base,omitempty"`
|
||||||
|
Data *ProtoInput `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageInput) Reset() {
|
||||||
|
*x = ProtoMessageInput{}
|
||||||
|
mi := &file_messages_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageInput) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMessageInput) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMessageInput) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMessageInput.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMessageInput) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageInput) GetMessageBase() *ProtoMessageBase {
|
||||||
|
if x != nil {
|
||||||
|
return x.MessageBase
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMessageInput) GetData() *ProtoInput {
|
||||||
|
if x != nil {
|
||||||
|
return x.Data
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_messages_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_messages_proto_rawDesc = string([]byte{
|
||||||
|
0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x74, 0x72,
|
||||||
|
0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6b, 0x0a, 0x10, 0x50,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12,
|
||||||
|
0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79,
|
||||||
|
0x70, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20,
|
||||||
|
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x52,
|
||||||
|
0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x76, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3a, 0x0a,
|
||||||
|
0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6d, 0x65,
|
||||||
|
0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x04, 0x64, 0x61, 0x74,
|
||||||
|
0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||||
|
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||||
|
0x42, 0x16, 0x5a, 0x14, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
|
0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
})
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_messages_proto_rawDescOnce sync.Once
|
||||||
|
file_messages_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_messages_proto_rawDescGZIP() []byte {
|
||||||
|
file_messages_proto_rawDescOnce.Do(func() {
|
||||||
|
file_messages_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_messages_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_messages_proto_goTypes = []any{
|
||||||
|
(*ProtoMessageBase)(nil), // 0: proto.ProtoMessageBase
|
||||||
|
(*ProtoMessageInput)(nil), // 1: proto.ProtoMessageInput
|
||||||
|
(*ProtoLatencyTracker)(nil), // 2: proto.ProtoLatencyTracker
|
||||||
|
(*ProtoInput)(nil), // 3: proto.ProtoInput
|
||||||
|
}
|
||||||
|
var file_messages_proto_depIdxs = []int32{
|
||||||
|
2, // 0: proto.ProtoMessageBase.latency:type_name -> proto.ProtoLatencyTracker
|
||||||
|
0, // 1: proto.ProtoMessageInput.message_base:type_name -> proto.ProtoMessageBase
|
||||||
|
3, // 2: proto.ProtoMessageInput.data:type_name -> proto.ProtoInput
|
||||||
|
3, // [3:3] is the sub-list for method output_type
|
||||||
|
3, // [3:3] is the sub-list for method input_type
|
||||||
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
|
0, // [0:3] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_messages_proto_init() }
|
||||||
|
func file_messages_proto_init() {
|
||||||
|
if File_messages_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_types_proto_init()
|
||||||
|
file_latency_tracker_proto_init()
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_messages_proto_goTypes,
|
||||||
|
DependencyIndexes: file_messages_proto_depIdxs,
|
||||||
|
MessageInfos: file_messages_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_messages_proto = out.File
|
||||||
|
file_messages_proto_goTypes = nil
|
||||||
|
file_messages_proto_depIdxs = nil
|
||||||
|
}
|
||||||
713
packages/relay/internal/proto/types.pb.go
Normal file
713
packages/relay/internal/proto/types.pb.go
Normal file
@@ -0,0 +1,713 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.4
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: types.proto
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// MouseMove message
|
||||||
|
type ProtoMouseMove struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseMove"
|
||||||
|
X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"`
|
||||||
|
Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) Reset() {
|
||||||
|
*x = ProtoMouseMove{}
|
||||||
|
mi := &file_types_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMouseMove) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMouseMove.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMouseMove) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) GetX() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.X
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMove) GetY() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Y
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseMoveAbs message
|
||||||
|
type ProtoMouseMoveAbs struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseMoveAbs"
|
||||||
|
X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"`
|
||||||
|
Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) Reset() {
|
||||||
|
*x = ProtoMouseMoveAbs{}
|
||||||
|
mi := &file_types_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMouseMoveAbs) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMouseMoveAbs.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMouseMoveAbs) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) GetX() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.X
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseMoveAbs) GetY() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Y
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseWheel message
|
||||||
|
type ProtoMouseWheel struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseWheel"
|
||||||
|
X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"`
|
||||||
|
Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) Reset() {
|
||||||
|
*x = ProtoMouseWheel{}
|
||||||
|
mi := &file_types_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMouseWheel) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMouseWheel.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMouseWheel) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) GetX() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.X
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseWheel) GetY() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Y
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseKeyDown message
|
||||||
|
type ProtoMouseKeyDown struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseKeyDown"
|
||||||
|
Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyDown) Reset() {
|
||||||
|
*x = ProtoMouseKeyDown{}
|
||||||
|
mi := &file_types_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyDown) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMouseKeyDown) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyDown) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMouseKeyDown.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMouseKeyDown) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyDown) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyDown) GetKey() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseKeyUp message
|
||||||
|
type ProtoMouseKeyUp struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseKeyUp"
|
||||||
|
Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyUp) Reset() {
|
||||||
|
*x = ProtoMouseKeyUp{}
|
||||||
|
mi := &file_types_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyUp) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoMouseKeyUp) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyUp) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoMouseKeyUp.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoMouseKeyUp) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyUp) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoMouseKeyUp) GetKey() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDown message
|
||||||
|
type ProtoKeyDown struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "KeyDown"
|
||||||
|
Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyDown) Reset() {
|
||||||
|
*x = ProtoKeyDown{}
|
||||||
|
mi := &file_types_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyDown) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoKeyDown) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoKeyDown) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[5]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoKeyDown.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoKeyDown) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyDown) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyDown) GetKey() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyUp message
|
||||||
|
type ProtoKeyUp struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "KeyUp"
|
||||||
|
Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyUp) Reset() {
|
||||||
|
*x = ProtoKeyUp{}
|
||||||
|
mi := &file_types_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyUp) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoKeyUp) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoKeyUp) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[6]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoKeyUp.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoKeyUp) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyUp) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoKeyUp) GetKey() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Key
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union of all Input types
|
||||||
|
type ProtoInput struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
// Types that are valid to be assigned to InputType:
|
||||||
|
//
|
||||||
|
// *ProtoInput_MouseMove
|
||||||
|
// *ProtoInput_MouseMoveAbs
|
||||||
|
// *ProtoInput_MouseWheel
|
||||||
|
// *ProtoInput_MouseKeyDown
|
||||||
|
// *ProtoInput_MouseKeyUp
|
||||||
|
// *ProtoInput_KeyDown
|
||||||
|
// *ProtoInput_KeyUp
|
||||||
|
InputType isProtoInput_InputType `protobuf_oneof:"input_type"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) Reset() {
|
||||||
|
*x = ProtoInput{}
|
||||||
|
mi := &file_types_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoInput) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoInput) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_types_proto_msgTypes[7]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoInput.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoInput) Descriptor() ([]byte, []int) {
|
||||||
|
return file_types_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetInputType() isProtoInput_InputType {
|
||||||
|
if x != nil {
|
||||||
|
return x.InputType
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetMouseMove() *ProtoMouseMove {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_MouseMove); ok {
|
||||||
|
return x.MouseMove
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetMouseMoveAbs() *ProtoMouseMoveAbs {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_MouseMoveAbs); ok {
|
||||||
|
return x.MouseMoveAbs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetMouseWheel() *ProtoMouseWheel {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_MouseWheel); ok {
|
||||||
|
return x.MouseWheel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetMouseKeyDown() *ProtoMouseKeyDown {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_MouseKeyDown); ok {
|
||||||
|
return x.MouseKeyDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetMouseKeyUp() *ProtoMouseKeyUp {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_MouseKeyUp); ok {
|
||||||
|
return x.MouseKeyUp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetKeyDown() *ProtoKeyDown {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_KeyDown); ok {
|
||||||
|
return x.KeyDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoInput) GetKeyUp() *ProtoKeyUp {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.InputType.(*ProtoInput_KeyUp); ok {
|
||||||
|
return x.KeyUp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type isProtoInput_InputType interface {
|
||||||
|
isProtoInput_InputType()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_MouseMove struct {
|
||||||
|
MouseMove *ProtoMouseMove `protobuf:"bytes,1,opt,name=mouse_move,json=mouseMove,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_MouseMoveAbs struct {
|
||||||
|
MouseMoveAbs *ProtoMouseMoveAbs `protobuf:"bytes,2,opt,name=mouse_move_abs,json=mouseMoveAbs,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_MouseWheel struct {
|
||||||
|
MouseWheel *ProtoMouseWheel `protobuf:"bytes,3,opt,name=mouse_wheel,json=mouseWheel,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_MouseKeyDown struct {
|
||||||
|
MouseKeyDown *ProtoMouseKeyDown `protobuf:"bytes,4,opt,name=mouse_key_down,json=mouseKeyDown,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_MouseKeyUp struct {
|
||||||
|
MouseKeyUp *ProtoMouseKeyUp `protobuf:"bytes,5,opt,name=mouse_key_up,json=mouseKeyUp,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_KeyDown struct {
|
||||||
|
KeyDown *ProtoKeyDown `protobuf:"bytes,6,opt,name=key_down,json=keyDown,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtoInput_KeyUp struct {
|
||||||
|
KeyUp *ProtoKeyUp `protobuf:"bytes,7,opt,name=key_up,json=keyUp,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoInput_MouseMove) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_MouseMoveAbs) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_MouseWheel) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_MouseKeyDown) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_MouseKeyUp) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_KeyDown) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
func (*ProtoInput_KeyUp) isProtoInput_InputType() {}
|
||||||
|
|
||||||
|
var File_types_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_types_proto_rawDesc = string([]byte{
|
||||||
|
0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75,
|
||||||
|
0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18,
|
||||||
|
0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20,
|
||||||
|
0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x43, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d,
|
||||||
|
0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x41, 0x62, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
||||||
|
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
|
||||||
|
0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a,
|
||||||
|
0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x41, 0x0a, 0x0f, 0x50,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65, 0x65, 0x6c, 0x12, 0x12,
|
||||||
|
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
|
||||||
|
0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78,
|
||||||
|
0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x39,
|
||||||
|
0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44,
|
||||||
|
0x6f, 0x77, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02,
|
||||||
|
0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x37, 0x0a, 0x0f, 0x50, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x12, 0x0a, 0x04,
|
||||||
|
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||||
|
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b,
|
||||||
|
0x65, 0x79, 0x22, 0x34, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x44, 0x6f,
|
||||||
|
0x77, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
|
||||||
|
0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x32, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||||
|
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xab, 0x03, 0x0a,
|
||||||
|
0x0a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x6d,
|
||||||
|
0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
|
0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75,
|
||||||
|
0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4d,
|
||||||
|
0x6f, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x6f, 0x76,
|
||||||
|
0x65, 0x5f, 0x61, 0x62, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f,
|
||||||
|
0x76, 0x65, 0x41, 0x62, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f,
|
||||||
|
0x76, 0x65, 0x41, 0x62, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x77,
|
||||||
|
0x68, 0x65, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65,
|
||||||
|
0x65, 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65, 0x65, 0x6c,
|
||||||
|
0x12, 0x40, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x6f,
|
||||||
|
0x77, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44, 0x6f,
|
||||||
|
0x77, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44, 0x6f,
|
||||||
|
0x77, 0x6e, 0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f,
|
||||||
|
0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70,
|
||||||
|
0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x30,
|
||||||
|
0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
|
||||||
|
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65,
|
||||||
|
0x79, 0x44, 0x6f, 0x77, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x6f, 0x77, 0x6e,
|
||||||
|
0x12, 0x2a, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||||
|
0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65,
|
||||||
|
0x79, 0x55, 0x70, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x55, 0x70, 0x42, 0x0c, 0x0a, 0x0a,
|
||||||
|
0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x16, 0x5a, 0x14, 0x72, 0x65,
|
||||||
|
0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
})
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_types_proto_rawDescOnce sync.Once
|
||||||
|
file_types_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_types_proto_rawDescGZIP() []byte {
|
||||||
|
file_types_proto_rawDescOnce.Do(func() {
|
||||||
|
file_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_types_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||||
|
var file_types_proto_goTypes = []any{
|
||||||
|
(*ProtoMouseMove)(nil), // 0: proto.ProtoMouseMove
|
||||||
|
(*ProtoMouseMoveAbs)(nil), // 1: proto.ProtoMouseMoveAbs
|
||||||
|
(*ProtoMouseWheel)(nil), // 2: proto.ProtoMouseWheel
|
||||||
|
(*ProtoMouseKeyDown)(nil), // 3: proto.ProtoMouseKeyDown
|
||||||
|
(*ProtoMouseKeyUp)(nil), // 4: proto.ProtoMouseKeyUp
|
||||||
|
(*ProtoKeyDown)(nil), // 5: proto.ProtoKeyDown
|
||||||
|
(*ProtoKeyUp)(nil), // 6: proto.ProtoKeyUp
|
||||||
|
(*ProtoInput)(nil), // 7: proto.ProtoInput
|
||||||
|
}
|
||||||
|
var file_types_proto_depIdxs = []int32{
|
||||||
|
0, // 0: proto.ProtoInput.mouse_move:type_name -> proto.ProtoMouseMove
|
||||||
|
1, // 1: proto.ProtoInput.mouse_move_abs:type_name -> proto.ProtoMouseMoveAbs
|
||||||
|
2, // 2: proto.ProtoInput.mouse_wheel:type_name -> proto.ProtoMouseWheel
|
||||||
|
3, // 3: proto.ProtoInput.mouse_key_down:type_name -> proto.ProtoMouseKeyDown
|
||||||
|
4, // 4: proto.ProtoInput.mouse_key_up:type_name -> proto.ProtoMouseKeyUp
|
||||||
|
5, // 5: proto.ProtoInput.key_down:type_name -> proto.ProtoKeyDown
|
||||||
|
6, // 6: proto.ProtoInput.key_up:type_name -> proto.ProtoKeyUp
|
||||||
|
7, // [7:7] is the sub-list for method output_type
|
||||||
|
7, // [7:7] is the sub-list for method input_type
|
||||||
|
7, // [7:7] is the sub-list for extension type_name
|
||||||
|
7, // [7:7] is the sub-list for extension extendee
|
||||||
|
0, // [0:7] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_types_proto_init() }
|
||||||
|
func file_types_proto_init() {
|
||||||
|
if File_types_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_types_proto_msgTypes[7].OneofWrappers = []any{
|
||||||
|
(*ProtoInput_MouseMove)(nil),
|
||||||
|
(*ProtoInput_MouseMoveAbs)(nil),
|
||||||
|
(*ProtoInput_MouseWheel)(nil),
|
||||||
|
(*ProtoInput_MouseKeyDown)(nil),
|
||||||
|
(*ProtoInput_MouseKeyUp)(nil),
|
||||||
|
(*ProtoInput_KeyDown)(nil),
|
||||||
|
(*ProtoInput_KeyUp)(nil),
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 8,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_types_proto_goTypes,
|
||||||
|
DependencyIndexes: file_types_proto_depIdxs,
|
||||||
|
MessageInfos: file_types_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_types_proto = out.File
|
||||||
|
file_types_proto_goTypes = nil
|
||||||
|
file_types_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package relay
|
package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -11,7 +12,7 @@ type SafeWebSocket struct {
|
|||||||
*websocket.Conn
|
*websocket.Conn
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
closeCallback func() // OnClose callback
|
closeCallback func() // OnClose callback
|
||||||
binaryCallbacks map[string]OnMessageCallback // MessageBase type -> callback
|
callbacks map[string]OnMessageCallback // MessageBase type -> callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSafeWebSocket creates a new SafeWebSocket from *websocket.Conn
|
// NewSafeWebSocket creates a new SafeWebSocket from *websocket.Conn
|
||||||
@@ -19,13 +20,13 @@ func NewSafeWebSocket(conn *websocket.Conn) *SafeWebSocket {
|
|||||||
ws := &SafeWebSocket{
|
ws := &SafeWebSocket{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
closeCallback: nil,
|
closeCallback: nil,
|
||||||
binaryCallbacks: make(map[string]OnMessageCallback),
|
callbacks: make(map[string]OnMessageCallback),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch a goroutine to handle binary messages
|
// Launch a goroutine to handle messages
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
// Read binary message
|
// Read message
|
||||||
kind, data, err := ws.Conn.ReadMessage()
|
kind, data, err := ws.Conn.ReadMessage()
|
||||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNoStatusReceived) {
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNoStatusReceived) {
|
||||||
// If unexpected close error, break
|
// If unexpected close error, break
|
||||||
@@ -42,22 +43,23 @@ func NewSafeWebSocket(conn *websocket.Conn) *SafeWebSocket {
|
|||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case websocket.TextMessage:
|
case websocket.TextMessage:
|
||||||
// Ignore, we use binary messages
|
|
||||||
continue
|
|
||||||
case websocket.BinaryMessage:
|
|
||||||
// Decode message
|
// Decode message
|
||||||
var msg MessageBase
|
var msg MessageBase
|
||||||
if err = DecodeMessage(data, &msg); err != nil {
|
if err = json.Unmarshal(data, &msg); err != nil {
|
||||||
log.Printf("Failed to decode binary WebSocket message, reason: %s\n", err)
|
log.Printf("Failed to decode text WebSocket message, reason: %s\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle message type callback
|
// Handle message type callback
|
||||||
if callback, ok := ws.binaryCallbacks[msg.PayloadType]; ok {
|
if callback, ok := ws.callbacks[msg.PayloadType]; ok {
|
||||||
callback(data)
|
callback(data)
|
||||||
} // TODO: Log unknown message type?
|
} // TODO: Log unknown message type?
|
||||||
|
break
|
||||||
|
case websocket.BinaryMessage:
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
log.Printf("Unknown WebSocket message type: %d\n", kind)
|
log.Printf("Unknown WebSocket message type: %d\n", kind)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,18 +90,18 @@ func (ws *SafeWebSocket) SendBinary(data []byte) error {
|
|||||||
func (ws *SafeWebSocket) RegisterMessageCallback(msgType string, callback OnMessageCallback) {
|
func (ws *SafeWebSocket) RegisterMessageCallback(msgType string, callback OnMessageCallback) {
|
||||||
ws.Lock()
|
ws.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.Unlock()
|
||||||
if ws.binaryCallbacks == nil {
|
if ws.callbacks == nil {
|
||||||
ws.binaryCallbacks = make(map[string]OnMessageCallback)
|
ws.callbacks = make(map[string]OnMessageCallback)
|
||||||
}
|
}
|
||||||
ws.binaryCallbacks[msgType] = callback
|
ws.callbacks[msgType] = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnregisterMessageCallback removes the callback for binary message of given type
|
// UnregisterMessageCallback removes the callback for binary message of given type
|
||||||
func (ws *SafeWebSocket) UnregisterMessageCallback(msgType string) {
|
func (ws *SafeWebSocket) UnregisterMessageCallback(msgType string) {
|
||||||
ws.Lock()
|
ws.Lock()
|
||||||
defer ws.Unlock()
|
defer ws.Unlock()
|
||||||
if ws.binaryCallbacks != nil {
|
if ws.callbacks != nil {
|
||||||
delete(ws.binaryCallbacks, msgType)
|
delete(ws.callbacks, msgType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ func (ws *SafeWebSocket) RegisterOnClose(callback func()) {
|
|||||||
ws.closeCallback = func() {
|
ws.closeCallback = func() {
|
||||||
// Clear our callbacks
|
// Clear our callbacks
|
||||||
ws.Lock()
|
ws.Lock()
|
||||||
ws.binaryCallbacks = nil
|
ws.callbacks = nil
|
||||||
ws.Unlock()
|
ws.Unlock()
|
||||||
// Call the callback
|
// Call the callback
|
||||||
callback()
|
callback()
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ serde = {version = "1.0.214", features = ["derive"] }
|
|||||||
tokio = { version = "1.41.0", features = ["full"] }
|
tokio = { version = "1.41.0", features = ["full"] }
|
||||||
clap = { version = "4.5.20", features = ["env"] }
|
clap = { version = "4.5.20", features = ["env"] }
|
||||||
serde_json = "1.0.132"
|
serde_json = "1.0.132"
|
||||||
webrtc = "0.11.0"
|
webrtc = "0.12.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
rand = "0.8.5"
|
rand = "0.9.0"
|
||||||
rustls = { version = "0.23.17", features = ["ring"] }
|
rustls = { version = "0.23.17", features = ["ring"] }
|
||||||
tokio-util = "0.7.12"
|
tokio-tungstenite = { version = "0.26.1", features = ["native-tls"] }
|
||||||
flate2 = "1.0.35"
|
|
||||||
tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] }
|
|
||||||
log = { version = "0.4.22", features = ["std"] }
|
log = { version = "0.4.22", features = ["std"] }
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
num-derive = "0.4.2"
|
num-derive = "0.4.2"
|
||||||
num-traits = "0.2.19"
|
num-traits = "0.2.19"
|
||||||
|
prost = "0.13.4"
|
||||||
|
prost-types = "0.13.4"
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ impl AppArgs {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.parse::<u32>()
|
.parse::<u32>()
|
||||||
.unwrap_or(60),
|
.unwrap_or(60),
|
||||||
relay_url: matches.get_one::<String>("relay-url").unwrap().clone(),
|
relay_url: matches
|
||||||
|
.get_one::<String>("relay-url")
|
||||||
|
.expect("relay url cannot be empty")
|
||||||
|
.clone(),
|
||||||
// Generate random room name if not provided
|
// Generate random room name if not provided
|
||||||
room: matches
|
room: matches
|
||||||
.get_one::<String>("room")
|
.get_one::<String>("room")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct TimestampEntry {
|
pub struct TimestampEntry {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod latency;
|
|||||||
mod messages;
|
mod messages;
|
||||||
mod nestrisink;
|
mod nestrisink;
|
||||||
mod websocket;
|
mod websocket;
|
||||||
|
mod proto;
|
||||||
|
|
||||||
use crate::args::encoding_args;
|
use crate::args::encoding_args;
|
||||||
use crate::nestrisink::NestriSignaller;
|
use crate::nestrisink::NestriSignaller;
|
||||||
|
|||||||
@@ -1,50 +1,14 @@
|
|||||||
use std::error::Error;
|
use crate::latency::LatencyTracker;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use flate2::Compression;
|
|
||||||
use flate2::read::GzDecoder;
|
|
||||||
use flate2::write::GzEncoder;
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::error::Error;
|
||||||
use webrtc::ice_transport::ice_candidate::RTCIceCandidateInit;
|
use webrtc::ice_transport::ice_candidate::RTCIceCandidateInit;
|
||||||
use webrtc::peer_connection::sdp::session_description::RTCSessionDescription;
|
use webrtc::peer_connection::sdp::session_description::RTCSessionDescription;
|
||||||
use crate::latency::LatencyTracker;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
pub enum InputMessage {
|
|
||||||
#[serde(rename = "mousemove")]
|
|
||||||
MouseMove { x: i32, y: i32 },
|
|
||||||
|
|
||||||
#[serde(rename = "mousemoveabs")]
|
|
||||||
MouseMoveAbs { x: i32, y: i32 },
|
|
||||||
|
|
||||||
#[serde(rename = "wheel")]
|
|
||||||
Wheel { x: f64, y: f64 },
|
|
||||||
|
|
||||||
#[serde(rename = "mousedown")]
|
|
||||||
MouseDown { key: i32 },
|
|
||||||
// Add other variants as needed
|
|
||||||
#[serde(rename = "mouseup")]
|
|
||||||
MouseUp { key: i32 },
|
|
||||||
|
|
||||||
#[serde(rename = "keydown")]
|
|
||||||
KeyDown { key: i32 },
|
|
||||||
|
|
||||||
#[serde(rename = "keyup")]
|
|
||||||
KeyUp { key: i32 },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct MessageBase {
|
pub struct MessageBase {
|
||||||
pub payload_type: String,
|
pub payload_type: String,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct MessageInput {
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub base: MessageBase,
|
|
||||||
pub data: String,
|
|
||||||
pub latency: Option<LatencyTracker>,
|
pub latency: Option<LatencyTracker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,34 +100,21 @@ pub struct MessageAnswer {
|
|||||||
pub answer_type: AnswerType,
|
pub answer_type: AnswerType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_message<T: Serialize>(message: &T) -> Result<Vec<u8>, Box<dyn Error>> {
|
pub fn encode_message<T: Serialize>(message: &T) -> Result<String, Box<dyn Error>> {
|
||||||
// Serialize the message to JSON
|
// Serialize the message to JSON
|
||||||
let json = serde_json::to_string(message)?;
|
let json = serde_json::to_string(message)?;
|
||||||
|
Ok(json)
|
||||||
// Compress the JSON using gzip
|
|
||||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
|
|
||||||
encoder.write_all(json.as_bytes())?;
|
|
||||||
let compressed_data = encoder.finish()?;
|
|
||||||
|
|
||||||
Ok(compressed_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_message(data: &[u8]) -> Result<MessageBase, Box<dyn Error + Send + Sync>> {
|
pub fn decode_message(data: String) -> Result<MessageBase, Box<dyn Error + Send + Sync>> {
|
||||||
let mut decoder = GzDecoder::new(data);
|
println!("Data: {}", data);
|
||||||
let mut decompressed_data = String::new();
|
let base_message: MessageBase = serde_json::from_str(&data)?;
|
||||||
decoder.read_to_string(&mut decompressed_data)?;
|
|
||||||
|
|
||||||
let base_message: MessageBase = serde_json::from_str(&decompressed_data)?;
|
|
||||||
Ok(base_message)
|
Ok(base_message)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_message_as<T: for<'de> Deserialize<'de>>(
|
pub fn decode_message_as<T: for<'de> Deserialize<'de>>(
|
||||||
data: Vec<u8>,
|
data: String,
|
||||||
) -> Result<T, Box<dyn Error + Send + Sync>> {
|
) -> Result<T, Box<dyn Error + Send + Sync>> {
|
||||||
let mut decoder = GzDecoder::new(data.as_slice());
|
let message: T = serde_json::from_str(&data)?;
|
||||||
let mut decompressed_data = String::new();
|
|
||||||
decoder.read_to_string(&mut decompressed_data)?;
|
|
||||||
|
|
||||||
let message: T = serde_json::from_str(&decompressed_data)?;
|
|
||||||
Ok(message)
|
Ok(message)
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
use crate::messages::{
|
use crate::messages::{
|
||||||
decode_message_as, encode_message, AnswerType, InputMessage, JoinerType, MessageAnswer,
|
decode_message_as, encode_message, AnswerType, JoinerType, MessageAnswer, MessageBase,
|
||||||
MessageBase, MessageICE, MessageInput, MessageJoin, MessageSDP,
|
MessageICE, MessageJoin, MessageSDP,
|
||||||
};
|
};
|
||||||
|
use crate::proto::proto::proto_input::InputType::{
|
||||||
|
KeyDown, KeyUp, MouseKeyDown, MouseKeyUp, MouseMove, MouseMoveAbs, MouseWheel,
|
||||||
|
};
|
||||||
|
use crate::proto::proto::{ProtoInput, ProtoMessageInput};
|
||||||
use crate::websocket::NestriWebSocket;
|
use crate::websocket::NestriWebSocket;
|
||||||
use glib::subclass::prelude::*;
|
use glib::subclass::prelude::*;
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gst_webrtc::{gst_sdp, WebRTCSDPType, WebRTCSessionDescription};
|
use gst_webrtc::{gst_sdp, WebRTCSDPType, WebRTCSessionDescription};
|
||||||
use gstrswebrtc::signaller::{Signallable, SignallableImpl};
|
use gstrswebrtc::signaller::{Signallable, SignallableImpl};
|
||||||
|
use prost::Message;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
use std::sync::{Mutex, RwLock};
|
use std::sync::{Mutex, RwLock};
|
||||||
@@ -200,6 +205,7 @@ impl SignallableImpl for Signaller {
|
|||||||
let join_msg = MessageJoin {
|
let join_msg = MessageJoin {
|
||||||
base: MessageBase {
|
base: MessageBase {
|
||||||
payload_type: "join".to_string(),
|
payload_type: "join".to_string(),
|
||||||
|
latency: None,
|
||||||
},
|
},
|
||||||
joiner_type: JoinerType::JoinerNode,
|
joiner_type: JoinerType::JoinerNode,
|
||||||
};
|
};
|
||||||
@@ -237,6 +243,7 @@ impl SignallableImpl for Signaller {
|
|||||||
let join_msg = MessageJoin {
|
let join_msg = MessageJoin {
|
||||||
base: MessageBase {
|
base: MessageBase {
|
||||||
payload_type: "join".to_string(),
|
payload_type: "join".to_string(),
|
||||||
|
latency: None,
|
||||||
},
|
},
|
||||||
joiner_type: JoinerType::JoinerNode,
|
joiner_type: JoinerType::JoinerNode,
|
||||||
};
|
};
|
||||||
@@ -265,6 +272,7 @@ impl SignallableImpl for Signaller {
|
|||||||
let sdp_message = MessageSDP {
|
let sdp_message = MessageSDP {
|
||||||
base: MessageBase {
|
base: MessageBase {
|
||||||
payload_type: "sdp".to_string(),
|
payload_type: "sdp".to_string(),
|
||||||
|
latency: None,
|
||||||
},
|
},
|
||||||
sdp: RTCSessionDescription::offer(sdp.sdp().as_text().unwrap()).unwrap(),
|
sdp: RTCSessionDescription::offer(sdp.sdp().as_text().unwrap()).unwrap(),
|
||||||
};
|
};
|
||||||
@@ -301,6 +309,7 @@ impl SignallableImpl for Signaller {
|
|||||||
let ice_message = MessageICE {
|
let ice_message = MessageICE {
|
||||||
base: MessageBase {
|
base: MessageBase {
|
||||||
payload_type: "ice".to_string(),
|
payload_type: "ice".to_string(),
|
||||||
|
latency: None,
|
||||||
},
|
},
|
||||||
candidate: candidate_init,
|
candidate: candidate_init,
|
||||||
};
|
};
|
||||||
@@ -354,11 +363,9 @@ fn setup_data_channel(data_channel: &gst_webrtc::WebRTCDataChannel, pipeline: &g
|
|||||||
|
|
||||||
data_channel.connect_on_message_data(move |_data_channel, data| {
|
data_channel.connect_on_message_data(move |_data_channel, data| {
|
||||||
if let Some(data) = data {
|
if let Some(data) = data {
|
||||||
match decode_message_as::<MessageInput>(data.to_vec()) {
|
match ProtoMessageInput::decode(data.to_vec().as_slice()) {
|
||||||
Ok(message_input) => {
|
Ok(message_input) => {
|
||||||
// Deserialize the input message data
|
if let Some(input_msg) = message_input.data {
|
||||||
if let Ok(input_msg) = serde_json::from_str::<InputMessage>(&message_input.data)
|
|
||||||
{
|
|
||||||
// Process the input message and create an event
|
// Process the input message and create an event
|
||||||
if let Some(event) =
|
if let Some(event) =
|
||||||
handle_input_message(input_msg, &pressed_keys, &pressed_buttons)
|
handle_input_message(input_msg, &pressed_keys, &pressed_buttons)
|
||||||
@@ -379,88 +386,92 @@ fn setup_data_channel(data_channel: &gst_webrtc::WebRTCDataChannel, pipeline: &g
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_input_message(
|
fn handle_input_message(
|
||||||
input_msg: InputMessage,
|
input_msg: ProtoInput,
|
||||||
pressed_keys: &Arc<Mutex<HashSet<i32>>>,
|
pressed_keys: &Arc<Mutex<HashSet<i32>>>,
|
||||||
pressed_buttons: &Arc<Mutex<HashSet<i32>>>,
|
pressed_buttons: &Arc<Mutex<HashSet<i32>>>,
|
||||||
) -> Option<gst::Event> {
|
) -> Option<gst::Event> {
|
||||||
match input_msg {
|
if let Some(input_type) = input_msg.input_type {
|
||||||
InputMessage::MouseMove { x, y } => {
|
match input_type {
|
||||||
|
MouseMove(data) => {
|
||||||
let structure = gst::Structure::builder("MouseMoveRelative")
|
let structure = gst::Structure::builder("MouseMoveRelative")
|
||||||
.field("pointer_x", x as f64)
|
.field("pointer_x", data.x as f64)
|
||||||
.field("pointer_y", y as f64)
|
.field("pointer_y", data.y as f64)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::MouseMoveAbs { x, y } => {
|
MouseMoveAbs(data) => {
|
||||||
let structure = gst::Structure::builder("MouseMoveAbsolute")
|
let structure = gst::Structure::builder("MouseMoveAbsolute")
|
||||||
.field("pointer_x", x as f64)
|
.field("pointer_x", data.x as f64)
|
||||||
.field("pointer_y", y as f64)
|
.field("pointer_y", data.y as f64)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::KeyDown { key } => {
|
KeyDown(data) => {
|
||||||
let mut keys = pressed_keys.lock().unwrap();
|
let mut keys = pressed_keys.lock().unwrap();
|
||||||
// If the key is already pressed, return to prevent key lockup
|
// If the key is already pressed, return to prevent key lockup
|
||||||
if keys.contains(&key) {
|
if keys.contains(&data.key) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
keys.insert(key);
|
keys.insert(data.key);
|
||||||
|
|
||||||
let structure = gst::Structure::builder("KeyboardKey")
|
let structure = gst::Structure::builder("KeyboardKey")
|
||||||
.field("key", key as u32)
|
.field("key", data.key as u32)
|
||||||
.field("pressed", true)
|
.field("pressed", true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::KeyUp { key } => {
|
KeyUp(data) => {
|
||||||
let mut keys = pressed_keys.lock().unwrap();
|
let mut keys = pressed_keys.lock().unwrap();
|
||||||
// Remove the key from the pressed state when released
|
// Remove the key from the pressed state when released
|
||||||
keys.remove(&key);
|
keys.remove(&data.key);
|
||||||
|
|
||||||
let structure = gst::Structure::builder("KeyboardKey")
|
let structure = gst::Structure::builder("KeyboardKey")
|
||||||
.field("key", key as u32)
|
.field("key", data.key as u32)
|
||||||
.field("pressed", false)
|
.field("pressed", false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::Wheel { x, y } => {
|
MouseWheel(data) => {
|
||||||
let structure = gst::Structure::builder("MouseAxis")
|
let structure = gst::Structure::builder("MouseAxis")
|
||||||
.field("x", x as f64)
|
.field("x", data.x as f64)
|
||||||
.field("y", y as f64)
|
.field("y", data.y as f64)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::MouseDown { key } => {
|
MouseKeyDown(data) => {
|
||||||
let mut buttons = pressed_buttons.lock().unwrap();
|
let mut buttons = pressed_buttons.lock().unwrap();
|
||||||
// If the button is already pressed, return to prevent button lockup
|
// If the button is already pressed, return to prevent button lockup
|
||||||
if buttons.contains(&key) {
|
if buttons.contains(&data.key) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
buttons.insert(key);
|
buttons.insert(data.key);
|
||||||
|
|
||||||
let structure = gst::Structure::builder("MouseButton")
|
let structure = gst::Structure::builder("MouseButton")
|
||||||
.field("button", key as u32)
|
.field("button", data.key as u32)
|
||||||
.field("pressed", true)
|
.field("pressed", true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
InputMessage::MouseUp { key } => {
|
MouseKeyUp(data) => {
|
||||||
let mut buttons = pressed_buttons.lock().unwrap();
|
let mut buttons = pressed_buttons.lock().unwrap();
|
||||||
// Remove the button from the pressed state when released
|
// Remove the button from the pressed state when released
|
||||||
buttons.remove(&key);
|
buttons.remove(&data.key);
|
||||||
|
|
||||||
let structure = gst::Structure::builder("MouseButton")
|
let structure = gst::Structure::builder("MouseButton")
|
||||||
.field("button", key as u32)
|
.field("button", data.key as u32)
|
||||||
.field("pressed", false)
|
.field("pressed", false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Some(gst::event::CustomUpstream::new(structure))
|
Some(gst::event::CustomUpstream::new(structure))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/server/src/proto.rs
Normal file
1
packages/server/src/proto.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod proto;
|
||||||
139
packages/server/src/proto/proto.rs
Normal file
139
packages/server/src/proto/proto.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// @generated
|
||||||
|
// This file is @generated by prost-build.
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoTimestampEntry {
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub stage: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag="2")]
|
||||||
|
pub time: ::core::option::Option<::prost_types::Timestamp>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoLatencyTracker {
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub sequence_id: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, repeated, tag="2")]
|
||||||
|
pub timestamps: ::prost::alloc::vec::Vec<ProtoTimestampEntry>,
|
||||||
|
}
|
||||||
|
/// MouseMove message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMouseMove {
|
||||||
|
/// Fixed value "MouseMove"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub x: i32,
|
||||||
|
#[prost(int32, tag="3")]
|
||||||
|
pub y: i32,
|
||||||
|
}
|
||||||
|
/// MouseMoveAbs message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMouseMoveAbs {
|
||||||
|
/// Fixed value "MouseMoveAbs"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub x: i32,
|
||||||
|
#[prost(int32, tag="3")]
|
||||||
|
pub y: i32,
|
||||||
|
}
|
||||||
|
/// MouseWheel message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMouseWheel {
|
||||||
|
/// Fixed value "MouseWheel"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub x: i32,
|
||||||
|
#[prost(int32, tag="3")]
|
||||||
|
pub y: i32,
|
||||||
|
}
|
||||||
|
/// MouseKeyDown message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMouseKeyDown {
|
||||||
|
/// Fixed value "MouseKeyDown"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub key: i32,
|
||||||
|
}
|
||||||
|
/// MouseKeyUp message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMouseKeyUp {
|
||||||
|
/// Fixed value "MouseKeyUp"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub key: i32,
|
||||||
|
}
|
||||||
|
/// KeyDown message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoKeyDown {
|
||||||
|
/// Fixed value "KeyDown"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub key: i32,
|
||||||
|
}
|
||||||
|
/// KeyUp message
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoKeyUp {
|
||||||
|
/// Fixed value "KeyUp"
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub r#type: ::prost::alloc::string::String,
|
||||||
|
#[prost(int32, tag="2")]
|
||||||
|
pub key: i32,
|
||||||
|
}
|
||||||
|
/// Union of all Input types
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoInput {
|
||||||
|
#[prost(oneof="proto_input::InputType", tags="1, 2, 3, 4, 5, 6, 7")]
|
||||||
|
pub input_type: ::core::option::Option<proto_input::InputType>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `ProtoInput`.
|
||||||
|
pub mod proto_input {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
|
pub enum InputType {
|
||||||
|
#[prost(message, tag="1")]
|
||||||
|
MouseMove(super::ProtoMouseMove),
|
||||||
|
#[prost(message, tag="2")]
|
||||||
|
MouseMoveAbs(super::ProtoMouseMoveAbs),
|
||||||
|
#[prost(message, tag="3")]
|
||||||
|
MouseWheel(super::ProtoMouseWheel),
|
||||||
|
#[prost(message, tag="4")]
|
||||||
|
MouseKeyDown(super::ProtoMouseKeyDown),
|
||||||
|
#[prost(message, tag="5")]
|
||||||
|
MouseKeyUp(super::ProtoMouseKeyUp),
|
||||||
|
#[prost(message, tag="6")]
|
||||||
|
KeyDown(super::ProtoKeyDown),
|
||||||
|
#[prost(message, tag="7")]
|
||||||
|
KeyUp(super::ProtoKeyUp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMessageBase {
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub payload_type: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag="2")]
|
||||||
|
pub latency: ::core::option::Option<ProtoLatencyTracker>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ProtoMessageInput {
|
||||||
|
#[prost(message, optional, tag="1")]
|
||||||
|
pub message_base: ::core::option::Option<ProtoMessageBase>,
|
||||||
|
#[prost(message, optional, tag="2")]
|
||||||
|
pub data: ::core::option::Option<ProtoInput>,
|
||||||
|
}
|
||||||
|
// @@protoc_insertion_point(module)
|
||||||
@@ -10,10 +10,10 @@ use std::time::Duration;
|
|||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::sync::{mpsc, Mutex, Notify};
|
use tokio::sync::{mpsc, Mutex, Notify};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use tokio_tungstenite::tungstenite::Message;
|
use tokio_tungstenite::tungstenite::{Message, Utf8Bytes};
|
||||||
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||||
|
|
||||||
type Callback = Box<dyn Fn(Vec<u8>) + Send + Sync>;
|
type Callback = Box<dyn Fn(String) + Send + Sync>;
|
||||||
type WSRead = SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>;
|
type WSRead = SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>;
|
||||||
type WSWrite = SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>;
|
type WSWrite = SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>;
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ pub struct NestriWebSocket {
|
|||||||
reader: Arc<Mutex<Option<WSRead>>>,
|
reader: Arc<Mutex<Option<WSRead>>>,
|
||||||
writer: Arc<Mutex<Option<WSWrite>>>,
|
writer: Arc<Mutex<Option<WSWrite>>>,
|
||||||
callbacks: Arc<RwLock<HashMap<String, Callback>>>,
|
callbacks: Arc<RwLock<HashMap<String, Callback>>>,
|
||||||
message_tx: mpsc::UnboundedSender<Vec<u8>>,
|
message_tx: mpsc::UnboundedSender<String>,
|
||||||
reconnected_notify: Arc<Notify>,
|
reconnected_notify: Arc<Notify>,
|
||||||
}
|
}
|
||||||
impl NestriWebSocket {
|
impl NestriWebSocket {
|
||||||
@@ -95,8 +95,8 @@ impl NestriWebSocket {
|
|||||||
while let Some(message_result) = ws_read.next().await {
|
while let Some(message_result) = ws_read.next().await {
|
||||||
match message_result {
|
match message_result {
|
||||||
Ok(message) => {
|
Ok(message) => {
|
||||||
let data = message.into_data();
|
let data = message.into_text().expect("failed to turn message into text");
|
||||||
let base_message = match decode_message(&data) {
|
let base_message = match decode_message(data.to_string()) {
|
||||||
Ok(base_message) => base_message,
|
Ok(base_message) => base_message,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to decode message: {:?}", e);
|
eprintln!("Failed to decode message: {:?}", e);
|
||||||
@@ -107,11 +107,14 @@ impl NestriWebSocket {
|
|||||||
let callbacks_lock = callbacks.read().unwrap();
|
let callbacks_lock = callbacks.read().unwrap();
|
||||||
if let Some(callback) = callbacks_lock.get(&base_message.payload_type) {
|
if let Some(callback) = callbacks_lock.get(&base_message.payload_type) {
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
callback(data);
|
callback(data.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error receiving message: {:?}, reconnecting in 3 seconds...", e);
|
eprintln!(
|
||||||
|
"Error receiving message: {:?}, reconnecting in 3 seconds...",
|
||||||
|
e
|
||||||
|
);
|
||||||
sleep(Duration::from_secs(3)).await;
|
sleep(Duration::from_secs(3)).await;
|
||||||
self_clone.reconnect().await.unwrap();
|
self_clone.reconnect().await.unwrap();
|
||||||
break; // Break the inner loop to get a new ws_read
|
break; // Break the inner loop to get a new ws_read
|
||||||
@@ -123,7 +126,7 @@ impl NestriWebSocket {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_write_loop(&self, mut message_rx: mpsc::UnboundedReceiver<Vec<u8>>) {
|
fn spawn_write_loop(&self, mut message_rx: mpsc::UnboundedReceiver<String>) {
|
||||||
let writer = self.writer.clone();
|
let writer = self.writer.clone();
|
||||||
let self_clone = self.clone();
|
let self_clone = self.clone();
|
||||||
|
|
||||||
@@ -136,7 +139,10 @@ impl NestriWebSocket {
|
|||||||
let mut writer_lock = writer.lock().await;
|
let mut writer_lock = writer.lock().await;
|
||||||
if let Some(writer) = writer_lock.as_mut() {
|
if let Some(writer) = writer_lock.as_mut() {
|
||||||
// Try to send the message over the WebSocket
|
// Try to send the message over the WebSocket
|
||||||
match writer.send(Message::Binary(message.clone())).await {
|
match writer
|
||||||
|
.send(Message::Text(Utf8Bytes::from(message.clone())))
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Message sent successfully
|
// Message sent successfully
|
||||||
break;
|
break;
|
||||||
@@ -196,7 +202,7 @@ impl NestriWebSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message through the WebSocket
|
/// Send a message through the WebSocket
|
||||||
pub fn send_message(&self, message: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
pub fn send_message(&self, message: String) -> Result<(), Box<dyn Error>> {
|
||||||
self.message_tx
|
self.message_tx
|
||||||
.send(message)
|
.send(message)
|
||||||
.map_err(|e| format!("Failed to send message: {:?}", e).into())
|
.map_err(|e| format!("Failed to send message: {:?}", e).into())
|
||||||
@@ -205,7 +211,7 @@ impl NestriWebSocket {
|
|||||||
/// Register a callback for a specific response type
|
/// Register a callback for a specific response type
|
||||||
pub fn register_callback<F>(&self, response_type: &str, callback: F)
|
pub fn register_callback<F>(&self, response_type: &str, callback: F)
|
||||||
where
|
where
|
||||||
F: Fn(Vec<u8>) + Send + Sync + 'static,
|
F: Fn(String) + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let mut callbacks_lock = self.callbacks.write().unwrap();
|
let mut callbacks_lock = self.callbacks.write().unwrap();
|
||||||
callbacks_lock.insert(response_type.to_string(), Box::new(callback));
|
callbacks_lock.insert(response_type.to_string(), Box::new(callback));
|
||||||
@@ -234,6 +240,7 @@ impl Log for NestriWebSocket {
|
|||||||
let log_message = MessageLog {
|
let log_message = MessageLog {
|
||||||
base: MessageBase {
|
base: MessageBase {
|
||||||
payload_type: "log".to_string(),
|
payload_type: "log".to_string(),
|
||||||
|
latency: None,
|
||||||
},
|
},
|
||||||
level,
|
level,
|
||||||
message,
|
message,
|
||||||
|
|||||||
7
protobufs/buf.yaml
Normal file
7
protobufs/buf.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
version: v2
|
||||||
|
breaking:
|
||||||
|
use:
|
||||||
|
- FILE
|
||||||
|
lint:
|
||||||
|
use:
|
||||||
|
- STANDARD
|
||||||
17
protobufs/latency_tracker.proto
Normal file
17
protobufs/latency_tracker.proto
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
option go_package = "relay/internal/proto";
|
||||||
|
|
||||||
|
package proto;
|
||||||
|
|
||||||
|
message ProtoTimestampEntry {
|
||||||
|
string stage = 1;
|
||||||
|
google.protobuf.Timestamp time = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message ProtoLatencyTracker {
|
||||||
|
string sequence_id = 1;
|
||||||
|
repeated ProtoTimestampEntry timestamps = 2;
|
||||||
|
}
|
||||||
18
protobufs/messages.proto
Normal file
18
protobufs/messages.proto
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "relay/internal/proto";
|
||||||
|
|
||||||
|
import "types.proto";
|
||||||
|
import "latency_tracker.proto";
|
||||||
|
|
||||||
|
package proto;
|
||||||
|
|
||||||
|
message ProtoMessageBase {
|
||||||
|
string payload_type = 1;
|
||||||
|
ProtoLatencyTracker latency = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ProtoMessageInput {
|
||||||
|
ProtoMessageBase message_base = 1;
|
||||||
|
ProtoInput data = 2;
|
||||||
|
}
|
||||||
63
protobufs/types.proto
Normal file
63
protobufs/types.proto
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "relay/internal/proto";
|
||||||
|
|
||||||
|
package proto;
|
||||||
|
|
||||||
|
// MouseMove message
|
||||||
|
message ProtoMouseMove {
|
||||||
|
string type = 1; // Fixed value "MouseMove"
|
||||||
|
int32 x = 2;
|
||||||
|
int32 y = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseMoveAbs message
|
||||||
|
message ProtoMouseMoveAbs {
|
||||||
|
string type = 1; // Fixed value "MouseMoveAbs"
|
||||||
|
int32 x = 2;
|
||||||
|
int32 y = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseWheel message
|
||||||
|
message ProtoMouseWheel {
|
||||||
|
string type = 1; // Fixed value "MouseWheel"
|
||||||
|
int32 x = 2;
|
||||||
|
int32 y = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseKeyDown message
|
||||||
|
message ProtoMouseKeyDown {
|
||||||
|
string type = 1; // Fixed value "MouseKeyDown"
|
||||||
|
int32 key = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseKeyUp message
|
||||||
|
message ProtoMouseKeyUp {
|
||||||
|
string type = 1; // Fixed value "MouseKeyUp"
|
||||||
|
int32 key = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDown message
|
||||||
|
message ProtoKeyDown {
|
||||||
|
string type = 1; // Fixed value "KeyDown"
|
||||||
|
int32 key = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyUp message
|
||||||
|
message ProtoKeyUp {
|
||||||
|
string type = 1; // Fixed value "KeyUp"
|
||||||
|
int32 key = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union of all Input types
|
||||||
|
message ProtoInput {
|
||||||
|
oneof input_type {
|
||||||
|
ProtoMouseMove mouse_move = 1;
|
||||||
|
ProtoMouseMoveAbs mouse_move_abs = 2;
|
||||||
|
ProtoMouseWheel mouse_wheel = 3;
|
||||||
|
ProtoMouseKeyDown mouse_key_down = 4;
|
||||||
|
ProtoMouseKeyUp mouse_key_up = 5;
|
||||||
|
ProtoKeyDown key_down = 6;
|
||||||
|
ProtoKeyUp key_up = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user