add docker cli access per connection
This commit is contained in:
parent
9389d41364
commit
3e37359e61
58
app.js
58
app.js
@ -1,6 +1,7 @@
|
|||||||
import Hyperswarm from 'hyperswarm';
|
import Hyperswarm from 'hyperswarm';
|
||||||
import b4a from 'b4a';
|
import b4a from 'b4a';
|
||||||
import { startTerminal, appendTerminalOutput } from './libs/terminal.js';
|
import { startTerminal, appendTerminalOutput } from './libs/terminal.js';
|
||||||
|
import { startDockerTerminal, cleanUpDockerTerminal } from './libs/dockerTerminal.js';
|
||||||
|
|
||||||
// DOM Elements
|
// DOM Elements
|
||||||
const containerList = document.getElementById('container-list');
|
const containerList = document.getElementById('container-list');
|
||||||
@ -32,6 +33,16 @@ function stopStatsInterval() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const dockerTerminalModal = document.getElementById('dockerTerminalModal');
|
||||||
|
|
||||||
|
if (dockerTerminalModal) {
|
||||||
|
dockerTerminalModal.addEventListener('hidden.bs.modal', () => {
|
||||||
|
console.log('[INFO] Modal fully closed. Performing additional cleanup.');
|
||||||
|
cleanUpDockerTerminal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function startStatsInterval() {
|
function startStatsInterval() {
|
||||||
if (statsInterval) {
|
if (statsInterval) {
|
||||||
@ -304,8 +315,6 @@ function handlePeerData(data, topicId, peer) {
|
|||||||
switch (response.type) {
|
switch (response.type) {
|
||||||
case 'stats':
|
case 'stats':
|
||||||
console.log('[INFO] Updating container stats...');
|
console.log('[INFO] Updating container stats...');
|
||||||
|
|
||||||
// Ensure IP is included and passed to updateContainerStats
|
|
||||||
const stats = response.data;
|
const stats = response.data;
|
||||||
stats.ip = stats.ip || 'No IP Assigned'; // Add a fallback for missing IPs
|
stats.ip = stats.ip || 'No IP Assigned'; // Add a fallback for missing IPs
|
||||||
console.log(`[DEBUG] Passing stats to updateContainerStats: ${JSON.stringify(stats, null, 2)}`);
|
console.log(`[DEBUG] Passing stats to updateContainerStats: ${JSON.stringify(stats, null, 2)}`);
|
||||||
@ -352,6 +361,7 @@ function handlePeerData(data, topicId, peer) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add a new connection
|
// Add a new connection
|
||||||
addConnectionForm.addEventListener('submit', (e) => {
|
addConnectionForm.addEventListener('submit', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -394,17 +404,41 @@ function addConnection(topicHex) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
// Add Docker Terminal button event listener
|
// Add Docker Terminal button event listener
|
||||||
connectionItem.querySelector('.docker-terminal-btn').addEventListener('click', (e) => {
|
connectionItem.querySelector('.docker-terminal-btn')?.addEventListener('click', (event) => {
|
||||||
e.stopPropagation();
|
event.stopPropagation();
|
||||||
const connection = connections[topicId];
|
|
||||||
if (connection && connection.peer) {
|
console.log('[DEBUG] Docker terminal button clicked.');
|
||||||
import('./libs/dockerTerminal.js').then(({ startDockerTerminal }) => {
|
|
||||||
startDockerTerminal(topicId, connection.peer);
|
if (!topicId) {
|
||||||
});
|
console.error('[ERROR] Missing topicId. Cannot proceed.');
|
||||||
} else {
|
return;
|
||||||
console.error('[ERROR] No active peer for Docker CLI terminal.');
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
const connection = connections[topicId];
|
||||||
|
console.log(`[DEBUG] Retrieved connection for topicId: ${topicId}`, connection);
|
||||||
|
|
||||||
|
if (connection && connection.peer) {
|
||||||
|
try {
|
||||||
|
console.log(`[DEBUG] Starting Docker terminal for topicId: ${topicId}`);
|
||||||
|
startDockerTerminal(topicId, connection.peer);
|
||||||
|
|
||||||
|
const dockerTerminalModal = document.getElementById('dockerTerminalModal');
|
||||||
|
if (dockerTerminalModal) {
|
||||||
|
const modalInstance = new bootstrap.Modal(dockerTerminalModal);
|
||||||
|
modalInstance.show();
|
||||||
|
console.log('[DEBUG] Docker Terminal modal displayed.');
|
||||||
|
} else {
|
||||||
|
console.error('[ERROR] Docker Terminal modal not found in the DOM.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[ERROR] Failed to start Docker CLI terminal for topicId: ${topicId}`, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn(`[WARNING] No active peer found for topicId: ${topicId}. Unable to start Docker CLI terminal.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
connectionItem.querySelector('span').addEventListener('click', () => switchConnection(topicId));
|
connectionItem.querySelector('span').addEventListener('click', () => switchConnection(topicId));
|
||||||
connectionItem.querySelector('.disconnect-btn').addEventListener('click', (e) => {
|
connectionItem.querySelector('.disconnect-btn').addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
23
index.html
23
index.html
@ -375,6 +375,7 @@
|
|||||||
background-color: #999;
|
background-color: #999;
|
||||||
/* Even lighter color when active */
|
/* Even lighter color when active */
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
@ -515,17 +516,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Docker Terminal Modal -->
|
<!-- Docker Terminal Modal -->
|
||||||
<!-- Docker CLI Terminal Modal -->
|
<div class="modal fade" id="dockerTerminalModal" tabindex="-1" aria-labelledby="docker-terminal-title" aria-hidden="true">
|
||||||
<div id="docker-terminal-modal" class="position-fixed bottom-0 start-0 w-100 max-height-90 bg-dark text-white d-flex flex-column" style="display: none; z-index: 1000;">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="header d-flex justify-content-between align-items-center bg-secondary p-2">
|
<div class="modal-content bg-dark text-white">
|
||||||
<span id="docker-terminal-title" class="fw-bold">Docker CLI Terminal</span>
|
<div class="modal-header">
|
||||||
<button id="docker-kill-terminal-btn" class="btn btn-sm btn-danger">
|
<h5 id="docker-terminal-title" class="modal-title">Docker CLI Terminal</h5>
|
||||||
<i class="fas fa-times-circle"></i>
|
<button id="docker-kill-terminal-btn" type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</button>
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="docker-terminal-container"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="docker-terminal-container" class="flex-grow-1 overflow-hidden" style="background-color: black;"></div>
|
|
||||||
<div id="docker-terminal-resize-handle" class="bg-secondary" style="height: 10px; cursor: ns-resize;"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Alert Container -->
|
<!-- Alert Container -->
|
||||||
|
@ -10,6 +10,11 @@ const dockerKillTerminalBtn = document.getElementById('docker-kill-terminal-btn'
|
|||||||
// Terminal variables
|
// Terminal variables
|
||||||
let dockerTerminalSession = null;
|
let dockerTerminalSession = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and start the Docker CLI terminal.
|
||||||
|
* @param {string} connectionId - Unique ID for the connection.
|
||||||
|
* @param {Object} peer - Active peer object for communication.
|
||||||
|
*/
|
||||||
function startDockerTerminal(connectionId, peer) {
|
function startDockerTerminal(connectionId, peer) {
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
console.error('[ERROR] No active peer for Docker CLI terminal.');
|
console.error('[ERROR] No active peer for Docker CLI terminal.');
|
||||||
@ -21,6 +26,18 @@ function startDockerTerminal(connectionId, peer) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify DOM elements
|
||||||
|
const dockerTerminalContainer = document.getElementById('docker-terminal-container');
|
||||||
|
const dockerTerminalTitle = document.getElementById('docker-terminal-title');
|
||||||
|
const dockerTerminalModal = document.getElementById('dockerTerminalModal');
|
||||||
|
const dockerKillTerminalBtn = document.getElementById('docker-kill-terminal-btn');
|
||||||
|
|
||||||
|
if (!dockerTerminalContainer || !dockerTerminalTitle || !dockerTerminalModal || !dockerKillTerminalBtn) {
|
||||||
|
console.error('[ERROR] Missing required DOM elements for Docker CLI terminal.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the xterm.js terminal
|
||||||
const xterm = new Terminal({
|
const xterm = new Terminal({
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
theme: { background: '#000000', foreground: '#ffffff' },
|
theme: { background: '#000000', foreground: '#ffffff' },
|
||||||
@ -28,84 +45,168 @@ function startDockerTerminal(connectionId, peer) {
|
|||||||
const fitAddon = new FitAddon();
|
const fitAddon = new FitAddon();
|
||||||
xterm.loadAddon(fitAddon);
|
xterm.loadAddon(fitAddon);
|
||||||
|
|
||||||
|
// Prepare the terminal container
|
||||||
dockerTerminalContainer.innerHTML = ''; // Clear previous content
|
dockerTerminalContainer.innerHTML = ''; // Clear previous content
|
||||||
xterm.open(dockerTerminalContainer);
|
xterm.open(dockerTerminalContainer);
|
||||||
fitAddon.fit();
|
fitAddon.fit();
|
||||||
|
|
||||||
dockerTerminalSession = { xterm, fitAddon, connectionId, peer };
|
dockerTerminalSession = { xterm, fitAddon, connectionId, peer };
|
||||||
|
|
||||||
let inputBuffer = ''; // Buffer for user input
|
// Buffer to accumulate user input
|
||||||
|
let inputBuffer = '';
|
||||||
|
|
||||||
|
// Handle terminal input
|
||||||
xterm.onData((input) => {
|
xterm.onData((input) => {
|
||||||
if (input === '\r') { // User pressed Enter
|
if (input === '\r') {
|
||||||
const sanitizedInput = sanitizeDockerCommand(inputBuffer.trim());
|
// User pressed Enter
|
||||||
if (sanitizedInput) {
|
const fullCommand = prependDockerCommand(inputBuffer.trim());
|
||||||
console.log(`[DEBUG] Sending Docker CLI command: ${sanitizedInput}`);
|
if (fullCommand) {
|
||||||
|
console.log(`[DEBUG] Sending Docker CLI command: ${fullCommand}`);
|
||||||
peer.write(
|
peer.write(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: 'dockerCommand',
|
command: 'dockerCommand',
|
||||||
connectionId,
|
connectionId,
|
||||||
data: sanitizedInput,
|
data: fullCommand,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
xterm.write('\r\n'); // Move to the next line in the terminal
|
xterm.write('\r\n'); // Move to the next line
|
||||||
} else {
|
} else {
|
||||||
xterm.write('\r\n[ERROR] Invalid command. Only Docker CLI commands are allowed.\r\n');
|
xterm.write('\r\n[ERROR] Invalid command. Please check your input.\r\n');
|
||||||
}
|
}
|
||||||
inputBuffer = ''; // Clear the buffer after processing
|
inputBuffer = ''; // Clear the buffer after processing
|
||||||
} else if (input === '\u007F') { // Handle backspace
|
} else if (input === '\u007F') {
|
||||||
|
// Handle backspace
|
||||||
if (inputBuffer.length > 0) {
|
if (inputBuffer.length > 0) {
|
||||||
inputBuffer = inputBuffer.slice(0, -1); // Remove the last character from the buffer
|
inputBuffer = inputBuffer.slice(0, -1); // Remove last character
|
||||||
xterm.write('\b \b'); // Erase the character from the terminal display
|
xterm.write('\b \b'); // Erase character from display
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inputBuffer += input; // Append input to the buffer
|
// Append input to buffer and display it
|
||||||
xterm.write(input); // Display input in the terminal
|
inputBuffer += input;
|
||||||
|
xterm.write(input);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle peer data
|
||||||
peer.on('data', (data) => {
|
peer.on('data', (data) => {
|
||||||
|
console.log('[DEBUG] Received data event');
|
||||||
try {
|
try {
|
||||||
const response = JSON.parse(data.toString());
|
const response = JSON.parse(data.toString());
|
||||||
if (response.type === 'dockerOutput' && response.connectionId === connectionId) {
|
if (response.connectionId === connectionId) {
|
||||||
xterm.write(`${response.data}\r\n`);
|
const decodedData = decodeResponseData(response.data, response.encoding);
|
||||||
|
|
||||||
|
if (response.type === 'dockerOutput') {
|
||||||
|
xterm.write(`${decodedData.trim()}\r\n`);
|
||||||
|
} else if (response.type === 'terminalErrorOutput') {
|
||||||
|
xterm.write(`\r\n[ERROR] ${decodedData.trim()}\r\n`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[ERROR] Failed to parse response from peer: ${error.message}`);
|
console.error(`[ERROR] Failed to parse response from peer: ${error.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update the terminal modal and title
|
||||||
dockerTerminalTitle.textContent = `Docker CLI Terminal: ${connectionId}`;
|
dockerTerminalTitle.textContent = `Docker CLI Terminal: ${connectionId}`;
|
||||||
dockerTerminalModal.style.display = 'flex';
|
const modalInstance = new bootstrap.Modal(dockerTerminalModal);
|
||||||
|
modalInstance.show();
|
||||||
|
|
||||||
|
// Attach event listener for Kill Terminal button
|
||||||
dockerKillTerminalBtn.onclick = () => {
|
dockerKillTerminalBtn.onclick = () => {
|
||||||
cleanUpDockerTerminal();
|
cleanUpDockerTerminal();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize input to ensure only Docker CLI commands are allowed
|
/**
|
||||||
function sanitizeDockerCommand(command) {
|
* Prepend 'docker' to the command if it's missing.
|
||||||
// Allow commands starting with "docker" and disallow dangerous operators
|
* @param {string} command - Command string entered by the user.
|
||||||
const isValid = /^docker(\s+[\w.-]+)*$/i.test(command);
|
* @returns {string|null} - Full Docker command or null if invalid.
|
||||||
return isValid ? command : null;
|
*/
|
||||||
|
function prependDockerCommand(command) {
|
||||||
|
// Disallow dangerous operators
|
||||||
|
if (/[\|;&`]/.test(command)) {
|
||||||
|
console.warn('[WARN] Invalid characters detected in command.');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up Docker CLI terminal session
|
// Prepend 'docker' if not already present
|
||||||
function cleanUpDockerTerminal() {
|
if (!command.startsWith('docker ')) {
|
||||||
if (dockerTerminalSession) {
|
return `docker ${command}`;
|
||||||
dockerTerminalSession.xterm.dispose();
|
}
|
||||||
dockerTerminalSession = null;
|
return command;
|
||||||
dockerTerminalContainer.innerHTML = ''; // Clear terminal content
|
}
|
||||||
dockerTerminalModal.style.display = 'none'; // Hide the modal
|
|
||||||
dockerTerminalModal.classList.add('hidden');
|
/**
|
||||||
console.log('[INFO] Docker CLI terminal session cleaned up.');
|
* Decode response data from Base64 or return as-is if not encoded.
|
||||||
|
* @param {string} data - Response data from the server.
|
||||||
|
* @param {string} encoding - Encoding type (e.g., 'base64').
|
||||||
|
* @returns {string} - Decoded or plain data.
|
||||||
|
*/
|
||||||
|
function decodeResponseData(data, encoding) {
|
||||||
|
if (encoding === 'base64') {
|
||||||
|
try {
|
||||||
|
return atob(data); // Decode Base64 data
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[ERROR] Failed to decode Base64 data: ${error.message}`);
|
||||||
|
return '[ERROR] Command failed.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return data; // Return plain data if not encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up the Docker CLI terminal session.
|
||||||
|
*/
|
||||||
|
function cleanUpDockerTerminal() {
|
||||||
|
console.log('[INFO] Cleaning up Docker Terminal...');
|
||||||
|
|
||||||
// Handle Kill Terminal button
|
// Retrieve the required DOM elements
|
||||||
|
const dockerTerminalContainer = document.getElementById('docker-terminal-container');
|
||||||
|
const dockerTerminalModal = document.getElementById('dockerTerminalModal');
|
||||||
|
|
||||||
|
if (!dockerTerminalContainer || !dockerTerminalModal) {
|
||||||
|
console.error('[ERROR] Required DOM elements not found for cleaning up the Docker Terminal.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispose of the terminal session if it exists
|
||||||
|
if (dockerTerminalSession) {
|
||||||
|
if (dockerTerminalSession.xterm) {
|
||||||
|
dockerTerminalSession.xterm.dispose();
|
||||||
|
}
|
||||||
|
dockerTerminalSession = null; // Reset the session object
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the terminal content
|
||||||
|
dockerTerminalContainer.innerHTML = '';
|
||||||
|
|
||||||
|
// Use Bootstrap API to hide the modal
|
||||||
|
const modalInstance = bootstrap.Modal.getInstance(dockerTerminalModal);
|
||||||
|
if (modalInstance) {
|
||||||
|
modalInstance.hide();
|
||||||
|
} else {
|
||||||
|
console.warn('[WARNING] Modal instance not found. Falling back to manual close.');
|
||||||
|
dockerTerminalModal.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure lingering backdrops are removed
|
||||||
|
const backdrop = document.querySelector('.modal-backdrop');
|
||||||
|
if (backdrop) {
|
||||||
|
backdrop.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the body's scroll behavior
|
||||||
|
document.body.classList.remove('modal-open');
|
||||||
|
document.body.style.paddingRight = '';
|
||||||
|
|
||||||
|
console.log('[INFO] Docker CLI terminal session cleanup completed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Attach event listener for Kill Terminal button (redundant safety check)
|
||||||
dockerKillTerminalBtn.onclick = () => {
|
dockerKillTerminalBtn.onclick = () => {
|
||||||
cleanUpDockerTerminal();
|
cleanUpDockerTerminal();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export functions
|
// Export functions
|
||||||
export { startDockerTerminal, cleanUpDockerTerminal };
|
export { startDockerTerminal, cleanUpDockerTerminal, dockerTerminalSession };
|
||||||
|
116
server/server.js
116
server/server.js
@ -7,6 +7,7 @@ import { PassThrough } from 'stream';
|
|||||||
import os from "os";
|
import os from "os";
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
|
||||||
// Load environment variables from .env file
|
// Load environment variables from .env file
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@ -98,6 +99,68 @@ swarm.on('connection', (peer) => {
|
|||||||
const config = await container.inspect();
|
const config = await container.inspect();
|
||||||
response = { type: 'containerConfig', data: config };
|
response = { type: 'containerConfig', data: config };
|
||||||
break;
|
break;
|
||||||
|
case 'dockerCommand':
|
||||||
|
console.log(`[INFO] Handling 'dockerCommand' with data: ${parsedData.data}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const command = parsedData.data.split(' '); // Split the command into executable and args
|
||||||
|
const executable = command[0];
|
||||||
|
const args = command.slice(1);
|
||||||
|
|
||||||
|
const childProcess = spawn(executable, args);
|
||||||
|
|
||||||
|
let response = {
|
||||||
|
type: 'dockerOutput',
|
||||||
|
connectionId: parsedData.connectionId,
|
||||||
|
data: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stream stdout to the peer
|
||||||
|
childProcess.stdout.on('data', (data) => {
|
||||||
|
console.log(`[DEBUG] Command stdout: ${data.toString()}`);
|
||||||
|
peer.write(
|
||||||
|
JSON.stringify({
|
||||||
|
...response,
|
||||||
|
data: data.toString('base64'),
|
||||||
|
encoding: 'base64',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stream stderr to the peer
|
||||||
|
childProcess.stderr.on('data', (data) => {
|
||||||
|
console.error(`[ERROR] Command stderr: ${data.toString()}`);
|
||||||
|
peer.write(
|
||||||
|
JSON.stringify({
|
||||||
|
...response,
|
||||||
|
data: `[ERROR] ${data.toString('base64')}`,
|
||||||
|
encoding: 'base64',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle command exit
|
||||||
|
childProcess.on('close', (code) => {
|
||||||
|
const exitMessage = `[INFO] Command exited with code ${code}`;
|
||||||
|
console.log(exitMessage);
|
||||||
|
peer.write(
|
||||||
|
JSON.stringify({
|
||||||
|
...response,
|
||||||
|
data: exitMessage,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[ERROR] Command execution failed: ${error.message}`);
|
||||||
|
peer.write(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'dockerOutput',
|
||||||
|
connectionId: parsedData.connectionId,
|
||||||
|
data: `[ERROR] Failed to execute command: ${error.message}`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'duplicateContainer':
|
case 'duplicateContainer':
|
||||||
console.log('[INFO] Handling \'duplicateContainer\' command');
|
console.log('[INFO] Handling \'duplicateContainer\' command');
|
||||||
@ -107,57 +170,6 @@ swarm.on('connection', (peer) => {
|
|||||||
|
|
||||||
await duplicateContainer(name, image, hostname, netmode, cpu, memoryInMB, dupConfig, peer);
|
await duplicateContainer(name, image, hostname, netmode, cpu, memoryInMB, dupConfig, peer);
|
||||||
return; // Response is handled within the duplicateContainer function
|
return; // Response is handled within the duplicateContainer function
|
||||||
case 'dockerCommand':
|
|
||||||
console.log(`[INFO] Executing Docker CLI command: ${parsedData.data}`);
|
|
||||||
try {
|
|
||||||
const exec = spawn('sh', ['-c', parsedData.data]); // Use spawn to run the Docker command
|
|
||||||
|
|
||||||
// Handle stdout (command output)
|
|
||||||
exec.stdout.on('data', (output) => {
|
|
||||||
console.log(`[DEBUG] Command output: ${output.toString()}`);
|
|
||||||
peer.write(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'dockerOutput',
|
|
||||||
connectionId: parsedData.connectionId,
|
|
||||||
data: output.toString(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle stderr (errors)
|
|
||||||
exec.stderr.on('data', (error) => {
|
|
||||||
console.error(`[ERROR] Command error output: ${error.toString()}`);
|
|
||||||
peer.write(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'dockerOutput',
|
|
||||||
connectionId: parsedData.connectionId,
|
|
||||||
data: `[ERROR] ${error.toString()}`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle command completion
|
|
||||||
exec.on('close', (code) => {
|
|
||||||
console.log(`[INFO] Command exited with code: ${code}`);
|
|
||||||
peer.write(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'dockerOutput',
|
|
||||||
connectionId: parsedData.connectionId,
|
|
||||||
data: `[INFO] Command exited with code ${code}\n`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`[ERROR] Failed to execute command: ${error.message}`);
|
|
||||||
peer.write(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'dockerOutput',
|
|
||||||
connectionId: parsedData.connectionId,
|
|
||||||
data: `[ERROR] Failed to execute command: ${error.message}`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'startContainer':
|
case 'startContainer':
|
||||||
console.log(`[INFO] Handling 'startContainer' command for container: ${parsedData.args.id}`);
|
console.log(`[INFO] Handling 'startContainer' command for container: ${parsedData.args.id}`);
|
||||||
await docker.getContainer(parsedData.args.id).start();
|
await docker.getContainer(parsedData.args.id).start();
|
||||||
@ -579,4 +591,4 @@ process.on('SIGINT', () => {
|
|||||||
console.log('[INFO] Server shutting down');
|
console.log('[INFO] Server shutting down');
|
||||||
swarm.destroy();
|
swarm.destroy();
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user