fix vnc bug

This commit is contained in:
赵一寰 2026-03-14 16:32:10 +08:00
parent c80d175556
commit 8cd238d9aa
5 changed files with 77 additions and 13 deletions

View File

@ -1509,7 +1509,9 @@ export function renderApp(state: AppViewState) {
"
>
<claw-computer-panel
.enabled=${state.showClawComputer}
.vncUrl=${state.settings.vncWsUrl}
.vncTarget=${state.settings.vncTarget}
.password=${state.settings.vncPassword}
@close=${() => state.toggleClawComputer()}
style="flex: 1; min-height: 0;"

View File

@ -22,7 +22,8 @@ interface RFBInstance {
@customElement("claw-computer-panel")
export class ClawComputerPanel extends LitElement {
@property() vncUrl = "ws://localhost:8081";
@property() vncUrl = "";
@property() vncTarget = "";
@property() password = "";
@state() status = "等待連接...";
@ -33,6 +34,20 @@ export class ClawComputerPanel extends LitElement {
private screenRef: Ref<HTMLDivElement> = createRef<HTMLDivElement>();
private autoConnectAttempted = false;
@property({ type: Boolean }) enabled = false;
updated(changedProperties: Map<string, unknown>) {
if (changedProperties.has("enabled")) {
if (this.enabled) {
if (!this.isConnected) {
setTimeout(() => void this.connect(), 100);
}
} else {
this.disconnect();
}
}
}
static styles = css`
:host {
display: block;
@ -179,7 +194,25 @@ export class ClawComputerPanel extends LitElement {
};
private connect = async () => {
const url = this.vncUrl || "ws://localhost:8081";
let url =
this.vncUrl || `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/vnc`;
// Append target configuration if available
if (this.vncTarget) {
try {
const urlObj = new URL(url);
urlObj.searchParams.set("target", this.vncTarget);
url = urlObj.toString();
} catch {
// Fallback for non-standard WebSocket URLs if URL parsing fails
if (url.includes("?")) {
url += `&target=${encodeURIComponent(this.vncTarget)}`;
} else {
url += `?target=${encodeURIComponent(this.vncTarget)}`;
}
}
}
if (this.rfb) {
this.rfb.disconnect();
}
@ -213,6 +246,12 @@ export class ClawComputerPanel extends LitElement {
clipViewport: true,
});
// @ts-ignore
this.rfb.addEventListener("securityfailure", (e: CustomEvent) => {
console.error("VNC security failure:", e.detail);
this.status = `Security negotiation failed: ${e.detail.reason || "Unknown reason"}`;
});
if (this.rfb) {
this.rfb.scaleViewport = this.isFitted;
}
@ -271,8 +310,8 @@ export class ClawComputerPanel extends LitElement {
firstUpdated() {
window.addEventListener("resize", this.handleResize);
// Auto-connect if URL is configured
if (this.vncUrl) {
// Auto-connect if enabled and URL is configured
if (this.enabled && this.vncUrl) {
// Use setTimeout to ensure DOM is fully ready and to allow UI to render first
setTimeout(() => {
void this.connect();

View File

@ -138,8 +138,11 @@ export function loadSettings(): UiSettings {
navCollapsed: false,
navWidth: 220,
navGroupsCollapsed: {},
vncWsUrl: "ws://localhost:8081",
vncTarget: "10.75.171.25900",
vncWsUrl:
typeof location !== "undefined"
? `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/vnc`
: "ws://localhost:18789/vnc",
vncTarget: "localhost:5900",
};
try {

View File

@ -347,7 +347,7 @@ export function renderOverview(props: OverviewProps) {
const v = (e.target as HTMLInputElement).value;
props.onSettingsChange({ ...props.settings, vncTarget: v });
}}
placeholder="10.75.171.25900"
placeholder="localhost:5900"
/>
</label>
<label class="field">

View File

@ -3,8 +3,8 @@ import type { PluginOption } from "vite";
import { WebSocketServer, type RawData } from "ws";
// Use environment variables or hardcoded defaults from the external script
const VNC_HOST = process.env.OPENCLAW_VNC_HOST || "10.75.171.0";
const VNC_PORT = parseInt(process.env.OPENCLAW_VNC_PORT || "25900", 10);
const VNC_HOST = process.env.OPENCLAW_VNC_HOST || "localhost";
const VNC_PORT = parseInt(process.env.OPENCLAW_VNC_PORT || "5900", 10);
const WS_PATH = "/vnc";
export function vncProxyPlugin(): PluginOption {
@ -21,10 +21,29 @@ export function vncProxyPlugin(): PluginOption {
console.log(`🚀 [Proxy] VNC WebSocket proxy injected at ${WS_PATH}`);
console.log(` Forwarding to: ${VNC_HOST}:${VNC_PORT}`);
wss.on("connection", (ws) => {
console.log(`[VNC Proxy] Client connected to ${WS_PATH}`);
wss.on("connection", (ws, req) => {
const url = new URL(req.url ?? "/", "http://localhost");
const target = url.searchParams.get("target");
const tcpSocket = net.connect(VNC_PORT, VNC_HOST);
let host = VNC_HOST;
let port = VNC_PORT;
if (target) {
if (target.includes(":")) {
const parts = target.split(":");
host = parts[0];
const p = parseInt(parts[1], 10);
if (!isNaN(p)) {
port = p;
}
} else {
host = target;
}
}
console.log(`[VNC Proxy] Client connected to ${WS_PATH}, forwarding to ${host}:${port}`);
const tcpSocket = net.connect(port, host);
tcpSocket.on("data", (data) => {
if (ws.readyState === ws.OPEN) {
@ -61,7 +80,8 @@ export function vncProxyPlugin(): PluginOption {
// Hook into Vite's HTTP server upgrade event
server.httpServer?.on("upgrade", (req, socket, head) => {
if (req.url === WS_PATH) {
const url = new URL(req.url ?? "/", "http://localhost");
if (url.pathname === WS_PATH) {
wss.handleUpgrade(req, socket, head, (ws) => {
wss.emit("connection", ws, req);
});