Files
rspade_system/app/RSpade/resource/vscode_extension/out/debug_client.js
root 14dd2fd223 Fix code quality violations for publish
Progressive breadcrumb resolution with caching, fix double headers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-16 04:43:47 +00:00

211 lines
7.4 KiB
JavaScript
Executable File

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DebugClient = void 0;
const vscode = __importStar(require("vscode"));
const crypto = __importStar(require("crypto"));
class DebugClient {
constructor(formattingProvider) {
this.ws = null; // WebSocket instance
this.isConnecting = false;
this.reconnectTimer = null;
this.pingTimer = null;
this.sessionId = null;
this.serverKey = null;
this.formattingProvider = formattingProvider;
this.outputChannel = vscode.window.createOutputChannel('RSPade Debug Proxy');
this.outputChannel.show();
this.log('Debug client initialized');
}
async start() {
this.log('Starting debug client...');
await this.connect();
}
async connect() {
if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) {
return;
}
this.isConnecting = true;
try {
// Get authentication from formatting provider
await this.ensureAuthenticated();
const serverUrl = await this.formattingProvider.get_server_url();
if (!serverUrl) {
throw new Error('No server URL configured');
}
// Parse URL and construct WebSocket URL
const url = new URL(serverUrl);
const wsProtocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${wsProtocol}//${url.host}/_ide/debug/ws`;
this.log(`Connecting to WebSocket: ${wsUrl}`);
// Create WebSocket (standard API doesn't support headers in constructor)
// We'll send auth after connection
this.ws = new WebSocket(wsUrl);
this.setupEventHandlers();
}
catch (error) {
this.log(`Connection failed: ${error.message}`);
this.isConnecting = false;
this.scheduleReconnect();
}
}
setupEventHandlers() {
if (!this.ws)
return;
this.ws.onopen = () => {
this.isConnecting = false;
this.log('WebSocket connected, sending authentication...');
// Send authentication as first message
const signature = crypto
.createHmac('sha256', this.serverKey)
.update(this.sessionId)
.digest('hex');
this.sendMessage({
type: 'auth',
data: {
sessionId: this.sessionId,
signature: signature
}
});
// Send initial hello message after auth
setTimeout(() => {
this.sendMessage({
type: 'hello',
data: { name: 'VS Code Debug Client' }
});
// Start ping timer
this.startPingTimer();
}, 100);
};
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
this.handleMessage(message);
}
catch (error) {
this.log(`Failed to parse message: ${error}`);
}
};
this.ws.onclose = () => {
this.log('WebSocket disconnected');
this.ws = null;
this.stopPingTimer();
this.scheduleReconnect();
};
this.ws.onerror = (error) => {
this.log(`WebSocket error: ${error}`);
};
}
handleMessage(message) {
this.log(`Received: ${message.type}`, message.data);
switch (message.type) {
case 'welcome':
this.log('✅ Authentication successful! Connected to debug proxy');
this.log(`Session ID: ${message.data?.sessionId}`);
break;
case 'pong':
this.log(`PONG received! Server responded to ping`);
break;
case 'hello_response':
this.log(`Server says: ${message.data?.message}`);
break;
case 'error':
this.log(`❌ Error: ${message.data?.message}`);
break;
default:
this.log(`Unknown message type: ${message.type}`);
}
}
sendMessage(message) {
if (this.ws?.readyState === 1) { // 1 = OPEN in standard WebSocket API
this.ws.send(JSON.stringify(message));
this.log(`Sent: ${message.type}`, message.data);
}
}
startPingTimer() {
this.stopPingTimer();
// Send ping every 5 seconds
this.pingTimer = setInterval(() => {
this.sendMessage({
type: 'ping',
data: { timestamp: Date.now() }
});
this.log('PING sent to server');
}, 5000);
}
stopPingTimer() {
if (this.pingTimer) {
clearInterval(this.pingTimer);
this.pingTimer = null;
}
}
scheduleReconnect() {
if (this.reconnectTimer) {
return;
}
this.log('Scheduling reconnection in 5 seconds...');
this.reconnectTimer = setTimeout(() => {
this.reconnectTimer = null;
this.connect();
}, 5000);
}
async ensureAuthenticated() {
// Get auth data from formatting provider
const authData = await this.formattingProvider.ensure_auth();
if (!authData) {
throw new Error('Failed to authenticate');
}
// Extract session ID and server key
this.sessionId = authData.session_id;
this.serverKey = authData.server_key;
if (!this.sessionId || !this.serverKey) {
throw new Error('Invalid auth data');
}
}
log(message, data) {
const timestamp = new Date().toISOString();
const logMessage = `[${timestamp}] ${message}`;
if (data) {
this.outputChannel.appendLine(`${logMessage}\n${JSON.stringify(data, null, 2)}`);
}
else {
this.outputChannel.appendLine(logMessage);
}
}
dispose() {
this.stopPingTimer();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
if (this.ws) {
this.ws.close();
this.ws = null;
}
this.outputChannel.dispose();
}
}
exports.DebugClient = DebugClient;
//# sourceMappingURL=debug_client.js.map