You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.9 KiB
JavaScript
188 lines
5.9 KiB
JavaScript
|
|
'use strict';
|
|
|
|
|
|
const winston = require('winston');
|
|
const nconf = require('nconf');
|
|
const semver = require('semver');
|
|
const prompt = require('prompt');
|
|
const utils = require('../utils');
|
|
|
|
let client;
|
|
|
|
const connection = require('./mongo/connection');
|
|
|
|
const mongoModule = module.exports;
|
|
|
|
function isUriNotSpecified() {
|
|
return !prompt.history('mongo:uri').value;
|
|
}
|
|
|
|
mongoModule.questions = [
|
|
{
|
|
name: 'mongo:uri',
|
|
description: 'MongoDB connection URI: (leave blank if you wish to specify host, port, username/password and database individually)\nFormat: mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]',
|
|
default: nconf.get('mongo:uri') || '',
|
|
hideOnWebInstall: true,
|
|
},
|
|
{
|
|
name: 'mongo:host',
|
|
description: 'Host IP or address of your MongoDB instance',
|
|
default: nconf.get('mongo:host') || '127.0.0.1',
|
|
ask: isUriNotSpecified,
|
|
},
|
|
{
|
|
name: 'mongo:port',
|
|
description: 'Host port of your MongoDB instance',
|
|
default: nconf.get('mongo:port') || 27017,
|
|
ask: isUriNotSpecified,
|
|
},
|
|
{
|
|
name: 'mongo:username',
|
|
description: 'MongoDB username',
|
|
default: nconf.get('mongo:username') || '',
|
|
ask: isUriNotSpecified,
|
|
},
|
|
{
|
|
name: 'mongo:password',
|
|
description: 'Password of your MongoDB database',
|
|
default: nconf.get('mongo:password') || '',
|
|
hidden: true,
|
|
ask: isUriNotSpecified,
|
|
before: function (value) { value = value || nconf.get('mongo:password') || ''; return value; },
|
|
},
|
|
{
|
|
name: 'mongo:database',
|
|
description: 'MongoDB database name',
|
|
default: nconf.get('mongo:database') || 'nodebb',
|
|
ask: isUriNotSpecified,
|
|
},
|
|
];
|
|
|
|
mongoModule.init = async function () {
|
|
client = await connection.connect(nconf.get('mongo'));
|
|
mongoModule.client = client.db();
|
|
};
|
|
|
|
mongoModule.createSessionStore = async function (options) {
|
|
const MongoStore = require('connect-mongo');
|
|
const meta = require('../meta');
|
|
|
|
const store = MongoStore.create({
|
|
clientPromise: connection.connect(options),
|
|
ttl: meta.getSessionTTLSeconds(),
|
|
});
|
|
|
|
return store;
|
|
};
|
|
|
|
mongoModule.createIndices = async function () {
|
|
if (!mongoModule.client) {
|
|
winston.warn('[database/createIndices] database not initialized');
|
|
return;
|
|
}
|
|
|
|
winston.info('[database] Checking database indices.');
|
|
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) {
|
|
const mongoPkg = require('mongodb/package.json');
|
|
mongoModule.checkCompatibilityVersion(mongoPkg.version, callback);
|
|
};
|
|
|
|
mongoModule.checkCompatibilityVersion = function (version, callback) {
|
|
if (semver.lt(version, '2.0.0')) {
|
|
return callback(new Error('The `mongodb` package is out-of-date, please run `./nodebb setup` again.'));
|
|
}
|
|
|
|
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 serverStatusError = '';
|
|
|
|
async function getServerStatus() {
|
|
try {
|
|
return await db.command({ serverStatus: 1 });
|
|
} catch (err) {
|
|
serverStatusError = err.message;
|
|
// Override mongo error with more human-readable error
|
|
if (err.name === 'MongoError' && err.codeName === 'Unauthorized') {
|
|
serverStatusError = '[[admin/advanced/database:mongo.unauthorized]]';
|
|
}
|
|
winston.error(err.stack);
|
|
}
|
|
}
|
|
|
|
let [serverStatus, stats, listCollections] = await Promise.all([
|
|
getServerStatus(),
|
|
db.command({ dbStats: 1 }),
|
|
getCollectionStats(db),
|
|
]);
|
|
stats = stats || {};
|
|
serverStatus = serverStatus || {};
|
|
stats.serverStatusError = serverStatusError;
|
|
const scale = 1024 * 1024 * 1024;
|
|
|
|
listCollections = listCollections.map(collectionInfo => ({
|
|
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 || { resident: 0, virtual: 0, mapped: 0 };
|
|
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 || { bytesIn: 0, bytesOut: 0, numRequests: 0 };
|
|
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;
|
|
};
|
|
|
|
async function getCollectionStats(db) {
|
|
const items = await db.listCollections().toArray();
|
|
return await Promise.all(items.map(collection => db.collection(collection.name).stats()));
|
|
}
|
|
|
|
mongoModule.close = async function () {
|
|
await client.close();
|
|
};
|
|
|
|
require('./mongo/main')(mongoModule);
|
|
require('./mongo/hash')(mongoModule);
|
|
require('./mongo/sets')(mongoModule);
|
|
require('./mongo/sorted')(mongoModule);
|
|
require('./mongo/list')(mongoModule);
|
|
require('./mongo/transaction')(mongoModule);
|
|
|
|
require('../promisify')(mongoModule, ['client', 'sessionStore']);
|