|
|
|
@ -3,7 +3,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const winston = require('winston');
|
|
|
|
|
const async = require('async');
|
|
|
|
|
const nconf = require('nconf');
|
|
|
|
|
const session = require('express-session');
|
|
|
|
|
const semver = require('semver');
|
|
|
|
@ -61,63 +60,39 @@ mongoModule.questions = [
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
mongoModule.init = function (callback) {
|
|
|
|
|
callback = callback || function () { };
|
|
|
|
|
|
|
|
|
|
connection.connect(nconf.get('mongo'), function (err, _client) {
|
|
|
|
|
if (err) {
|
|
|
|
|
winston.error('NodeBB could not connect to your Mongo database. Mongo returned the following error', err);
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
client = _client;
|
|
|
|
|
mongoModule.client = client.db();
|
|
|
|
|
callback();
|
|
|
|
|
});
|
|
|
|
|
mongoModule.init = async function () {
|
|
|
|
|
client = await connection.connect(nconf.get('mongo'));
|
|
|
|
|
mongoModule.client = client.db();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.createSessionStore = function (options, callback) {
|
|
|
|
|
connection.connect(options, function (err, client) {
|
|
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
const meta = require('../meta');
|
|
|
|
|
const sessionStore = require('connect-mongo')(session);
|
|
|
|
|
const store = new sessionStore({
|
|
|
|
|
client: client,
|
|
|
|
|
ttl: meta.getSessionTTLSeconds(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
callback(null, store);
|
|
|
|
|
mongoModule.createSessionStore = async function (options) {
|
|
|
|
|
const client = await connection.connect(options);
|
|
|
|
|
const meta = require('../meta');
|
|
|
|
|
const sessionStore = require('connect-mongo')(session);
|
|
|
|
|
const store = new sessionStore({
|
|
|
|
|
client: client,
|
|
|
|
|
ttl: meta.getSessionTTLSeconds(),
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.createIndices = function (callback) {
|
|
|
|
|
function createIndex(collection, index, options, callback) {
|
|
|
|
|
mongoModule.client.collection(collection).createIndex(index, options, callback);
|
|
|
|
|
}
|
|
|
|
|
return store;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.createIndices = async function () {
|
|
|
|
|
if (!mongoModule.client) {
|
|
|
|
|
winston.warn('[database/createIndices] database not initialized');
|
|
|
|
|
return callback();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
winston.info('[database] Checking database indices.');
|
|
|
|
|
async.series([
|
|
|
|
|
async.apply(createIndex, 'objects', { _key: 1, score: -1 }, { background: true }),
|
|
|
|
|
async.apply(createIndex, 'objects', { _key: 1, value: -1 }, { background: true, unique: true, sparse: true }),
|
|
|
|
|
async.apply(createIndex, 'objects', { expireAt: 1 }, { expireAfterSeconds: 0, background: true }),
|
|
|
|
|
], function (err) {
|
|
|
|
|
if (err) {
|
|
|
|
|
winston.error('Error creating index', err);
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
winston.info('[database] Checking database indices done!');
|
|
|
|
|
callback();
|
|
|
|
|
});
|
|
|
|
|
const collection = mongoModule.client.collection('objects');
|
|
|
|
|
await collection.createIndex({ _key: 1, score: -1 }, { background: true });
|
|
|
|
|
await collection.createIndex({ _key: 1, value: -1 }, { background: true, unique: true, sparse: true });
|
|
|
|
|
await collection.createIndex({ expireAt: 1 }, { expireAfterSeconds: 0, background: true });
|
|
|
|
|
winston.info('[database] Checking database indices done!');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.checkCompatibility = function (callback) {
|
|
|
|
|
var mongoPkg = require('mongodb/package.json');
|
|
|
|
|
const mongoPkg = require('mongodb/package.json');
|
|
|
|
|
mongoModule.checkCompatibilityVersion(mongoPkg.version, callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -129,97 +104,70 @@ mongoModule.checkCompatibilityVersion = function (version, callback) {
|
|
|
|
|
callback();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.info = function (db, callback) {
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function (next) {
|
|
|
|
|
if (db) {
|
|
|
|
|
return setImmediate(next, null, db);
|
|
|
|
|
}
|
|
|
|
|
connection.connect(nconf.get('mongo'), function (err, client) {
|
|
|
|
|
next(err, client ? client.db() : undefined);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
function (db, next) {
|
|
|
|
|
mongoModule.client = mongoModule.client || db;
|
|
|
|
|
|
|
|
|
|
async.parallel({
|
|
|
|
|
serverStatus: function (next) {
|
|
|
|
|
db.command({ serverStatus: 1 }, next);
|
|
|
|
|
},
|
|
|
|
|
stats: function (next) {
|
|
|
|
|
db.command({ dbStats: 1 }, next);
|
|
|
|
|
},
|
|
|
|
|
listCollections: function (next) {
|
|
|
|
|
getCollectionStats(db, next);
|
|
|
|
|
},
|
|
|
|
|
}, next);
|
|
|
|
|
},
|
|
|
|
|
function (results, next) {
|
|
|
|
|
var stats = results.stats || {};
|
|
|
|
|
results.serverStatus = results.serverStatus || {};
|
|
|
|
|
var scale = 1024 * 1024 * 1024;
|
|
|
|
|
|
|
|
|
|
results.listCollections = results.listCollections.map(function (collectionInfo) {
|
|
|
|
|
return {
|
|
|
|
|
name: collectionInfo.ns,
|
|
|
|
|
count: collectionInfo.count,
|
|
|
|
|
size: collectionInfo.size,
|
|
|
|
|
avgObjSize: collectionInfo.avgObjSize,
|
|
|
|
|
storageSize: collectionInfo.storageSize,
|
|
|
|
|
totalIndexSize: collectionInfo.totalIndexSize,
|
|
|
|
|
indexSizes: collectionInfo.indexSizes,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stats.mem = results.serverStatus.mem || {};
|
|
|
|
|
stats.mem.resident = (stats.mem.resident / 1024).toFixed(3);
|
|
|
|
|
stats.mem.virtual = (stats.mem.virtual / 1024).toFixed(3);
|
|
|
|
|
stats.mem.mapped = (stats.mem.mapped / 1024).toFixed(3);
|
|
|
|
|
stats.collectionData = results.listCollections;
|
|
|
|
|
stats.network = results.serverStatus.network || {};
|
|
|
|
|
stats.network.bytesIn = (stats.network.bytesIn / scale).toFixed(3);
|
|
|
|
|
stats.network.bytesOut = (stats.network.bytesOut / scale).toFixed(3);
|
|
|
|
|
stats.network.numRequests = utils.addCommas(stats.network.numRequests);
|
|
|
|
|
stats.raw = JSON.stringify(stats, null, 4);
|
|
|
|
|
|
|
|
|
|
stats.avgObjSize = stats.avgObjSize.toFixed(2);
|
|
|
|
|
stats.dataSize = (stats.dataSize / scale).toFixed(3);
|
|
|
|
|
stats.storageSize = (stats.storageSize / scale).toFixed(3);
|
|
|
|
|
stats.fileSize = stats.fileSize ? (stats.fileSize / scale).toFixed(3) : 0;
|
|
|
|
|
stats.indexSize = (stats.indexSize / scale).toFixed(3);
|
|
|
|
|
stats.storageEngine = results.serverStatus.storageEngine ? results.serverStatus.storageEngine.name : 'mmapv1';
|
|
|
|
|
stats.host = results.serverStatus.host;
|
|
|
|
|
stats.version = results.serverStatus.version;
|
|
|
|
|
stats.uptime = results.serverStatus.uptime;
|
|
|
|
|
stats.mongo = true;
|
|
|
|
|
|
|
|
|
|
next(null, stats);
|
|
|
|
|
},
|
|
|
|
|
], callback);
|
|
|
|
|
mongoModule.info = async function (db) {
|
|
|
|
|
if (!db) {
|
|
|
|
|
const client = await connection.connect(nconf.get('mongo'));
|
|
|
|
|
db = client.db();
|
|
|
|
|
}
|
|
|
|
|
mongoModule.client = mongoModule.client || db;
|
|
|
|
|
|
|
|
|
|
let [serverStatus, stats, listCollections] = await Promise.all([
|
|
|
|
|
db.command({ serverStatus: 1 }),
|
|
|
|
|
db.command({ dbStats: 1 }),
|
|
|
|
|
getCollectionStats(db),
|
|
|
|
|
]);
|
|
|
|
|
stats = stats || {};
|
|
|
|
|
serverStatus = serverStatus || {};
|
|
|
|
|
const scale = 1024 * 1024 * 1024;
|
|
|
|
|
|
|
|
|
|
listCollections = listCollections.map(function (collectionInfo) {
|
|
|
|
|
return {
|
|
|
|
|
name: collectionInfo.ns,
|
|
|
|
|
count: collectionInfo.count,
|
|
|
|
|
size: collectionInfo.size,
|
|
|
|
|
avgObjSize: collectionInfo.avgObjSize,
|
|
|
|
|
storageSize: collectionInfo.storageSize,
|
|
|
|
|
totalIndexSize: collectionInfo.totalIndexSize,
|
|
|
|
|
indexSizes: collectionInfo.indexSizes,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stats.mem = serverStatus.mem || {};
|
|
|
|
|
stats.mem.resident = (stats.mem.resident / 1024).toFixed(3);
|
|
|
|
|
stats.mem.virtual = (stats.mem.virtual / 1024).toFixed(3);
|
|
|
|
|
stats.mem.mapped = (stats.mem.mapped / 1024).toFixed(3);
|
|
|
|
|
stats.collectionData = listCollections;
|
|
|
|
|
stats.network = serverStatus.network || {};
|
|
|
|
|
stats.network.bytesIn = (stats.network.bytesIn / scale).toFixed(3);
|
|
|
|
|
stats.network.bytesOut = (stats.network.bytesOut / scale).toFixed(3);
|
|
|
|
|
stats.network.numRequests = utils.addCommas(stats.network.numRequests);
|
|
|
|
|
stats.raw = JSON.stringify(stats, null, 4);
|
|
|
|
|
|
|
|
|
|
stats.avgObjSize = stats.avgObjSize.toFixed(2);
|
|
|
|
|
stats.dataSize = (stats.dataSize / scale).toFixed(3);
|
|
|
|
|
stats.storageSize = (stats.storageSize / scale).toFixed(3);
|
|
|
|
|
stats.fileSize = stats.fileSize ? (stats.fileSize / scale).toFixed(3) : 0;
|
|
|
|
|
stats.indexSize = (stats.indexSize / scale).toFixed(3);
|
|
|
|
|
stats.storageEngine = serverStatus.storageEngine ? serverStatus.storageEngine.name : 'mmapv1';
|
|
|
|
|
stats.host = serverStatus.host;
|
|
|
|
|
stats.version = serverStatus.version;
|
|
|
|
|
stats.uptime = serverStatus.uptime;
|
|
|
|
|
stats.mongo = true;
|
|
|
|
|
return stats;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function getCollectionStats(db, callback) {
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function (next) {
|
|
|
|
|
db.listCollections().toArray(next);
|
|
|
|
|
},
|
|
|
|
|
function (items, next) {
|
|
|
|
|
async.map(items, function (collection, next) {
|
|
|
|
|
db.collection(collection.name).stats(next);
|
|
|
|
|
}, next);
|
|
|
|
|
},
|
|
|
|
|
], callback);
|
|
|
|
|
async function getCollectionStats(db) {
|
|
|
|
|
const items = await db.listCollections().toArray();
|
|
|
|
|
return await Promise.all(items.map(collection => db.collection(collection.name).stats));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mongoModule.close = function (callback) {
|
|
|
|
|
callback = callback || function () {};
|
|
|
|
|
client.close(function (err) {
|
|
|
|
|
callback(err);
|
|
|
|
|
});
|
|
|
|
|
client.close(err => callback(err));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mongoModule.socketAdapter = function () {
|
|
|
|
|
var mongoAdapter = require('socket.io-adapter-mongo');
|
|
|
|
|
const mongoAdapter = require('socket.io-adapter-mongo');
|
|
|
|
|
return mongoAdapter(connection.getConnectionString());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|