Add Remote Desktop (JPEG-over-WebSocket), Agent v2.2.0
- RtcService.cs: Screen capture via Graphics.CopyFromScreen, ~8fps JPEG stream over WebSocket - shellServer.js: Separate rdp-agent/rdp types with independent socket maps (no shell collision) - AgentDetailPage: WebSocket-based RemoteDesktop component replaces WebRTC attempt - setup.iss: Fixed filename to include 'v' prefix (IT-Nexus-Agent-Setup-v2.2.0.exe) - Removed SIPSorcery dependencies, added System.Drawing.Common Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,10 @@ const agentSockets = new Map();
|
||||
// agentId -> WebSocket
|
||||
const browserSockets = new Map();
|
||||
|
||||
// RDP: separate Maps damit Shell nicht kollidiert
|
||||
const rdpAgentSockets = new Map();
|
||||
const rdpBrowserSockets = new Map();
|
||||
|
||||
function setupWebSocketServer(httpServer) {
|
||||
const wss = new WebSocket.Server({ server: httpServer, path: '/ws' });
|
||||
|
||||
@@ -24,6 +28,10 @@ function setupWebSocketServer(httpServer) {
|
||||
handleAgent(ws, url);
|
||||
} else if (type === 'shell') {
|
||||
handleBrowser(ws, url);
|
||||
} else if (type === 'rdp-agent') {
|
||||
handleRdpAgent(ws, url);
|
||||
} else if (type === 'rdp') {
|
||||
handleRdpBrowser(ws, url);
|
||||
} else {
|
||||
ws.close(1008, 'unknown type');
|
||||
}
|
||||
@@ -124,6 +132,63 @@ function handleBrowser(ws, url) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleRdpAgent(ws, url) {
|
||||
const key = url.searchParams.get('key');
|
||||
if (key !== process.env.AGENT_API_KEY) { ws.close(1008, 'unauthorized'); return; }
|
||||
const hostname = url.searchParams.get('hostname');
|
||||
if (!hostname) { ws.close(1008, 'hostname required'); return; }
|
||||
|
||||
const db = getDatabase();
|
||||
const agent = db.prepare('SELECT id FROM monitoring_agents WHERE hostname = ?').get(hostname);
|
||||
if (!agent) { ws.close(1008, 'agent not found'); return; }
|
||||
|
||||
const agentId = agent.id;
|
||||
const oldWs = rdpAgentSockets.get(agentId);
|
||||
if (oldWs?.readyState === WebSocket.OPEN) oldWs.close();
|
||||
rdpAgentSockets.set(agentId, ws);
|
||||
console.log(`[WS-RDP] Agent verbunden: ${hostname}`);
|
||||
|
||||
ws.on('message', (data) => {
|
||||
const bws = rdpBrowserSockets.get(agentId);
|
||||
if (bws?.readyState === WebSocket.OPEN) bws.send(data.toString());
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
rdpAgentSockets.delete(agentId);
|
||||
const bws = rdpBrowserSockets.get(agentId);
|
||||
if (bws?.readyState === WebSocket.OPEN) {
|
||||
bws.send(JSON.stringify({ type: 'rdp_disconnected' }));
|
||||
}
|
||||
console.log(`[WS-RDP] Agent getrennt: ${hostname}`);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRdpBrowser(ws, url) {
|
||||
const token = url.searchParams.get('token');
|
||||
try { jwt.verify(token, process.env.JWT_SECRET); }
|
||||
catch { ws.close(1008, 'unauthorized'); return; }
|
||||
|
||||
const agentId = parseInt(url.searchParams.get('agentId'));
|
||||
if (!agentId) { ws.close(1008, 'agentId required'); return; }
|
||||
|
||||
const oldBws = rdpBrowserSockets.get(agentId);
|
||||
if (oldBws?.readyState === WebSocket.OPEN) oldBws.close();
|
||||
rdpBrowserSockets.set(agentId, ws);
|
||||
|
||||
ws.on('message', (data) => {
|
||||
const aws = rdpAgentSockets.get(agentId);
|
||||
if (aws?.readyState === WebSocket.OPEN) aws.send(data.toString());
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
rdpBrowserSockets.delete(agentId);
|
||||
const aws = rdpAgentSockets.get(agentId);
|
||||
if (aws?.readyState === WebSocket.OPEN) {
|
||||
aws.send(JSON.stringify({ type: 'rdp_stop' }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Ankündigung an Agent pushen (für sofortige Zustellung)
|
||||
function pushAnnouncementToAgent(agentId, announcements) {
|
||||
const aws = agentSockets.get(agentId);
|
||||
|
||||
Reference in New Issue
Block a user