projects/shelled/rustdesk-web-client/js/proto.js
Z User 7b758ebe01 Add standalone RustDesk web client (reverse-engineered)
Complete browser-based remote desktop client built from protocol analysis:
- Protobuf message definitions (75+ message types, 10 enums)
- NaCl encryption (Ed25519 + Curve25519 ECDH + XSalsa20-Poly1305)
- WebSocket signaling (hbbs) + relay (hbbr) connection lifecycle
- VP8/VP9/AV1 video decoding via ogvjs WASM + yuv-canvas WebGL
- Opus audio decoding via libopus WASM + Web Audio API
- Full mouse/keyboard input forwarding to protobuf events
- Connection dialog, status bar, toolbar, log panel UI

Also tracked web_deps (codec libraries) in rustdesk-as-ref/
2026-04-06 21:11:21 +00:00

1210 lines
28 KiB
JavaScript

/**
* RustDesk Standalone Web Client - Protobuf Message Definitions
*
* This module defines all protobuf messages used in the RustDesk protocol
* using protobuf.js programmatic definitions (parsed from .proto text format).
*/
const RDProto = (() => {
// Embedded proto definition - complete RustDesk protocol
const PROTO_TEXT = `
syntax = "proto3";
package hbb;
// ===== Enums =====
enum NatType {
UNKNOWN_NAT = 0;
ASYMMETRIC = 1;
SYMMETRIC = 2;
}
enum ConnType {
DEFAULT_CONN = 0;
FILE_TRANSFER = 1;
PORT_FORWARD = 2;
RDP = 3;
VIEW_CAMERA = 4;
TERMINAL = 5;
}
enum ImageQuality {
NotSet = 0;
Low = 2;
Balanced = 3;
Best = 4;
}
enum BoolOption {
NotSet = 0;
Yes = 1;
No = 2;
}
enum PreferCodec {
Auto = 0;
VP9 = 1;
H264 = 2;
H265 = 3;
VP8 = 4;
AV1 = 5;
}
enum Chroma {
I420 = 0;
I444 = 1;
}
enum KeyboardMode {
Legacy = 0;
Map = 1;
Translate = 2;
Auto = 3;
}
enum ControlKey {
Unknown = 0;
Alt = 1;
Backspace = 2;
CapsLock = 3;
Control = 4;
Delete = 5;
DownArrow = 6;
End = 7;
Escape = 8;
F1 = 9;
F10 = 10;
F11 = 11;
F12 = 12;
F2 = 13;
F3 = 14;
F4 = 15;
F5 = 16;
F6 = 17;
F7 = 18;
F8 = 19;
F9 = 20;
Home = 21;
LeftArrow = 22;
Meta = 23;
PageDown = 24;
PageUp = 25;
Return = 26;
RightArrow = 27;
Shift = 28;
Space = 29;
Tab = 30;
UpArrow = 31;
Numpad0 = 32;
Numpad1 = 33;
Numpad2 = 34;
Numpad3 = 35;
Numpad4 = 36;
Numpad5 = 37;
Numpad6 = 38;
Numpad7 = 39;
Numpad8 = 40;
Numpad9 = 41;
NumpadAdd = 42;
NumpadDecimal = 43;
NumpadDelete = 44;
NumpadDivide = 45;
NumpadEnter = 46;
NumpadMultiply = 47;
NumpadSubtract = 48;
Insert = 49;
LeftControl = 50;
LeftShift = 51;
LeftAlt = 52;
LeftMeta = 53;
RightControl = 54;
RightShift = 55;
RightAlt = 56;
RightMeta = 57;
VolumeDown = 58;
VolumeMute = 59;
VolumeUp = 60;
Win = 61;
WakeUp = 62;
NumLock = 63;
ScrollLock = 64;
Print = 65;
PrintScreen = 66;
CtrlAltDel = 100;
LockScreen = 101;
}
// ===== Rendezvous Protocol =====
message RendezvousMessage {
oneof union {
RegisterPeer register_peer = 6;
RegisterPeerResponse register_peer_response = 7;
PunchHoleRequest punch_hole_request = 8;
PunchHole punch_hole = 9;
PunchHoleSent punch_hole_sent = 10;
PunchHoleResponse punch_hole_response = 11;
FetchLocalAddr fetch_local_addr = 12;
LocalAddr local_addr = 13;
ConfigUpdate configure_update = 14;
RegisterPk register_pk = 15;
RegisterPkResponse register_pk_response = 16;
SoftwareUpdate software_update = 17;
RequestRelay request_relay = 18;
RelayResponse relay_response = 19;
TestNatRequest test_nat_request = 20;
TestNatResponse test_nat_response = 21;
PeerDiscovery peer_discovery = 22;
OnlineRequest online_request = 23;
OnlineResponse online_response = 24;
KeyExchange key_exchange = 25;
HealthCheck hc = 26;
HttpProxyRequest http_proxy_request = 27;
HttpProxyResponse http_proxy_response = 28;
}
}
message RegisterPeer {
string id = 1;
uint32 serial = 2;
}
message RegisterPeerResponse {
bool request_pk = 1;
}
message RegisterPk {
string id = 1;
string uuid = 2;
bytes pk = 3;
string old_id = 4;
bool no_register_device = 5;
}
message RegisterPkResponse {
enum Result {
OK = 0;
UUID_MISMATCH = 2;
ID_EXISTS = 3;
TOO_FREQUENT = 4;
INVALID_ID_FORMAT = 5;
NOT_SUPPORT = 6;
SERVER_ERROR = 7;
}
Result result = 1;
}
message PunchHoleRequest {
string id = 1;
NatType nat_type = 2;
string licence_key = 3;
ConnType conn_type = 4;
string token = 5;
string version = 6;
uint32 udp_port = 7;
bool force_relay = 8;
string socket_addr_v6 = 9;
}
message PunchHole {
string socket_addr = 1;
string relay_server = 2;
NatType nat_type = 3;
uint32 udp_port = 4;
bool force_relay = 5;
string socket_addr_v6 = 6;
}
message PunchHoleSent {
string socket_addr = 1;
string id = 2;
string relay_server = 3;
NatType nat_type = 4;
string version = 5;
uint32 udp_port = 6;
string socket_addr_v6 = 7;
}
message PunchHoleResponse {
string socket_addr = 1;
bytes pk = 2;
enum Failure {
ID_NOT_EXIST = 0;
OFFLINE = 2;
LICENSE_MISMATCH = 3;
LICENSE_OVERUSE = 4;
}
Failure failure = 3;
string relay_server = 4;
oneof union {
NatType nat_type = 5;
bool is_local = 6;
}
string other_failure = 7;
string feedback = 8;
bool is_udp = 9;
uint32 udp_port = 10;
string socket_addr_v6 = 11;
}
message RequestRelay {
string id = 1;
string uuid = 2;
string socket_addr = 3;
string relay_server = 4;
bool secure = 5;
string licence_key = 6;
ConnType conn_type = 7;
string token = 8;
}
message RelayResponse {
string socket_addr = 1;
string uuid = 2;
string relay_server = 3;
oneof union {
string id = 4;
bytes pk = 5;
}
string refuse_reason = 6;
string version = 7;
string feedback = 8;
string socket_addr_v6 = 9;
uint32 udp_port = 10;
}
message OnlineRequest {
string id = 1;
repeated string peers = 2;
}
message OnlineResponse {
bytes states = 1;
}
message KeyExchange {
repeated bytes keys = 1;
}
message FetchLocalAddr {
string socket_addr = 1;
string relay_server = 2;
string socket_addr_v6 = 3;
}
message LocalAddr {
string socket_addr = 1;
string local_addr = 2;
string relay_server = 3;
string id = 4;
string version = 5;
string socket_addr_v6 = 6;
}
message ConfigUpdate {
uint32 serial = 1;
repeated string rendezvous_servers = 2;
}
message SoftwareUpdate {
string url = 1;
}
message TestNatRequest {
uint32 serial = 1;
}
message TestNatResponse {
uint32 port = 1;
ConfigUpdate cu = 2;
}
message PeerDiscovery {
string cmd = 1;
string mac = 2;
string id = 3;
string username = 4;
string hostname = 5;
string platform = 6;
string misc = 7;
}
message HealthCheck {
string token = 1;
}
message HttpProxyRequest {
string method = 1;
string path = 2;
repeated HeaderEntry headers = 3;
bytes body = 4;
}
message HttpProxyResponse {
int32 status = 1;
repeated HeaderEntry headers = 2;
bytes body = 3;
string error = 4;
}
message HeaderEntry {
string name = 1;
string value = 2;
}
// ===== Session Protocol =====
message Message {
oneof union {
SignedId signed_id = 3;
PublicKey public_key = 4;
TestDelay test_delay = 5;
VideoFrame video_frame = 6;
LoginRequest login_request = 7;
LoginResponse login_response = 8;
Hash hash = 9;
MouseEvent mouse_event = 10;
AudioFrame audio_frame = 11;
CursorData cursor_data = 12;
CursorPosition cursor_position = 13;
uint64 cursor_id = 14;
KeyEvent key_event = 15;
Clipboard clipboard = 16;
FileAction file_action = 17;
FileResponse file_response = 18;
Misc misc = 19;
Cliprdr cliprdr = 20;
MessageBox message_box = 21;
SwitchSidesResponse switch_sides_response = 22;
VoiceCallRequest voice_call_request = 23;
VoiceCallResponse voice_call_response = 24;
PeerInfo peer_info = 25;
PointerDeviceEvent pointer_device_event = 26;
Auth2FA auth_2fa = 27;
MultiClipboards multi_clipboards = 28;
ScreenshotRequest screenshot_request = 29;
ScreenshotResponse screenshot_response = 30;
TerminalAction terminal_action = 31;
TerminalResponse terminal_response = 32;
}
}
message SignedId {
bytes id = 1;
}
message IdPk {
string id = 1;
bytes pk = 2;
}
message PublicKey {
bytes asymmetric_value = 1;
bytes symmetric_value = 2;
}
message Hash {
string salt = 1;
string challenge = 2;
}
message LoginRequest {
string username = 1;
bytes password = 2;
string my_id = 4;
string my_name = 5;
OptionMessage option = 6;
oneof union {
FileTransfer file_transfer = 7;
PortForward port_forward = 8;
ViewCamera view_camera = 15;
Terminal terminal = 16;
}
bool video_ack_required = 9;
uint64 session_id = 10;
string version = 11;
OSLogin os_login = 12;
string my_platform = 13;
bytes hwid = 14;
string avatar = 17;
}
message LoginResponse {
oneof union {
string error = 1;
PeerInfo peer_info = 2;
}
bool enable_trusted_devices = 3;
}
message PeerInfo {
string username = 1;
string hostname = 2;
string platform = 3;
repeated DisplayInfo displays = 4;
int32 current_display = 5;
bool sas_enabled = 6;
string version = 7;
Features features = 8;
SupportedEncoding encoding = 9;
SupportedResolutions resolutions = 10;
string platform_additions = 11;
WindowsSessions windows_sessions = 12;
}
message DisplayInfo {
sint32 x = 1;
sint32 y = 2;
int32 width = 3;
int32 height = 4;
string name = 5;
bool online = 6;
bool cursor_embedded = 7;
Resolution original_resolution = 8;
double scale = 9;
}
message Resolution {
int32 width = 1;
int32 height = 2;
}
message Features {
bool privacy_mode = 1;
bool terminal = 2;
}
message SupportedEncoding {
bool h264 = 1;
bool h265 = 2;
bool vp8 = 3;
bool av1 = 4;
CodecAbility i444 = 5;
}
message CodecAbility {
bool vp8 = 1;
bool vp9 = 2;
bool av1 = 3;
bool h264 = 4;
bool h265 = 5;
}
message SupportedResolutions {
repeated Resolution resolutions = 1;
}
message WindowsSessions {
repeated WindowsSession sessions = 1;
uint32 current_sid = 2;
}
message WindowsSession {
uint32 sid = 1;
string name = 2;
}
message OptionMessage {
ImageQuality image_quality = 1;
BoolOption lock_after_session_end = 2;
BoolOption show_remote_cursor = 3;
BoolOption privacy_mode = 4;
int32 custom_image_quality = 5;
BoolOption disable_audio = 6;
BoolOption enable_file_transfer = 7;
BoolOption clipboard = 8;
SupportedDecoding supported_decoding = 9;
int32 custom_fps = 10;
BoolOption follow_remote_cursor = 11;
BoolOption follow_remote_window = 12;
BoolOption disable_camera = 13;
BoolOption block_input = 14;
BoolOption keyboard = 15;
BoolOption terminal_persistent = 16;
BoolOption show_my_cursor = 17;
}
message SupportedDecoding {
bool ability_vp9 = 1;
bool ability_h264 = 2;
bool ability_h265 = 3;
bool ability_vp8 = 4;
bool ability_av1 = 5;
PreferCodec prefer = 6;
CodecAbility i444 = 7;
Chroma prefer_chroma = 8;
}
message FileTransfer {
string dir = 1;
bool show_hidden = 2;
}
message PortForward {
string host = 1;
int32 port = 2;
}
message ViewCamera {}
message Terminal {
string service_id = 1;
}
message OSLogin {
string username = 1;
string password = 2;
}
// ===== Video =====
message VideoFrame {
oneof union {
EncodedVideoFrames vp9s = 6;
RGB rgb = 7;
YUV yuv = 8;
EncodedVideoFrames h264s = 10;
EncodedVideoFrames h265s = 11;
EncodedVideoFrames vp8s = 12;
EncodedVideoFrames av1s = 13;
}
int32 display = 14;
}
message EncodedVideoFrames {
repeated EncodedVideoFrame frames = 1;
}
message EncodedVideoFrame {
bytes data = 1;
bool key = 2;
int64 pts = 3;
}
message RGB {
bool compress = 1;
}
message YUV {
bool compress = 1;
int32 stride = 2;
}
// ===== Audio =====
message AudioFrame {
bytes data = 1;
}
// ===== Input =====
message MouseEvent {
int32 mask = 1;
sint32 x = 2;
sint32 y = 3;
repeated ControlKey modifiers = 4;
}
message KeyEvent {
bool down = 1;
bool press = 2;
oneof union {
ControlKey control_key = 3;
uint32 chr = 4;
uint32 unicode = 5;
string seq = 6;
uint32 win2win_hotkey = 7;
}
repeated ControlKey modifiers = 8;
KeyboardMode mode = 9;
}
// ===== Cursor =====
message CursorData {
uint64 id = 1;
sint32 hotx = 2;
sint32 hoty = 3;
int32 width = 4;
int32 height = 5;
bytes colors = 6;
}
message CursorPosition {
sint32 x = 1;
sint32 y = 2;
}
// ===== Misc =====
message Misc {
oneof union {
ChatMessage chat_message = 1;
SwitchDisplay switch_display = 2;
PermissionInfo permission_info = 3;
Option option = 4;
AudioFormat audio_format = 5;
string close_reason = 6;
bool refresh_video = 7;
bool video_received = 8;
BackNotification back_notification = 9;
bool restart_remote_device = 10;
bool uac = 11;
bool foreground_window_elevated = 12;
bool stop_service = 13;
ElevationRequest elevation_request = 14;
bool elevation_response = 15;
bool portable_service_running = 16;
SwitchSidesRequest switch_sides_request = 17;
SwitchBack switch_back = 18;
ChangeResolution change_resolution = 19;
PluginRequest plugin_request = 20;
PluginFailure plugin_failure = 21;
bool full_speed_fps = 22;
bool auto_adjust_fps = 23;
bool client_record_status = 24;
CaptureDisplays capture_displays = 25;
int32 refresh_video_display = 26;
ToggleVirtualDisplay toggle_virtual_display = 27;
TogglePrivacyMode toggle_privacy_mode = 28;
SupportedEncoding supported_encoding = 29;
string selected_sid = 30;
DisplayResolution change_display_resolution = 31;
MessageQuery message_query = 32;
bool follow_current_display = 33;
}
}
message ChatMessage { string text = 1; }
message SwitchDisplay {
int32 display = 1;
sint32 x = 2;
sint32 y = 3;
int32 width = 4;
int32 height = 5;
bool cursor_embedded = 6;
SupportedResolutions resolutions = 7;
Resolution original_resolution = 8;
}
message PermissionInfo {
enum Permission {
Keyboard = 0;
Clipboard = 2;
Audio = 3;
File = 4;
Restart = 5;
Recording = 6;
BlockInput = 7;
}
Permission permission = 1;
bool enabled = 2;
}
message Option { string name = 1; string value = 2; }
message AudioFormat {
uint32 sample_rate = 1;
uint32 channels = 2;
}
message BackNotification {
oneof union {
PrivacyModeState privacy_mode_state = 1;
BlockInputState block_input_state = 2;
}
string details = 3;
string impl_key = 4;
enum PrivacyModeState { OFF = 0; ON = 1; BLANK_SCREEN = 2; }
enum BlockInputState { RUNNING = 0; ON = 1; OFF = 2; }
}
message ElevationRequest {
oneof union { bool direct = 1; ElevationRequestWithLogon logon = 2; }
}
message ElevationRequestWithLogon { string username = 1; string password = 2; }
message SwitchSidesRequest { bytes uuid = 1; }
message SwitchBack {}
message ChangeResolution { Resolution resolution = 1; }
message PluginRequest { string id = 1; bytes content = 2; }
message PluginFailure { string id = 1; string name = 2; string msg = 3; }
message CaptureDisplays {
repeated int32 set = 1;
repeated int32 add = 2;
repeated int32 sub = 3;
}
message ToggleVirtualDisplay { int32 display = 1; bool on = 2; }
message TogglePrivacyMode { string impl_key = 1; bool on = 2; }
message DisplayResolution { int32 display = 1; Resolution resolution = 2; }
message MessageQuery { int32 switch_display = 1; }
// ===== Clipboard =====
message Clipboard {
enum ClipboardFormat {
Text = 0;
Rtf = 1;
Html = 2;
ImageRgba = 21;
ImagePng = 22;
ImageSvg = 23;
Special = 31;
}
bool compress = 1;
repeated ClipboardContent contents = 2;
}
message ClipboardContent {
Clipboard.ClipboardFormat format = 1;
bytes data = 2;
}
// ===== File Transfer =====
message FileAction {
oneof union {
ReadDir read_dir = 1;
FileTransferSendRequest send = 2;
FileTransferReceiveRequest receive = 3;
FileDirCreate create = 4;
FileRemoveDir remove_dir = 5;
FileRemoveFile remove_file = 6;
ReadAllFiles all_files = 7;
FileTransferCancel cancel = 8;
FileTransferSendConfirmRequest send_confirm = 9;
FileRename rename = 10;
ReadEmptyDirs read_empty_dirs = 11;
}
}
message ReadDir { string path = 1; bool include_hidden = 2; }
message ReadAllFiles { string id = 1; string path = 2; bool include_hidden = 3; }
message ReadEmptyDirs { string id = 1; string path = 2; bool include_hidden = 3; }
message FileDirCreate { string id = 1; string path = 2; }
message FileRemoveDir { string id = 1; string path = 2; bool recursive = 3; }
message FileRemoveFile { string id = 1; string path = 2; sint32 file_num = 3; }
message FileRename { string id = 1; string path = 2; string new_name = 3; }
message FileTransferSendRequest {
string id = 1;
string path = 2;
bool include_hidden = 3;
sint32 file_num = 4;
enum FileType { Generic = 0; Printer = 1; }
FileType file_type = 5;
}
message FileTransferReceiveRequest {
string id = 1;
string path = 2;
repeated FileEntry files = 3;
sint32 file_num = 4;
uint64 total_size = 5;
}
message FileTransferSendConfirmRequest {
string id = 1;
sint32 file_num = 2;
oneof union {
bool skip = 3;
uint32 offset_blk = 4;
}
}
message FileTransferCancel { string id = 1; }
message FileResponse {
oneof union {
FileDirectory dir = 1;
FileTransferBlock block = 2;
FileTransferError error = 3;
FileTransferDone done = 4;
FileTransferDigest digest = 5;
ReadEmptyDirsResponse empty_dirs = 6;
}
}
message FileDirectory {
string id = 1;
string path = 2;
repeated FileEntry entries = 3;
}
message FileEntry {
enum FileType {
Dir = 0;
DirLink = 2;
DirDrive = 3;
File = 4;
FileLink = 5;
}
FileType entry_type = 1;
string name = 2;
bool is_hidden = 3;
uint64 size = 4;
uint64 modified_time = 5;
}
message FileTransferBlock {
string id = 1;
sint32 file_num = 2;
bytes data = 3;
bool compressed = 4;
uint32 blk_id = 5;
}
message FileTransferError { string id = 1; string error = 2; sint32 file_num = 3; }
message FileTransferDone { string id = 1; sint32 file_num = 2; }
message FileTransferDigest {
string id = 1;
sint32 file_num = 2;
uint64 last_modified = 3;
uint64 file_size = 4;
bool is_upload = 5;
bool is_identical = 6;
uint64 transferred_size = 7;
bool is_resume = 8;
}
message ReadEmptyDirsResponse {
string path = 1;
repeated FileDirectory empty_dirs = 2;
}
// ===== Test Delay =====
message TestDelay {
int64 time = 1;
bool from_client = 2;
int32 last_delay = 3;
int32 target_bitrate = 4;
}
// ===== Auth =====
message Auth2FA { string code = 1; bytes hwid = 2; }
// ===== Terminal =====
message TerminalAction {
oneof union {
OpenTerminal open = 1;
TerminalData data = 2;
ResizeTerminal resize = 3;
CloseTerminal close = 4;
}
}
message TerminalResponse {
oneof union {
TerminalOpened opened = 1;
TerminalData data = 2;
TerminalClosed closed = 3;
TerminalError error = 4;
}
}
message OpenTerminal { int32 terminal_id = 1; uint32 rows = 2; uint32 cols = 3; }
message TerminalData { int32 terminal_id = 1; bytes data = 2; bool compressed = 3; }
message ResizeTerminal { int32 terminal_id = 1; uint32 rows = 2; uint32 cols = 3; }
message CloseTerminal { int32 terminal_id = 1; }
message TerminalOpened { int32 terminal_id = 1; bool success = 2; string message = 3; }
message TerminalClosed { int32 terminal_id = 1; int32 exit_code = 2; }
message TerminalError { int32 terminal_id = 1; string message = 2; }
// ===== Others =====
message MessageBox {
string msgtype = 1;
string title = 2;
string text = 3;
string link = 4;
}
message PointerDeviceEvent {
TouchEvent touch = 1;
repeated ControlKey modifiers = 2;
}
message TouchEvent {
oneof union {
TouchScaleUpdate scale_update = 1;
TouchPanStart pan_start = 2;
TouchPanUpdate pan_update = 3;
TouchPanEnd pan_end = 4;
TouchEnd end = 5;
}
}
message TouchScaleUpdate { int32 scale = 1; }
message TouchPanStart { sint32 x = 1; sint32 y = 2; }
message TouchPanUpdate { sint32 x = 1; sint32 y = 2; }
message TouchPanEnd { sint32 x = 1; sint32 y = 2; }
message TouchEnd { sint32 x = 1; sint32 y = 2; }
message ScreenshotRequest { int32 display = 1; uint64 sid = 2; }
message ScreenshotResponse { uint64 sid = 1; string msg = 2; bytes data = 3; }
message SwitchSidesResponse { bytes uuid = 1; LoginRequest lr = 2; }
message VoiceCallRequest { int64 req_timestamp = 1; bool is_connect = 2; }
message VoiceCallResponse { bool accepted = 1; int64 req_timestamp = 2; int64 ack_timestamp = 3; }
message MultiClipboards { repeated Clipboard clipboards = 1; }
message Cliprdr {
oneof union {
CliprdrMonitorReady ready = 1;
CliprdrServerFormatList format_list = 2;
CliprdrServerFormatListResponse format_list_response = 3;
CliprdrServerFormatDataRequest format_data_request = 4;
CliprdrServerFormatDataResponse format_data_response = 5;
CliprdrFileContentsRequest file_contents_request = 6;
CliprdrFileContentsResponse file_contents_response = 7;
CliprdrTryEmpty try_empty = 8;
CliprdrFiles files = 9;
}
}
message CliprdrMonitorReady {}
message CliprdrServerFormatList { repeated CliprdrFormat formats = 1; }
message CliprdrFormat { int32 id = 1; string format = 2; }
message CliprdrServerFormatListResponse { int32 msg_flags = 1; }
message CliprdrServerFormatDataRequest { int32 requested_format_id = 1; }
message CliprdrServerFormatDataResponse { int32 msg_flags = 1; bytes format_data = 2; }
message CliprdrTryEmpty {}
message CliprdrFiles { repeated CliprdrFile files = 1; }
message CliprdrFile { string name = 1; uint64 size = 2; }
message CliprdrFileContentsRequest {
uint32 stream_id = 1;
uint32 list_index = 2;
uint32 dw_flags = 3;
uint64 n_position_low = 4;
uint64 n_position_high = 5;
uint32 cb_requested = 6;
bool have_clip_data_id = 7;
uint32 clip_data_id = 8;
}
message CliprdrFileContentsResponse {
int32 msg_flags = 1;
uint32 stream_id = 2;
bytes requested_data = 3;
}
`;
let root = null;
let RendezvousMessage = null;
let Message = null;
/**
* Initialize protobuf definitions. Must be called after protobuf.js is loaded.
*/
function init() {
try {
root = protobuf.Root.fromJSON(protobuf.parse(PROTO_TEXT).toJSON());
RendezvousMessage = root.lookupType('hbb.RendezvousMessage');
Message = root.lookupType('hbb.Message');
console.log('[RDProto] Protocol definitions loaded successfully');
return true;
} catch (e) {
console.error('[RDProto] Failed to load protocol definitions:', e);
return false;
}
}
/**
* Lookup a message type by name
*/
function lookup(name) {
return root.lookupType(`hbb.${name}`);
}
/**
* Encode a RendezvousMessage to bytes
*/
function encodeRendezvousMsg(data) {
const errMsg = RendezvousMessage.verify(data);
if (errMsg) throw new Error(`RendezvousMessage verify error: ${errMsg}`);
const msg = RendezvousMessage.create(data);
return RendezvousMessage.encode(msg).finish();
}
/**
* Decode a RendezvousMessage from bytes
*/
function decodeRendezvousMsg(bytes) {
return RendezvousMessage.decode(new Uint8Array(bytes));
}
/**
* Encode a Message to bytes
*/
function encodeMsg(data) {
const errMsg = Message.verify(data);
if (errMsg) throw new Error(`Message verify error: ${errMsg}`);
const msg = Message.create(data);
return Message.encode(msg).finish();
}
/**
* Decode a Message from bytes
*/
function decodeMsg(bytes) {
return Message.decode(new Uint8Array(bytes));
}
/**
* Get the active union field name from a message
*/
function getActiveField(msg) {
if (msg.union === null || msg.union === undefined) return null;
// protobuf.js oneof: check which field is set
const oneofFields = msg.$type.oneofs;
if (oneofFields && oneofFields.union) {
return oneofFields.union.oneof.find(f => msg[f] != null);
}
return null;
}
/**
* Helper: Create a TestDelay message for latency measurement
*/
function createTestDelay(fromClient = true, lastDelay = 0) {
return {
test_delay: {
time: BigInt(Date.now()),
from_client: fromClient,
last_delay: lastDelay
}
};
}
/**
* Helper: Create a MouseEvent
*/
function createMouseEvent(mask, x, y, modifiers = []) {
return {
mouse_event: {
mask: mask,
x: x,
y: y,
modifiers: modifiers
}
};
}
/**
* Helper: Create a KeyEvent (legacy mode)
*/
function createKeyEvent(controlKey, down, press = false, modifiers = []) {
return {
key_event: {
control_key: controlKey,
down: down,
press: press,
modifiers: modifiers,
mode: 0 // Legacy
}
};
}
/**
* Helper: Create a KeyEvent with character
*/
function createCharKeyEvent(chr, down, press = false, modifiers = []) {
return {
key_event: {
chr: chr,
down: down,
press: press,
modifiers: modifiers,
mode: 0 // Legacy
}
};
}
/**
* Helper: Create a LoginRequest
*/
function createLoginRequest(myId, myName, password, peerPlatform, version) {
return {
login_request: {
my_id: myId,
my_name: myName,
password: password,
my_platform: peerPlatform || 'Web',
version: version || '1.3.6',
option: {
image_quality: 0, // NotSet
show_remote_cursor: 1, // Yes
privacy_mode: 0,
disable_audio: 0,
enable_file_transfer: 1,
clipboard: 1,
supported_decoding: {
ability_vp9: true,
ability_h264: false,
ability_h265: false,
ability_vp8: true,
ability_av1: true,
prefer: 0, // Auto
}
}
}
};
}
/**
* Helper: Create a LoginRequest for password auth
*/
function createPasswordLogin(myId, myName, hashedPassword, peerPlatform, version) {
return createLoginRequest(myId, myName, hashedPassword, peerPlatform, version);
}
/**
* Helper: Create a Clipboard message
*/
function createClipboard(text) {
const encoder = new TextEncoder();
return {
clipboard: {
contents: [{
format: 0, // Text
data: encoder.encode(text)
}]
}
};
}
return {
init,
lookup,
encodeRendezvousMsg,
decodeRendezvousMsg,
encodeMsg,
decodeMsg,
getActiveField,
createTestDelay,
createMouseEvent,
createKeyEvent,
createCharKeyEvent,
createLoginRequest,
createPasswordLogin,
createClipboard,
// Expose type references
get Message() { return Message; },
get RendezvousMessage() { return RendezvousMessage; },
get root() { return root; }
};
})();