This commit is contained in:
Baobhan Sith
2025-04-20 17:48:19 +08:00
parent 17f30f33d4
commit 9a496252d2
4 changed files with 423 additions and 30 deletions
+80
View File
@@ -42,6 +42,18 @@ interface PortInfo {
}
// --- End FIX ---
// --- NEW: Stats Interface (Ensure this matches frontend) ---
interface DockerStats {
ID: string;
Name: string;
CPUPerc: string;
MemUsage: string;
MemPerc: string;
NetIO: string;
BlockIO: string;
PIDs: string;
}
// --- 新增:解析 Ports 字符串的辅助函数 ---
function parsePortsString(portsString: string | undefined | null): PortInfo[] { // Now PortInfo is defined
if (!portsString) {
@@ -680,6 +692,74 @@ export const initializeWebSocket = async (server: http.Server, sessionParser: Re
break;
}
// --- NEW CASE: Handle docker:get_stats ---
case 'docker:get_stats': {
if (!state || !state.sshClient) { // Check state and sshClient
console.warn(`WebSocket: 收到来自 ${ws.username} (会话: ${sessionId}) 的 ${type} 请求,但无活动 SSH 连接。`);
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId: payload?.containerId, message: 'SSH connection not active.' } }));
return; // Use return instead of break inside switch
}
if (!payload || !payload.containerId) {
console.warn(`WebSocket: Invalid payload for docker:get_stats in session ${sessionId}:`, payload);
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId: payload?.containerId, message: 'Missing containerId.' } }));
return;
}
const containerId = payload.containerId;
console.log(`WebSocket: Handling docker:get_stats for container ${containerId} in session ${sessionId}`);
const command = `docker stats ${containerId} --no-stream --format '{{json .}}'`;
try {
// --- FIX: Use sshClient.exec directly ---
const execResult = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
let stdout = '';
let stderr = '';
state.sshClient.exec(command, { pty: false }, (err, stream) => {
if (err) return reject(err);
stream.on('data', (data: Buffer) => { stdout += data.toString(); });
stream.stderr.on('data', (data: Buffer) => { stderr += data.toString(); });
stream.on('close', (code: number | null) => {
// Don't reject on non-zero exit code here, stderr check is more reliable for docker stats
resolve({ stdout, stderr });
});
stream.on('error', (execErr: Error) => reject(execErr));
});
});
// --- End FIX ---
if (execResult.stderr) {
// Handle cases like container not found or docker errors
console.error(`WebSocket: Docker stats stderr for ${containerId} in session ${sessionId}: ${execResult.stderr}`);
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId, message: execResult.stderr.trim() || 'Error executing stats command.' } }));
return; // Use return after sending error
}
if (!execResult.stdout) {
console.warn(`WebSocket: No stats output for container ${containerId} in session ${sessionId}. Might be stopped or error occurred.`);
// Check stderr again just in case, although previous check should catch most errors
if (!execResult.stderr) {
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId, message: 'No stats data received (container might be stopped).' } }));
}
return; // Use return after sending error or warning
}
try {
const statsData = JSON.parse(execResult.stdout.trim());
// Optional: Clean up or format statsData if needed before sending
ws.send(JSON.stringify({ type: 'docker:stats:update', payload: { containerId, stats: statsData } }));
} catch (parseError) {
console.error(`WebSocket: Failed to parse docker stats JSON for ${containerId} in session ${sessionId}: ${execResult.stdout}`, parseError);
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId, message: 'Failed to parse stats data.' } }));
}
} catch (error: any) {
console.error(`WebSocket: Failed to execute docker stats for ${containerId} in session ${sessionId}:`, error);
ws.send(JSON.stringify({ type: 'docker:stats:error', payload: { containerId, message: error.message || 'Failed to fetch Docker stats.' } }));
}
break; // Break after handling the case
} // --- END CASE: docker:get_stats ---
default:
console.warn(`WebSocket:收到来自 ${ws.username} (会话: ${sessionId}) 的未知消息类型: ${type}`);
ws.send(JSON.stringify({ type: 'error', payload: `不支持的消息类型: ${type}` }));