1import { useRef, useState, useEffect } from 'react';
3export function useRemoteDesktop(agentId) {
4 const rdsWS = useRef(null);
5 const rdsImgRef = useRef(null);
6 const [rdsFrame, setRdsFrame] = useState(null);
7 const [scriptOutput, setScriptOutput] = useState('');
8 const [scriptRunning, setScriptRunning] = useState(false);
10 const connectRds = () => {
12 const loc = window.location;
13 const proto = loc.protocol === 'https:' ? 'wss' : 'ws';
14 const host = loc.host;
15 const token = localStorage.getItem('jwt') || '';
16 const ws = new WebSocket(`${proto}://${host}/api/rds/stream/${agentId}?token=${token}`);
18 ws.onmessage = (event) => {
20 const parsed = JSON.parse(event.data);
21 if (parsed.type === 'script_output') {
22 setScriptOutput((prev) => prev + parsed.data);
23 } else if (parsed.type === 'script_done') {
24 setScriptRunning(false);
25 setScriptOutput((prev) => prev + `\n[Process exited with code ${parsed.code}]\n`);
26 } else if (parsed.type === 'frame') {
27 setRdsFrame(parsed.data);
30 // ignore non-JSON output
34 console.warn('WebSocket closed.');
35 setScriptRunning(false);
39 const handleMouseEvent = (e) => {
40 if (!rdsWS.current || rdsWS.current.readyState !== WebSocket.OPEN) return;
41 const rect = rdsImgRef.current.getBoundingClientRect();
42 const x = (e.clientX - rect.left) / rect.width;
43 const y = (e.clientY - rect.top) / rect.height;
52 rdsWS.current.send(JSON.stringify(msg));
56 const handleKeyEvent = (e, rdsOpen) => {
58 rdsWS.current?.send(JSON.stringify({
75 rdsWS.current.close();
80 const sendClipboard = async () => {
82 const txt = await navigator.clipboard.readText();
83 rdsWS.current?.send(JSON.stringify({ type: "clipboard", text: txt }));
87 const uploadFile = async (file) => {
88 const buf = await file.arrayBuffer();
89 const base64 = btoa(String.fromCharCode(...new Uint8Array(buf)));
90 rdsWS.current.send(JSON.stringify({