server/imports/core/mongodb/shell.js
import { Meteor } from 'meteor/meteor';
import Database from '/server/imports/modules/database';
import Logger from '/server/imports/modules/logger';
import Error from '/server/imports/modules/error_handler';
import Connection from '/server/imports/core/connection/index';
import MongoDBHelper from './helper';
const spawn = require('cross-spawn');
const MongoDBShell = function () {
this.spawnedShellsBySessionId = {};
};
const setEventsToShell = function (connectionId, sessionId) {
Logger.info({ message: 'shell-event-bind', metadataToLog: { connectionId, sessionId } });
this.spawnedShellsBySessionId[sessionId].on('error', Meteor.bindEnvironment((error) => {
Logger.error({ message: 'shell-event-bind', metadataToLog: { error, sessionId } });
this.spawnedShellsBySessionId[sessionId] = null;
if (error) {
Database.create({
type: Database.types.ShellCommands,
document: {
date: Date.now(),
sessionId,
connectionId,
message: `unexpected error ${error.message}`,
}
});
}
}));
this.spawnedShellsBySessionId[sessionId].stdout.on('data', Meteor.bindEnvironment((data) => {
if (data && data.toString()) {
Database.create({
type: Database.types.ShellCommands,
document: {
date: Date.now(),
sessionId,
connectionId,
message: data.toString(),
}
});
}
}));
this.spawnedShellsBySessionId[sessionId].stderr.on('data', Meteor.bindEnvironment((data) => {
if (data && data.toString()) {
Database.create({
type: Database.types.ShellCommands,
document: {
date: Date.now(),
sessionId,
connectionId,
message: data.toString()
}
});
}
}));
this.spawnedShellsBySessionId[sessionId].on('close', Meteor.bindEnvironment((code) => {
// show ended message in codemirror
Database.create({
type: Database.types.ShellCommands,
document: {
date: Date.now(),
connectionId,
sessionId,
message: `shell closed ${code.toString()}`
}
});
this.spawnedShellsBySessionId[sessionId] = null;
Meteor.setTimeout(() => {
// remove all for further
Database.remove({ type: Database.types.ShellCommands, selector: { sessionId } });
}, 500);
}));
};
MongoDBShell.prototype = {
connectToShell({ connectionId, username, password, sessionId }) {
const connection = Database.readOne({ type: Database.types.Connections, query: { _id: connectionId } });
try {
if (!this.spawnedShellsBySessionId[sessionId]) {
const connectionUrl = Connection.getConnectionUrl(connection, username, password, true);
const mongoPath = MongoDBHelper.getProperBinary('mongo');
Logger.debug({ message: 'shell', metadataToLog: { mongoPath, connectionUrl, sessionId } });
this.spawnedShellsBySessionId[sessionId] = spawn(mongoPath, [connectionUrl]);
setEventsToShell.call(this, connectionId, sessionId);
}
} catch (ex) {
this.spawnedShellsBySessionId[sessionId] = null;
Error.create({ type: Error.types.ShellError, externalError: ex, metadataToLog: { connectionId, username, sessionId } });
}
if (this.spawnedShellsBySessionId[sessionId]) {
Logger.info({ message: 'shell', metadataToLog: { command: `use ${connection.databaseName}`, sessionId } });
this.spawnedShellsBySessionId[sessionId].stdin.write(`use ${connection.databaseName}\n`);
return `use ${connection.databaseName}`;
}
Error.create({ type: Error.types.ShellError, message: 'spawn-failed' });
},
clearShell({ sessionId }) {
Logger.info({ message: 'clear-shell', metadataToLog: sessionId });
Database.remove({ type: Database.types.ShellCommands, selector: { sessionId } });
},
executeShellCommand({ command, connectionId, username, password, sessionId }) {
Logger.info({ message: 'shell-command-execution', metadataToLog: { sessionId, command, connectionId } });
if (!this.spawnedShellsBySessionId[sessionId]) this.connectToShell({ connectionId, username, password, sessionId });
if (this.spawnedShellsBySessionId[sessionId]) this.spawnedShellsBySessionId[sessionId].stdin.write(`${command}\n`);
}
};
export default new MongoDBShell();