tedious
Version:
A TDS driver, for connecting to MS SQLServer databases.
91 lines (90 loc) • 13.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.instanceLookup = instanceLookup;
exports.parseBrowserResponse = parseBrowserResponse;
var _dns = _interopRequireDefault(require("dns"));
var _sender = require("./sender");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const SQL_SERVER_BROWSER_PORT = 1434;
const TIMEOUT = 2 * 1000;
const RETRIES = 3;
// There are three bytes at the start of the response, whose purpose is unknown.
const MYSTERY_HEADER_LENGTH = 3;
// Most of the functionality has been determined from from jTDS's MSSqlServerInfo class.
async function instanceLookup(options) {
const server = options.server;
if (typeof server !== 'string') {
throw new TypeError('Invalid arguments: "server" must be a string');
}
const instanceName = options.instanceName;
if (typeof instanceName !== 'string') {
throw new TypeError('Invalid arguments: "instanceName" must be a string');
}
const timeout = options.timeout === undefined ? TIMEOUT : options.timeout;
if (typeof timeout !== 'number') {
throw new TypeError('Invalid arguments: "timeout" must be a number');
}
const retries = options.retries === undefined ? RETRIES : options.retries;
if (typeof retries !== 'number') {
throw new TypeError('Invalid arguments: "retries" must be a number');
}
if (options.lookup !== undefined && typeof options.lookup !== 'function') {
throw new TypeError('Invalid arguments: "lookup" must be a function');
}
const lookup = options.lookup ?? _dns.default.lookup;
if (options.port !== undefined && typeof options.port !== 'number') {
throw new TypeError('Invalid arguments: "port" must be a number');
}
const port = options.port ?? SQL_SERVER_BROWSER_PORT;
const signal = options.signal;
signal.throwIfAborted();
let response;
const request = Buffer.from([0x02]);
for (let i = 0; i <= retries; i++) {
const timeoutSignal = AbortSignal.timeout(timeout);
try {
response = await (0, _sender.sendMessage)(options.server, port, lookup, AbortSignal.any([signal, timeoutSignal]), request);
} catch (err) {
// If the current attempt timed out, continue with the next
if (timeoutSignal.aborted) {
continue;
}
throw err;
}
}
if (!response) {
throw new Error('Failed to get response from SQL Server Browser on ' + server);
}
const message = response.toString('ascii', MYSTERY_HEADER_LENGTH);
const foundPort = parseBrowserResponse(message, instanceName);
if (!foundPort) {
throw new Error('Port for ' + instanceName + ' not found in ' + options.server);
}
return foundPort;
}
function parseBrowserResponse(response, instanceName) {
let getPort;
const instances = response.split(';;');
for (let i = 0, len = instances.length; i < len; i++) {
const instance = instances[i];
const parts = instance.split(';');
for (let p = 0, partsLen = parts.length; p < partsLen; p += 2) {
const name = parts[p];
const value = parts[p + 1];
if (name === 'tcp' && getPort) {
const port = parseInt(value, 10);
return port;
}
if (name === 'InstanceName') {
if (value.toUpperCase() === instanceName.toUpperCase()) {
getPort = true;
} else {
getPort = false;
}
}
}
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZG5zIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfc2VuZGVyIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiU1FMX1NFUlZFUl9CUk9XU0VSX1BPUlQiLCJUSU1FT1VUIiwiUkVUUklFUyIsIk1ZU1RFUllfSEVBREVSX0xFTkdUSCIsImluc3RhbmNlTG9va3VwIiwib3B0aW9ucyIsInNlcnZlciIsIlR5cGVFcnJvciIsImluc3RhbmNlTmFtZSIsInRpbWVvdXQiLCJ1bmRlZmluZWQiLCJyZXRyaWVzIiwibG9va3VwIiwiZG5zIiwicG9ydCIsInNpZ25hbCIsInRocm93SWZBYm9ydGVkIiwicmVzcG9uc2UiLCJyZXF1ZXN0IiwiQnVmZmVyIiwiZnJvbSIsImkiLCJ0aW1lb3V0U2lnbmFsIiwiQWJvcnRTaWduYWwiLCJzZW5kTWVzc2FnZSIsImFueSIsImVyciIsImFib3J0ZWQiLCJFcnJvciIsIm1lc3NhZ2UiLCJ0b1N0cmluZyIsImZvdW5kUG9ydCIsInBhcnNlQnJvd3NlclJlc3BvbnNlIiwiZ2V0UG9ydCIsImluc3RhbmNlcyIsInNwbGl0IiwibGVuIiwibGVuZ3RoIiwiaW5zdGFuY2UiLCJwYXJ0cyIsInAiLCJwYXJ0c0xlbiIsIm5hbWUiLCJ2YWx1ZSIsInBhcnNlSW50IiwidG9VcHBlckNhc2UiXSwic291cmNlcyI6WyIuLi9zcmMvaW5zdGFuY2UtbG9va3VwLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBkbnMgZnJvbSAnZG5zJztcblxuaW1wb3J0IHsgc2VuZE1lc3NhZ2UgfSBmcm9tICcuL3NlbmRlcic7XG5cbmNvbnN0IFNRTF9TRVJWRVJfQlJPV1NFUl9QT1JUID0gMTQzNDtcbmNvbnN0IFRJTUVPVVQgPSAyICogMTAwMDtcbmNvbnN0IFJFVFJJRVMgPSAzO1xuLy8gVGhlcmUgYXJlIHRocmVlIGJ5dGVzIGF0IHRoZSBzdGFydCBvZiB0aGUgcmVzcG9uc2UsIHdob3NlIHB1cnBvc2UgaXMgdW5rbm93bi5cbmNvbnN0IE1ZU1RFUllfSEVBREVSX0xFTkdUSCA9IDM7XG5cbnR5cGUgTG9va3VwRnVuY3Rpb24gPSAoaG9zdG5hbWU6IHN0cmluZywgb3B0aW9uczogZG5zLkxvb2t1cEFsbE9wdGlvbnMsIGNhbGxiYWNrOiAoZXJyOiBOb2RlSlMuRXJybm9FeGNlcHRpb24gfCBudWxsLCBhZGRyZXNzZXM6IGRucy5Mb29rdXBBZGRyZXNzW10pID0+IHZvaWQpID0+IHZvaWQ7XG5cbi8vIE1vc3Qgb2YgdGhlIGZ1bmN0aW9uYWxpdHkgaGFzIGJlZW4gZGV0ZXJtaW5lZCBmcm9tIGZyb20galREUydzIE1TU3FsU2VydmVySW5mbyBjbGFzcy5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnN0YW5jZUxvb2t1cChvcHRpb25zOiB7IHNlcnZlcjogc3RyaW5nLCBpbnN0YW5jZU5hbWU6IHN0cmluZywgdGltZW91dD86IG51bWJlciwgcmV0cmllcz86IG51bWJlciwgcG9ydD86IG51bWJlciwgbG9va3VwPzogTG9va3VwRnVuY3Rpb24sIHNpZ25hbDogQWJvcnRTaWduYWwgfSkge1xuICBjb25zdCBzZXJ2ZXIgPSBvcHRpb25zLnNlcnZlcjtcbiAgaWYgKHR5cGVvZiBzZXJ2ZXIgIT09ICdzdHJpbmcnKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSW52YWxpZCBhcmd1bWVudHM6IFwic2VydmVyXCIgbXVzdCBiZSBhIHN0cmluZycpO1xuICB9XG5cbiAgY29uc3QgaW5zdGFuY2VOYW1lID0gb3B0aW9ucy5pbnN0YW5jZU5hbWU7XG4gIGlmICh0eXBlb2YgaW5zdGFuY2VOYW1lICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0ludmFsaWQgYXJndW1lbnRzOiBcImluc3RhbmNlTmFtZVwiIG11c3QgYmUgYSBzdHJpbmcnKTtcbiAgfVxuXG4gIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgPT09IHVuZGVmaW5lZCA/IFRJTUVPVVQgOiBvcHRpb25zLnRpbWVvdXQ7XG4gIGlmICh0eXBlb2YgdGltZW91dCAhPT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIGFyZ3VtZW50czogXCJ0aW1lb3V0XCIgbXVzdCBiZSBhIG51bWJlcicpO1xuICB9XG5cbiAgY29uc3QgcmV0cmllcyA9IG9wdGlvbnMucmV0cmllcyA9PT0gdW5kZWZpbmVkID8gUkVUUklFUyA6IG9wdGlvbnMucmV0cmllcztcbiAgaWYgKHR5cGVvZiByZXRyaWVzICE9PSAnbnVtYmVyJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0ludmFsaWQgYXJndW1lbnRzOiBcInJldHJpZXNcIiBtdXN0IGJlIGEgbnVtYmVyJyk7XG4gIH1cblxuICBpZiAob3B0aW9ucy5sb29rdXAgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb3B0aW9ucy5sb29rdXAgIT09ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIGFyZ3VtZW50czogXCJsb29rdXBcIiBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcbiAgfVxuICBjb25zdCBsb29rdXAgPSBvcHRpb25zLmxvb2t1cCA/PyBkbnMubG9va3VwO1xuXG4gIGlmIChvcHRpb25zLnBvcnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb3B0aW9ucy5wb3J0ICE9PSAnbnVtYmVyJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0ludmFsaWQgYXJndW1lbnRzOiBcInBvcnRcIiBtdXN0IGJlIGEgbnVtYmVyJyk7XG4gIH1cbiAgY29uc3QgcG9ydCA9IG9wdGlvbnMucG9ydCA/PyBTUUxfU0VSVkVSX0JST1dTRVJfUE9SVDtcblxuICBjb25zdCBzaWduYWwgPSBvcHRpb25zLnNpZ25hbDtcblxuICBzaWduYWwudGhyb3dJZkFib3J0ZWQoKTtcblxuICBsZXQgcmVzcG9uc2U7XG5cbiAgY29uc3QgcmVxdWVzdCA9IEJ1ZmZlci5mcm9tKFsweDAyXSk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPD0gcmV0cmllczsgaSsrKSB7XG4gICAgY29uc3QgdGltZW91dFNpZ25hbCA9IEFib3J0U2lnbmFsLnRpbWVvdXQodGltZW91dCk7XG5cbiAgICB0cnkge1xuICAgICAgcmVzcG9uc2UgPSBhd2FpdCBzZW5kTWVzc2FnZShvcHRpb25zLnNlcnZlciwgcG9ydCwgbG9va3VwLCBBYm9ydFNpZ25hbC5hbnkoWyBzaWduYWwsIHRpbWVvdXRTaWduYWwgXSksIHJlcXVlc3QpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gSWYgdGhlIGN1cnJlbnQgYXR0ZW1wdCB0aW1lZCBvdXQsIGNvbnRpbnVlIHdpdGggdGhlIG5leHRcbiAgICAgIGlmICh0aW1lb3V0U2lnbmFsLmFib3J0ZWQpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZ2V0IHJlc3BvbnNlIGZyb20gU1FMIFNlcnZlciBCcm93c2VyIG9uICcgKyBzZXJ2ZXIpO1xuICB9XG5cbiAgY29uc3QgbWVzc2FnZSA9IHJlc3BvbnNlLnRvU3RyaW5nKCdhc2NpaScsIE1ZU1RFUllfSEVBREVSX0xFTkdUSCk7XG4gIGNvbnN0IGZvdW5kUG9ydCA9IHBhcnNlQnJvd3NlclJlc3BvbnNlKG1lc3NhZ2UsIGluc3RhbmNlTmFtZSk7XG5cbiAgaWYgKCFmb3VuZFBvcnQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1BvcnQgZm9yICcgKyBpbnN0YW5jZU5hbWUgKyAnIG5vdCBmb3VuZCBpbiAnICsgb3B0aW9ucy5zZXJ2ZXIpO1xuICB9XG5cbiAgcmV0dXJuIGZvdW5kUG9ydDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQnJvd3NlclJlc3BvbnNlKHJlc3BvbnNlOiBzdHJpbmcsIGluc3RhbmNlTmFtZTogc3RyaW5nKSB7XG4gIGxldCBnZXRQb3J0O1xuXG4gIGNvbnN0IGluc3RhbmNlcyA9IHJlc3BvbnNlLnNwbGl0KCc7OycpO1xuICBmb3IgKGxldCBpID0gMCwgbGVuID0gaW5zdGFuY2VzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgY29uc3QgaW5zdGFuY2UgPSBpbnN0YW5jZXNbaV07XG4gICAgY29uc3QgcGFydHMgPSBpbnN0YW5jZS5zcGxpdCgnOycpO1xuXG4gICAgZm9yIChsZXQgcCA9IDAsIHBhcnRzTGVuID0gcGFydHMubGVuZ3RoOyBwIDwgcGFydHNMZW47IHAgKz0gMikge1xuICAgICAgY29uc3QgbmFtZSA9IHBhcnRzW3BdO1xuICAgICAgY29uc3QgdmFsdWUgPSBwYXJ0c1twICsgMV07XG5cbiAgICAgIGlmIChuYW1lID09PSAndGNwJyAmJiBnZXRQb3J0KSB7XG4gICAgICAgIGNvbnN0IHBvcnQgPSBwYXJzZUludCh2YWx1ZSwgMTApO1xuICAgICAgICByZXR1cm4gcG9ydDtcbiAgICAgIH1cblxuICAgICAgaWYgKG5hbWUgPT09ICdJbnN0YW5jZU5hbWUnKSB7XG4gICAgICAgIGlmICh2YWx1ZS50b1VwcGVyQ2FzZSgpID09PSBpbnN0YW5jZU5hbWUudG9VcHBlckNhc2UoKSkge1xuICAgICAgICAgIGdldFBvcnQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGdldFBvcnQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUEsSUFBQUEsSUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBRUEsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBQXVDLFNBQUFELHVCQUFBRyxDQUFBLFdBQUFBLENBQUEsSUFBQUEsQ0FBQSxDQUFBQyxVQUFBLEdBQUFELENBQUEsS0FBQUUsT0FBQSxFQUFBRixDQUFBO0FBRXZDLE1BQU1HLHVCQUF1QixHQUFHLElBQUk7QUFDcEMsTUFBTUMsT0FBTyxHQUFHLENBQUMsR0FBRyxJQUFJO0FBQ3hCLE1BQU1DLE9BQU8sR0FBRyxDQUFDO0FBQ2pCO0FBQ0Es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