// muri
|
|
|
|
/**
|
|
* MongoDB URI parser as described here:
|
|
* http://www.mongodb.org/display/DOCS/Connections
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies
|
|
*/
|
|
|
|
var qs = require('querystring');
|
|
|
|
/**
|
|
* Defaults
|
|
*/
|
|
|
|
var DEFAULT_PORT = 27017;
|
|
var DEFAULT_DB = 'test';
|
|
var ADMIN_DB = 'admin';
|
|
|
|
/**
|
|
* Muri
|
|
*/
|
|
|
|
module.exports = exports = function muri (str) {
|
|
if (!/^mongodb:\/\//.test(str)) {
|
|
throw new Error('Invalid mongodb uri "' + str + '". Must begin with "mongodb://"');
|
|
}
|
|
|
|
var ret = {
|
|
hosts: []
|
|
, db: DEFAULT_DB
|
|
, options: {}
|
|
}
|
|
|
|
var match = /^mongodb:\/\/([^?]+)(\??.*)$/.exec(str);
|
|
if (!match || '/' == match[1]) {
|
|
throw new Error('Invalid mongodb uri "' + str + '". Missing hostname');
|
|
}
|
|
|
|
var uris = match[1];
|
|
var path = match[2];
|
|
var db;
|
|
|
|
uris.split(',').forEach(function (uri) {
|
|
var o = parse(uri);
|
|
|
|
if (o.host) {
|
|
ret.hosts.push({
|
|
host: o.host
|
|
, port: parseInt(o.port, 10)
|
|
})
|
|
|
|
if (!db && o.db) {
|
|
db = o.db;
|
|
}
|
|
} else if (o.ipc) {
|
|
ret.hosts.push({ ipc: o.ipc });
|
|
}
|
|
|
|
if (o.auth) {
|
|
ret.auth = {
|
|
user: o.auth.user ? (o.auth.user) : void 0
|
|
, pass: o.auth.pass ? (o.auth.pass) : void 0
|
|
}
|
|
}
|
|
})
|
|
|
|
if (!ret.hosts.length) {
|
|
throw new Error('Invalid mongodb uri "' + str + '". Missing hostname');
|
|
}
|
|
|
|
var parts = path.split('?');
|
|
|
|
if (!db) {
|
|
if (parts[0]) {
|
|
db = parts[0].replace(/^\//, '');
|
|
} else {
|
|
// deal with ipc formats
|
|
db = /\/([^\.]+)$/.exec(match[1]);
|
|
if (db && db[1]) {
|
|
db = db[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (db) {
|
|
ret.db = db;
|
|
} else if (ret.auth) {
|
|
ret.db = ADMIN_DB;
|
|
}
|
|
|
|
if (parts[1]) {
|
|
ret.options = options(parts[1]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Parse str into key/val pairs casting values appropriately.
|
|
*/
|
|
|
|
function options (str) {
|
|
var sep = /;/.test(str)
|
|
? ';'
|
|
: '&';
|
|
|
|
var ret = qs.parse(str, sep);
|
|
|
|
Object.keys(ret).forEach(function (key) {
|
|
var val = ret[key];
|
|
if ('readPreferenceTags' == key) {
|
|
val = readPref(val);
|
|
if (val) {
|
|
ret[key] = Array.isArray(val)
|
|
? val
|
|
: [val];
|
|
}
|
|
} else {
|
|
ret[key] = format(val);
|
|
}
|
|
});
|
|
|
|
return ret;
|
|
}
|
|
|
|
function format (val) {
|
|
var num;
|
|
|
|
if ('true' == val) {
|
|
return true;
|
|
} else if ('false' == val) {
|
|
return false;
|
|
} else {
|
|
num = parseInt(+val, 10);
|
|
if (!isNaN(num)) {
|
|
return num;
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
function readPref (val) {
|
|
var ret;
|
|
|
|
if (Array.isArray(val)) {
|
|
ret = val.map(readPref).filter(Boolean);
|
|
return ret.length
|
|
? ret
|
|
: undefined
|
|
}
|
|
|
|
var pair = val.split(',');
|
|
var hasKeys;
|
|
ret = {};
|
|
|
|
pair.forEach(function (kv) {
|
|
kv = (kv || '').trim();
|
|
if (!kv) return;
|
|
hasKeys = true;
|
|
var split = kv.split(':');
|
|
ret[split[0]] = format(split[1]);
|
|
});
|
|
|
|
return hasKeys && ret;
|
|
}
|
|
|
|
var ipcRgx = /\.sock/;
|
|
|
|
function parse (uriString) {
|
|
// do not use require('url').parse b/c it can't handle # in username or pwd
|
|
// mongo uris are strange
|
|
|
|
var uri = uriString;
|
|
var ret = {};
|
|
var parts;
|
|
var auth;
|
|
var ipcs;
|
|
|
|
// skip protocol
|
|
uri = uri.replace(/^mongodb:\/\//, '');
|
|
|
|
// auth
|
|
if (/@/.test(uri)) {
|
|
parts = uri.split(/@/);
|
|
auth = parts[0];
|
|
uri = parts[1];
|
|
|
|
parts = auth.split(':');
|
|
ret.auth = {};
|
|
ret.auth.user = decodeURIComponent(parts[0]);
|
|
ret.auth.pass = parts[1] ? decodeURIComponent(parts[1]) : void 0;
|
|
}
|
|
|
|
// unix domain sockets
|
|
if (ipcRgx.test(uri)) {
|
|
ipcs = uri.split(ipcRgx);
|
|
ret.ipc = ipcs[0] + '.sock';
|
|
|
|
// included a database?
|
|
if (ipcs[1]) {
|
|
// strip leading / from database name
|
|
ipcs[1] = ipcs[1].replace(/^\//, '');
|
|
|
|
if (ipcs[1]) {
|
|
ret.db = ipcs[1];
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// database name
|
|
parts = uri.split('/');
|
|
if (parts[1]) ret.db = parts[1];
|
|
|
|
// ipv6, [ip]:host
|
|
if (/^\[[^\]]+\]:\d+/.test(parts[0])) {
|
|
ret.host = parts[0].substring(1, parts[0].indexOf(']:'));
|
|
ret.port = parts[0].substring(parts[0].indexOf(']:') + ']:'.length);
|
|
} else {
|
|
// host:port
|
|
parts = parts[0].split(':');
|
|
ret.host = parts[0];
|
|
ret.port = parts[1] || DEFAULT_PORT;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Version
|
|
*/
|
|
|
|
module.exports.version = require('../package.json').version;
|