forked from snxraven/peardock
add backend
This commit is contained in:
parent
8ebb9efe5a
commit
f4d88e0ded
5
app.js
5
app.js
@ -203,10 +203,7 @@ function startTerminal(containerId, containerName) {
|
||||
|
||||
xterm.onData((data) => {
|
||||
console.log(`[DEBUG] Sending terminal input: ${data}`);
|
||||
if (data === '\u001b[2;5R') {
|
||||
fitAddon.fit();
|
||||
return;
|
||||
}
|
||||
|
||||
activePeer.write(JSON.stringify({ type: 'terminalInput', data }));
|
||||
});
|
||||
|
||||
|
146
server/server.js
Normal file
146
server/server.js
Normal file
@ -0,0 +1,146 @@
|
||||
import Hyperswarm from 'hyperswarm';
|
||||
import Docker from 'dockerode';
|
||||
import crypto from 'hypercore-crypto';
|
||||
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
const swarm = new Hyperswarm();
|
||||
const connectedPeers = new Set();
|
||||
|
||||
// Generate a topic for the server
|
||||
const topic = crypto.randomBytes(32);
|
||||
console.log(`[INFO] Server started with topic: ${topic.toString('hex')}`);
|
||||
|
||||
swarm.join(topic, { server: true, client: false });
|
||||
|
||||
swarm.on('connection', (peer) => {
|
||||
console.log(`[INFO] Peer connected`);
|
||||
connectedPeers.add(peer);
|
||||
|
||||
peer.on('data', async (data) => {
|
||||
try {
|
||||
const parsedData = JSON.parse(data.toString());
|
||||
console.log(`[DEBUG] Received data from peer: ${JSON.stringify(parsedData)}`);
|
||||
let response;
|
||||
|
||||
switch (parsedData.command) {
|
||||
case 'listContainers':
|
||||
console.log(`[INFO] Handling 'listContainers' command`);
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
response = { type: 'containers', data: containers };
|
||||
break;
|
||||
|
||||
case 'startContainer':
|
||||
console.log(`[INFO] Handling 'startContainer' command for container: ${parsedData.args.id}`);
|
||||
await docker.getContainer(parsedData.args.id).start();
|
||||
response = { success: true, message: `Container ${parsedData.args.id} started` };
|
||||
break;
|
||||
|
||||
case 'stopContainer':
|
||||
console.log(`[INFO] Handling 'stopContainer' command for container: ${parsedData.args.id}`);
|
||||
await docker.getContainer(parsedData.args.id).stop();
|
||||
response = { success: true, message: `Container ${parsedData.args.id} stopped` };
|
||||
break;
|
||||
|
||||
case 'removeContainer':
|
||||
console.log(`[INFO] Handling 'removeContainer' command for container: ${parsedData.args.id}`);
|
||||
await docker.getContainer(parsedData.args.id).remove({ force: true });
|
||||
response = { success: true, message: `Container ${parsedData.args.id} removed` };
|
||||
break;
|
||||
|
||||
case 'startTerminal':
|
||||
console.log(`[INFO] Starting terminal for container: ${parsedData.args.containerId}`);
|
||||
handleTerminal(parsedData.args.containerId, peer);
|
||||
return; // No response needed for streaming
|
||||
|
||||
default:
|
||||
console.warn(`[WARN] Unknown command: ${parsedData.command}`);
|
||||
response = { error: 'Unknown command' };
|
||||
}
|
||||
|
||||
console.log(`[DEBUG] Sending response to peer: ${JSON.stringify(response)}`);
|
||||
peer.write(JSON.stringify(response));
|
||||
} catch (err) {
|
||||
console.error(`[ERROR] Failed to handle data from peer: ${err.message}`);
|
||||
peer.write(JSON.stringify({ error: err.message }));
|
||||
}
|
||||
});
|
||||
|
||||
peer.on('close', () => {
|
||||
console.log(`[INFO] Peer disconnected`);
|
||||
connectedPeers.delete(peer);
|
||||
});
|
||||
});
|
||||
|
||||
// Stream Docker events to all peers
|
||||
docker.getEvents({}, (err, stream) => {
|
||||
if (err) {
|
||||
console.error(`[ERROR] Failed to get Docker events: ${err.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.on('data', async (chunk) => {
|
||||
try {
|
||||
const event = JSON.parse(chunk.toString());
|
||||
console.log(`[INFO] Docker event received: ${event.status} - ${event.id}`);
|
||||
|
||||
// Get updated container list and broadcast
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
const update = { type: 'containers', data: containers };
|
||||
|
||||
for (const peer of connectedPeers) {
|
||||
peer.write(JSON.stringify(update));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[ERROR] Failed to process Docker event: ${err.message}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async function handleTerminal(containerId, peer) {
|
||||
const container = docker.getContainer(containerId);
|
||||
|
||||
try {
|
||||
const exec = await container.exec({
|
||||
Cmd: ['/bin/sh'],
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
});
|
||||
|
||||
const stream = await exec.start({ hijack: true, stdin: true });
|
||||
|
||||
console.log(`[INFO] Terminal session started for container: ${containerId}`);
|
||||
|
||||
stream.on('data', (chunk) => {
|
||||
console.log(`[DEBUG] Terminal output: ${chunk.toString()}`);
|
||||
peer.write(JSON.stringify({ type: 'terminalOutput', containerId, data: chunk.toString() }));
|
||||
});
|
||||
|
||||
peer.on('data', (input) => {
|
||||
try {
|
||||
const parsed = JSON.parse(input.toString());
|
||||
if (parsed.type === 'terminalInput' && parsed.data) {
|
||||
console.log(`[DEBUG] Terminal input: ${parsed.data}`);
|
||||
stream.write(parsed.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[ERROR] Failed to parse terminal input: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
peer.on('close', () => {
|
||||
console.log(`[INFO] Peer disconnected, ending terminal session for container: ${containerId}`);
|
||||
stream.end();
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`[ERROR] Failed to start terminal for container ${containerId}: ${err.message}`);
|
||||
peer.write(JSON.stringify({ error: `Failed to start terminal: ${err.message}` }));
|
||||
}
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log(`[INFO] Server shutting down`);
|
||||
swarm.destroy();
|
||||
process.exit();
|
||||
});
|
Loading…
Reference in New Issue
Block a user