3 * Test script for custom canvas desktop endpoint
4 * Tests WebSocket connection and JWT authentication
7 * node test-canvas-endpoint.js <jwt_token> <node_id> [meshcentral_url]
10 * node test-canvas-endpoint.js "eyJhbGc..." "node123" "wss://meshcentral.domain.com"
13const WebSocket = require('ws');
15// Parse command line arguments
16const args = process.argv.slice(2);
18 console.log('Usage: node test-canvas-endpoint.js <jwt_token> <node_id> [meshcentral_url]');
20 console.log('Arguments:');
21 console.log(' jwt_token - JWT token from dashboard login');
22 console.log(' node_id - MeshCentral node ID (agent identifier)');
23 console.log(' meshcentral_url - Optional: MeshCentral WebSocket URL');
24 console.log(' Default: wss://rmm-psa-meshcentral-aq48h.ondigitalocean.app');
26 console.log('Example:');
27 console.log(' node test-canvas-endpoint.js "eyJhbGc..." "node//abc123..."');
32const nodeId = args[1];
33const baseUrl = args[2] || 'wss://rmm-psa-meshcentral-aq48h.ondigitalocean.app';
36const wsUrl = `${baseUrl}/api/canvas-desktop/${encodeURIComponent(nodeId)}?token=${encodeURIComponent(token)}`;
38console.log('========================================');
39console.log('Canvas Desktop Endpoint Test');
40console.log('========================================');
42console.log('Configuration:');
43console.log(` Node ID: ${nodeId}`);
44console.log(` Token: ${token.substring(0, 30)}...`);
45console.log(` URL: ${baseUrl}`);
47console.log('Connecting...');
50// Create WebSocket connection
51const ws = new WebSocket(wsUrl, {
52 rejectUnauthorized: false // Accept self-signed certificates (dev/staging only)
59 console.log('✅ WebSocket connection OPENED');
63 console.log('📤 Sending ping...');
64 ws.send(JSON.stringify({ type: 'ping', timestamp: Date.now() }));
66 // Setup ping interval to keep connection alive
67 pingInterval = setInterval(() => {
68 if (ws.readyState === WebSocket.OPEN) {
69 console.log('📤 Sending periodic ping...');
70 ws.send(JSON.stringify({ type: 'ping', timestamp: Date.now() }));
72 }, 10000); // Ping every 10 seconds
75ws.on('message', (data) => {
78 const msg = JSON.parse(data.toString());
79 console.log(`📨 Message ${messageCount} received:`, JSON.stringify(msg, null, 2));
82 // If this is a pong response, calculate latency
83 if (msg.type === 'pong' && msg.timestamp) {
84 const latency = Date.now() - msg.timestamp;
85 console.log(`⚡ Latency: ${latency}ms`);
89 // If connected successfully, show capabilities
90 if (msg.type === 'connected') {
91 console.log('🎉 Connection Successful!');
93 console.log('Connection Details:');
94 console.log(` Node ID: ${msg.nodeId}`);
95 console.log(` User ID: ${msg.userId}`);
96 console.log(` Tenant ID: ${msg.tenantId}`);
97 console.log(` Phase: ${msg.phase}`);
98 console.log(` Capabilities: ${msg.capabilities?.join(', ')}`);
99 console.log(` Message: ${msg.message}`);
104 console.error('❌ Error parsing message:', err.message);
105 console.error(' Raw data:', data.toString());
110ws.on('error', (err) => {
111 console.error('❌ WebSocket ERROR:', err.message);
114 // Common errors and solutions
115 if (err.message.includes('ENOTFOUND')) {
116 console.log('💡 Troubleshooting: Cannot resolve hostname');
117 console.log(' - Check if MeshCentral URL is correct');
118 console.log(' - Verify DNS resolution');
119 } else if (err.message.includes('ECONNREFUSED')) {
120 console.log('💡 Troubleshooting: Connection refused');
121 console.log(' - Check if MeshCentral is running');
122 console.log(' - Verify the port is correct');
123 } else if (err.message.includes('401') || err.message.includes('403')) {
124 console.log('💡 Troubleshooting: Authentication failed');
125 console.log(' - Check if JWT token is valid');
126 console.log(' - Verify token has not expired');
127 console.log(' - Ensure JWT_SECRET matches between backend and MeshCentral');
132ws.on('close', (code, reason) => {
133 clearInterval(pingInterval);
134 console.log(`🔌 WebSocket CLOSED`);
135 console.log(` Code: ${code}`);
136 console.log(` Reason: ${reason || 'No reason provided'}`);
138 console.log(`Total messages received: ${messageCount}`);
141 // Explain close codes
143 console.log('✅ Normal closure (successful test)');
144 } else if (code === 1006) {
145 console.log('⚠️ Abnormal closure (connection lost without close frame)');
146 } else if (code === 1008) {
147 console.log('❌ Policy violation (likely authentication failed)');
148 } else if (code === 1011) {
149 console.log('❌ Server error');
152 process.exit(code === 1000 ? 0 : 1);
155// Handle Ctrl+C gracefully
156process.on('SIGINT', () => {
158 console.log('⚠️ Interrupted by user');
159 console.log('Closing connection...');
160 ws.close(1000, 'User interrupted');
163// Timeout after 30 seconds
165 if (ws.readyState === WebSocket.OPEN) {
166 console.log('⏱️ Test timeout (30 seconds) - closing connection');
167 ws.close(1000, 'Test completed');
171console.log('Test running... (press Ctrl+C to stop)');