Bug fixes

This commit is contained in:
Raven Scott
2024-11-28 02:51:47 -05:00
parent db04774fb4
commit 9ec5bf0788
4 changed files with 291 additions and 117 deletions

View File

@ -3,6 +3,7 @@
import Hyperswarm from 'hyperswarm';
import Docker from 'dockerode';
import crypto from 'hypercore-crypto';
import { PassThrough } from 'stream';
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
const swarm = new Hyperswarm();
@ -80,8 +81,9 @@ swarm.on('connection', (peer) => {
break;
default:
console.warn(`[WARN] Unknown command: ${parsedData.command}`);
response = { error: 'Unknown command' };
// console.warn(`[WARN] Unknown command: ${parsedData.command}`);
// response = { error: 'Unknown command' };
return
}
// Send response if one was generated
@ -95,9 +97,15 @@ swarm.on('connection', (peer) => {
}
});
peer.on('error', (err) => {
console.error(`[ERROR] Peer connection error: ${err.message}`);
cleanupPeer(peer);
});
peer.on('close', () => {
console.log('[INFO] Peer disconnected');
connectedPeers.delete(peer);
cleanupPeer(peer)
// Clean up any terminal session associated with this peer
if (terminalSessions.has(peer)) {
@ -110,6 +118,19 @@ swarm.on('connection', (peer) => {
});
});
// Helper function to handle peer cleanup
function cleanupPeer(peer) {
connectedPeers.delete(peer);
if (terminalSessions.has(peer)) {
const session = terminalSessions.get(peer);
console.log(`[INFO] Cleaning up terminal session for container: ${session.containerId}`);
session.stream.end();
peer.removeListener('data', session.onData);
terminalSessions.delete(peer);
}
}
// Function to duplicate a container
async function duplicateContainer(name, config, peer) {
try {
@ -143,21 +164,30 @@ async function duplicateContainer(name, config, peer) {
// Start the new container
await newContainer.start();
// Send success response
// Send success response to the requesting peer
peer.write(JSON.stringify({ success: true, message: `Container '${newName}' duplicated and started successfully.` }));
// List containers again to update the client
// Get the updated list of containers
const containers = await docker.listContainers({ all: true });
const update = { type: 'containers', data: containers };
// Broadcast the updated container list to all connected peers
for (const connectedPeer of connectedPeers) {
connectedPeer.write(JSON.stringify(update));
}
// Start streaming stats for the new container
const newContainerInfo = containers.find(c => c.Names.includes(`/${newName}`));
if (newContainerInfo) {
streamContainerStats(newContainerInfo);
}
} catch (err) {
console.error(`[ERROR] Failed to duplicate container: ${err.message}`);
peer.write(JSON.stringify({ error: `Failed to duplicate container: ${err.message}` }));
}
}
// Stream Docker events to all peers
docker.getEvents({}, (err, stream) => {
if (err) {
@ -195,7 +225,6 @@ docker.listContainers({ all: true }, (err, containers) => {
const container = docker.getContainer(containerInfo.Id);
container.stats({ stream: true }, (err, stream) => {
if (err) {
console.error(`[ERROR] Failed to get stats for container ${containerInfo.Id}: ${err.message}`);
return;
}
@ -219,12 +248,10 @@ docker.listContainers({ all: true }, (err, containers) => {
peer.write(JSON.stringify({ type: 'stats', data: statsData }));
}
} catch (err) {
console.error(`[ERROR] Failed to parse stats for container ${containerInfo.Id}: ${err.message}`);
}
});
stream.on('error', (err) => {
console.error(`[ERROR] Stats stream error for container ${containerInfo.Id}: ${err.message}`);
});
});
});
@ -241,6 +268,7 @@ function calculateCPUPercent(stats) {
return 0.0;
}
// Function to handle terminal sessions
// Function to handle terminal sessions
async function handleTerminal(containerId, peer) {
const container = docker.getContainer(containerId);
@ -258,16 +286,18 @@ async function handleTerminal(containerId, peer) {
console.log(`[INFO] Terminal session started for container: ${containerId}`);
const stdout = new PassThrough();
const stderr = new PassThrough();
container.modem.demuxStream(stream, stdout, stderr);
const onData = (input) => {
try {
const parsed = JSON.parse(input.toString());
if (parsed.type === 'terminalInput' && parsed.data) {
let inputData;
if (parsed.encoding === 'base64') {
inputData = Buffer.from(parsed.data, 'base64');
} else {
inputData = Buffer.from(parsed.data);
}
const inputData = parsed.encoding === 'base64'
? Buffer.from(parsed.data, 'base64')
: Buffer.from(parsed.data);
stream.write(inputData);
}
} catch (err) {
@ -276,16 +306,22 @@ async function handleTerminal(containerId, peer) {
};
peer.on('data', onData);
// Store the session along with the onData listener
terminalSessions.set(peer, { containerId, exec, stream, onData });
stream.on('data', (chunk) => {
const dataBase64 = chunk.toString('base64');
stdout.on('data', (chunk) => {
peer.write(JSON.stringify({
type: 'terminalOutput',
containerId,
data: dataBase64,
data: chunk.toString('base64'),
encoding: 'base64',
}));
});
stderr.on('data', (chunk) => {
peer.write(JSON.stringify({
type: 'terminalErrorOutput',
containerId,
data: chunk.toString('base64'),
encoding: 'base64',
}));
});
@ -302,6 +338,7 @@ async function handleTerminal(containerId, peer) {
}
}
// Function to handle killing terminal sessions
function handleKillTerminal(containerId, peer) {
const session = terminalSessions.get(peer);
@ -322,9 +359,45 @@ function handleKillTerminal(containerId, peer) {
}
}
// Function to duplicate a container (already defined above)
function streamContainerStats(containerInfo) {
const container = docker.getContainer(containerInfo.Id);
container.stats({ stream: true }, (err, stream) => {
if (err) {
console.error(`[ERROR] Failed to get stats for container ${containerInfo.Id}: ${err.message}`);
return;
}
stream.on('data', (data) => {
try {
const stats = JSON.parse(data.toString());
const cpuUsage = calculateCPUPercent(stats);
const memoryUsage = stats.memory_stats.usage;
const networks = stats.networks;
const ipAddress = networks ? Object.values(networks)[0].IPAddress : '-';
const statsData = {
id: containerInfo.Id,
cpu: cpuUsage,
memory: memoryUsage,
ip: ipAddress,
};
// Broadcast stats to all connected peers
for (const peer of connectedPeers) {
peer.write(JSON.stringify({ type: 'stats', data: statsData }));
}
} catch (err) {
console.error(`[ERROR] Failed to parse stats for container ${containerInfo.Id}: ${err.message}`);
}
});
stream.on('error', (err) => {
console.error(`[ERROR] Stats stream error for container ${containerInfo.Id}: ${err.message}`);
});
});
}
// Stream Docker events to all peers (already defined above)
// Handle process termination
process.on('SIGINT', () => {