Skip to content

Instantly share code, notes, and snippets.

@huksley
Last active July 22, 2022 07:55
Show Gist options
  • Save huksley/a630a063ffdeb27051ff1b26ceb0aab4 to your computer and use it in GitHub Desktop.
Save huksley/a630a063ffdeb27051ff1b26ceb0aab4 to your computer and use it in GitHub Desktop.
Converts MongoDB Atlas connection url (or cluster name) into regular mongo:// URL with initial host randomization.
const dns = require("dns");
/**
* Converts MongoDB Atlas connection url (or cluster name) into regular URL,
* with initial host randomization.
*
* Uses so-called DNS Seed List Connection Format
* @see https://www.mongodb.com/docs/manual/reference/connection-string/#dns-seed-list-connection-format
**/
const convertMongoAtlasConnectionUrl = (url) =>
new Promise((resolve, reject) => {
let host = url || process.env.MONGO_URL;
let db = process.env.MONGO_DB || "db";
let query = "";
if (!host) {
reject(new Error("No url or hostname specified!"));
}
try {
const url = new URL(host);
host = url.host;
query = url.search ? url.search.substring(1) : "";
db = url.pathname.length > 1 ? url.pathname.substring(1) : db;
} catch (e) {
// Don't care - consume either url or hostname
console.info(e);
}
const srv = "_mongodb._tcp." + host;
dns.resolve(srv, "SRV", (err, addresses) => {
if (err) {
const e = new Error("Failed to resolve SRV " + srv + ": " + (err?.message || String(err)));
e.error = err;
reject(e);
} else {
const nodes = addresses.map((a) => a.name);
dns.resolve(host, "TXT", (err, values) => {
if (err) {
const e = new Error("Failed to resolve TXT " + host + ": " + (err?.message || String(err)));
e.error = err;
reject(e);
} else {
let options = values.flat(1).join("");
if (options.indexOf("connectTimeoutMS=") < 0) {
options += "&connectTimeoutMS=" + (process.env.MONGO_CONNECT_TIMEOUT || "3000");
}
if (options.indexOf("ssl=") < 0 && options.indexOf("tls=") < 0) {
options += "&ssl=true";
}
if (query) {
options += "&" + query;
}
const random = nodes[Math.floor(Math.random() * nodes.length)];
resolve("mongodb://" + random + ":27017/" + db + "?" + options);
}
});
}
});
});
if (require.main === module) {
convertMongoAtlasConnectionUrl(process.argv[2])
.then((url) => process.stdout.write(url))
.catch((e) => {
console.warn(e?.message || String(e));
process.exit(1);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment