mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-01-22 18:13:00 +08:00
more api
This commit is contained in:
parent
2846804234
commit
f4c3198037
@ -15,6 +15,7 @@
|
|||||||
"libsodium": "^0.7.9",
|
"libsodium": "^0.7.9",
|
||||||
"libsodium-wrappers": "^0.7.9",
|
"libsodium-wrappers": "^0.7.9",
|
||||||
"ogv": "^1.8.6",
|
"ogv": "^1.8.6",
|
||||||
"ts-proto": "^1.101.0"
|
"ts-proto": "^1.101.0",
|
||||||
|
"zstddec": "^0.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,22 @@ export default class Connection {
|
|||||||
_interval: any;
|
_interval: any;
|
||||||
_id: string;
|
_id: string;
|
||||||
_hash: message.Hash | undefined;
|
_hash: message.Hash | undefined;
|
||||||
_msgbox: MsgboxCallback | undefined;
|
_msgbox: MsgboxCallback;
|
||||||
_draw: DrawCallback | undefined;
|
_draw: DrawCallback;
|
||||||
_peerInfo: message.PeerInfo | undefined;
|
_peerInfo: message.PeerInfo | undefined;
|
||||||
_firstFrame: Boolean | undefined;
|
_firstFrame: Boolean | undefined;
|
||||||
_videoDecoder: any;
|
_videoDecoder: any;
|
||||||
_audioDecoder: any;
|
_audioDecoder: any;
|
||||||
|
_password: string | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this._msgbox = globals.msgbox;
|
||||||
|
this._draw = globals.draw;
|
||||||
this._msgs = [];
|
this._msgs = [];
|
||||||
this._id = "";
|
this._id = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(id: string) {
|
||||||
this._interval = setInterval(() => {
|
this._interval = setInterval(() => {
|
||||||
while (this._msgs.length) {
|
while (this._msgs.length) {
|
||||||
this._ws?.sendMessage(this._msgs[0]);
|
this._ws?.sendMessage(this._msgs[0]);
|
||||||
@ -44,9 +50,6 @@ export default class Connection {
|
|||||||
this._audioDecoder = decoder;
|
this._audioDecoder = decoder;
|
||||||
console.log("opus loaded");
|
console.log("opus loaded");
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
async start(id: string) {
|
|
||||||
const uri = getDefaultUri();
|
const uri = getDefaultUri();
|
||||||
const ws = new Websock(uri);
|
const ws = new Websock(uri);
|
||||||
this._ws = ws;
|
this._ws = ws;
|
||||||
@ -69,7 +72,7 @@ export default class Connection {
|
|||||||
const phr = msg.punchHoleResponse;
|
const phr = msg.punchHoleResponse;
|
||||||
const rr = msg.relayResponse;
|
const rr = msg.relayResponse;
|
||||||
if (phr) {
|
if (phr) {
|
||||||
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNKNOWN) {
|
if (phr.failure != rendezvous.PunchHoleResponse_Failure.UNRECOGNIZED) {
|
||||||
switch (phr?.failure) {
|
switch (phr?.failure) {
|
||||||
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
|
case rendezvous.PunchHoleResponse_Failure.ID_NOT_EXIST:
|
||||||
this.msgbox("error", "Error", "ID does not exist");
|
this.msgbox("error", "Error", "ID does not exist");
|
||||||
@ -110,7 +113,8 @@ export default class Connection {
|
|||||||
uuid,
|
uuid,
|
||||||
});
|
});
|
||||||
ws.sendRendezvous({ requestRelay });
|
ws.sendRendezvous({ requestRelay });
|
||||||
await this.secure(pk);
|
const secure = (await this.secure(pk)) || false;
|
||||||
|
globals.pushEvent("connection_ready", { secure, direct: false });
|
||||||
await this.msgLoop();
|
await this.msgLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +183,7 @@ export default class Connection {
|
|||||||
});
|
});
|
||||||
await this._ws?.sendMessage({ publicKey });
|
await this._ws?.sendMessage({ publicKey });
|
||||||
this._ws?.setSecretKey(secretKey);
|
this._ws?.setSecretKey(secretKey);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async msgLoop() {
|
async msgLoop() {
|
||||||
@ -186,7 +191,7 @@ export default class Connection {
|
|||||||
const msg = this._ws?.parseMessage(await this._ws?.next());
|
const msg = this._ws?.parseMessage(await this._ws?.next());
|
||||||
if (msg?.hash) {
|
if (msg?.hash) {
|
||||||
this._hash = msg?.hash;
|
this._hash = msg?.hash;
|
||||||
await this.handleHash();
|
await this.login(this._password);
|
||||||
this.msgbox("input-password", "Password Required", "");
|
this.msgbox("input-password", "Password Required", "");
|
||||||
} else if (msg?.testDelay) {
|
} else if (msg?.testDelay) {
|
||||||
const testDelay = msg?.testDelay;
|
const testDelay = msg?.testDelay;
|
||||||
@ -198,23 +203,30 @@ export default class Connection {
|
|||||||
if (r.error) {
|
if (r.error) {
|
||||||
this.msgbox("error", "Error", r.error);
|
this.msgbox("error", "Error", r.error);
|
||||||
} else if (r.peerInfo) {
|
} else if (r.peerInfo) {
|
||||||
this._peerInfo = r.peerInfo;
|
this.handlePeerInfo(r.peerInfo);
|
||||||
this.msgbox(
|
|
||||||
"success",
|
|
||||||
"Successful",
|
|
||||||
"Connected, waiting for image..."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if (msg?.videoFrame) {
|
} else if (msg?.videoFrame) {
|
||||||
this.handleVideoFrame(msg?.videoFrame!);
|
this.handleVideoFrame(msg?.videoFrame!);
|
||||||
|
} else if (msg?.clipboard) {
|
||||||
|
const cb = msg?.clipboard;
|
||||||
|
if (cb.compress) cb.content = globals.decompress(cb.content);
|
||||||
|
globals.pushEvent("clipboard", cb);
|
||||||
|
} else if (msg?.cursorData) {
|
||||||
|
const cd = msg?.cursorData;
|
||||||
|
cd.colors = globals.decompress(cd.colors);
|
||||||
|
globals.pushEvent("cursor_data", cd);
|
||||||
|
} else if (msg?.cursorId) {
|
||||||
|
globals.pushEvent("cursor_id", { id: msg?.cursorId });
|
||||||
|
} else if (msg?.cursorPosition) {
|
||||||
|
globals.pushEvent("cursor_position", msg?.cursorPosition);
|
||||||
|
} else if (msg?.misc) {
|
||||||
|
this.handleMisc(msg?.misc);
|
||||||
|
} else if (msg?.audioFrame) {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleHash() {
|
|
||||||
await this._sendLoginMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
msgbox(type_: string, title: string, text: string) {
|
msgbox(type_: string, title: string, text: string) {
|
||||||
this._msgbox?.(type_, title, text);
|
this._msgbox?.(type_, title, text);
|
||||||
}
|
}
|
||||||
@ -224,12 +236,20 @@ export default class Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
this._msgs = [];
|
||||||
clearInterval(this._interval);
|
clearInterval(this._interval);
|
||||||
this._ws?.close();
|
this._ws?.close();
|
||||||
this._videoDecoder?.close();
|
this._videoDecoder?.close();
|
||||||
this._audioDecoder?.close();
|
this._audioDecoder?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refresh() {
|
||||||
|
const misc = message.Misc.fromPartial({
|
||||||
|
refreshVideo: true,
|
||||||
|
});
|
||||||
|
await this._ws?.sendMessage({ misc });
|
||||||
|
}
|
||||||
|
|
||||||
setMsgbox(callback: MsgboxCallback) {
|
setMsgbox(callback: MsgboxCallback) {
|
||||||
this._msgbox = callback;
|
this._msgbox = callback;
|
||||||
}
|
}
|
||||||
@ -238,19 +258,27 @@ export default class Connection {
|
|||||||
this._draw = callback;
|
this._draw = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(password: string) {
|
async login(password: string | undefined, _remember: Boolean = false) {
|
||||||
|
this._password = password;
|
||||||
this.msgbox("connecting", "Connecting...", "Logging in...");
|
this.msgbox("connecting", "Connecting...", "Logging in...");
|
||||||
let salt = this._hash?.salt;
|
const salt = this._hash?.salt;
|
||||||
if (salt) {
|
if (salt && password) {
|
||||||
let p = hash([password, salt]);
|
let p = hash([password, salt]);
|
||||||
let challenge = this._hash?.challenge;
|
const challenge = this._hash?.challenge;
|
||||||
if (challenge) {
|
if (challenge) {
|
||||||
p = hash([p, challenge]);
|
p = hash([p, challenge]);
|
||||||
await this._sendLoginMessage(p);
|
await this._sendLoginMessage(p);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
await this._sendLoginMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async reconnect() {
|
||||||
|
this.close();
|
||||||
|
await this.start(this._id);
|
||||||
|
}
|
||||||
|
|
||||||
async _sendLoginMessage(password: Uint8Array | undefined = undefined) {
|
async _sendLoginMessage(password: Uint8Array | undefined = undefined) {
|
||||||
const loginRequest = message.LoginRequest.fromPartial({
|
const loginRequest = message.LoginRequest.fromPartial({
|
||||||
username: this._id!,
|
username: this._id!,
|
||||||
@ -267,7 +295,7 @@ export default class Connection {
|
|||||||
this._firstFrame = true;
|
this._firstFrame = true;
|
||||||
}
|
}
|
||||||
if (vf.vp9s) {
|
if (vf.vp9s) {
|
||||||
let dec = this._videoDecoder;
|
const dec = this._videoDecoder;
|
||||||
// dec.sync();
|
// dec.sync();
|
||||||
vf.vp9s.frames.forEach((f) => {
|
vf.vp9s.frames.forEach((f) => {
|
||||||
dec.processFrame(f.data.slice(0).buffer, (ok: any) => {
|
dec.processFrame(f.data.slice(0).buffer, (ok: any) => {
|
||||||
@ -278,6 +306,44 @@ export default class Connection {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePeerInfo(pi: message.PeerInfo) {
|
||||||
|
this._peerInfo = pi;
|
||||||
|
if (pi.displays.length == 0) {
|
||||||
|
this.msgbox("error", "Remote Error", "No Display");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.msgbox("success", "Successful", "Connected, waiting for image...");
|
||||||
|
globals.pushEvent("peer_info", pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMisc(misc: message.Misc) {
|
||||||
|
if (misc.audioFormat) {
|
||||||
|
//
|
||||||
|
} else if (misc.permissionInfo) {
|
||||||
|
const p = misc.permissionInfo;
|
||||||
|
console.info("Change permission " + p.permission + " -> " + p.enabled);
|
||||||
|
let name;
|
||||||
|
switch (p.permission) {
|
||||||
|
case message.PermissionInfo_Permission.Keyboard:
|
||||||
|
name = "keyboard";
|
||||||
|
break;
|
||||||
|
case message.PermissionInfo_Permission.Clipboard:
|
||||||
|
name = "clipboard";
|
||||||
|
break;
|
||||||
|
case message.PermissionInfo_Permission.Audio:
|
||||||
|
name = "audio";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
globals.pushEvent("permission", { [name]: p.enabled });
|
||||||
|
} else if (misc.switchDisplay) {
|
||||||
|
globals.pushEvent("switch_display", misc.switchDisplay);
|
||||||
|
} else if (misc.closeReason) {
|
||||||
|
this.msgbox("error", "Connection Error", misc.closeReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -1,7 +1,39 @@
|
|||||||
import Connection from "./connection";
|
import Connection from "./connection";
|
||||||
import _sodium from "libsodium-wrappers";
|
import _sodium from "libsodium-wrappers";
|
||||||
|
import { ZSTDecoder } from 'zstddec';
|
||||||
|
|
||||||
|
const decompressor = new ZSTDDecoder();
|
||||||
|
await decompressor.init();
|
||||||
|
|
||||||
|
var currentFrame = undefined;
|
||||||
|
var events = [];
|
||||||
|
|
||||||
window.currentConnection = undefined;
|
window.currentConnection = undefined;
|
||||||
|
window.getRgba = () => currentFrame;
|
||||||
|
window.getLanguage = () => navigator.language;
|
||||||
|
|
||||||
|
export function msgbox(type, title, text) {
|
||||||
|
text = text.toLowerCase();
|
||||||
|
var hasRetry = msgtype == "error"
|
||||||
|
&& title == "Connection Error"
|
||||||
|
&& !text.indexOf("offline") >= 0
|
||||||
|
&& !text.indexOf("exist") >= 0
|
||||||
|
&& !text.indexOf("handshake") >= 0
|
||||||
|
&& !text.indexOf("failed") >= 0
|
||||||
|
&& !text.indexOf("resolve") >= 0
|
||||||
|
&& !text.indexOf("mismatch") >= 0
|
||||||
|
&& !text.indexOf("manually") >= 0;
|
||||||
|
events.push({ name: 'msgbox', type, title, text, hasRetry });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pushEvent(name, payload) {
|
||||||
|
payload.name = name;
|
||||||
|
events.push(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function draw(frame) {
|
||||||
|
currentFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
export function setConn(conn) {
|
export function setConn(conn) {
|
||||||
window.currentConnection = conn;
|
window.currentConnection = conn;
|
||||||
@ -14,6 +46,7 @@ export function getConn() {
|
|||||||
export function close() {
|
export function close() {
|
||||||
getConn()?.close();
|
getConn()?.close();
|
||||||
setConn(undefined);
|
setConn(undefined);
|
||||||
|
currentFrame = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newConn() {
|
export function newConn() {
|
||||||
@ -74,3 +107,57 @@ export function encrypt(unsigned, nonce, key) {
|
|||||||
export function decrypt(signed, nonce, key) {
|
export function decrypt(signed, nonce, key) {
|
||||||
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
return sodium.crypto_secretbox_open_easy(signed, makeOnce(nonce), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function decompress(compressedArray) {
|
||||||
|
const MAX = 1024 * 1024 * 64;
|
||||||
|
const MIN = 1024 * 1024;
|
||||||
|
let n = 30 * data.length;
|
||||||
|
if (n > MAX) {
|
||||||
|
n = MAX;
|
||||||
|
}
|
||||||
|
if (n < MIN) {
|
||||||
|
n = MIN;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return decompressor.decode(compressedArray, n);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('decompress failed: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setByName = (name, value) => {
|
||||||
|
switch (name) {
|
||||||
|
case 'connect':
|
||||||
|
newConn();
|
||||||
|
break;
|
||||||
|
case 'login':
|
||||||
|
currentConnection.login(value.password, value.remember);
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
currentConnection.refresh();
|
||||||
|
break;
|
||||||
|
case 'reconnect':
|
||||||
|
currentConnection.reconnect();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.getByName = (name, value) => {
|
||||||
|
switch (name) {
|
||||||
|
case 'peers':
|
||||||
|
return localStorage.getItem('peers');
|
||||||
|
break;
|
||||||
|
case 'event':
|
||||||
|
if (events.length) {
|
||||||
|
const e = events[0];
|
||||||
|
events.splice(0, 1);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
@ -376,3 +376,8 @@ vite@^2.7.2:
|
|||||||
rollup "^2.59.0"
|
rollup "^2.59.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
zstddec@^0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.0.2.tgz#57e2f28dd1ff56b750e07d158a43f0611ad9eeb4"
|
||||||
|
integrity sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==
|
||||||
|
Loading…
Reference in New Issue
Block a user