UNPKG

oracledb

Version:

A Node.js module for Oracle Database access from JavaScript and TypeScript

905 lines (817 loc) 28.8 kB
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. //----------------------------------------------------------------------------- // // This software is dual-licensed to you under the Universal Permissive License // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose // either license. // // If you elect to accept the software under the Apache License, Version 2.0, // the following applies: // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //----------------------------------------------------------------------------- 'use strict'; const { findNVPairRecurse, createNVPair } = require('./nvStrToNvPair.js'); const errors = require("../../errors.js"); const os = require("os"); const net = require('net'); const dns = require('dns'); const dnsPromises = dns.promises; const cInfo = require("../util.js").CLIENT_INFO; const SchemaObjectFactoryInterface = { ADDR: 0, ADDR_LIST: 1, DESC: 2, DESC_LIST: 3, }; /** * Class representing Address Object */ class Address { /** return the type of this SchemaObject */ isS() { return SchemaObjectFactoryInterface.ADDR; } /** initialize this object from the given string * @param string the string * Error thrown if invalid NV-string format (ie, bad parens) * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...)) and ") */ initFromString(s) { const nvp = createNVPair(s); this.initFromNVPair(nvp); } /** initialize this object from an NVPair * @param nvp the NVPair * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromNVPair(nvp) { if (nvp == null || !(nvp.name.toUpperCase() == "ADDRESS")) errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); const protnvp = findNVPairRecurse(nvp, 'protocol'); const portnvp = findNVPairRecurse(nvp, 'port'); const hostnvp = findNVPairRecurse(nvp, 'host'); const httpsProxyNVP = findNVPairRecurse(nvp, 'https_proxy'); const httpsProxyPortNVP = findNVPairRecurse(nvp, 'https_proxy_port'); if (portnvp) this.port = Number(portnvp.atom); if (hostnvp) this.host = hostnvp.atom; if (protnvp) this.prot = protnvp.atom; if (httpsProxyNVP) this.httpsProxy = httpsProxyNVP.atom; if (httpsProxyPortNVP) this.httpsProxyPort = Number(httpsProxyPortNVP.atom); this.addr = nvp.toString(); } /** return the string representation of this object */ toString() { return this.addr; } } /** * Class representing addressList object */ class AddressList { constructor() { this.children = new Array(); this.sourceRoute = false; this.loadBalance = false; this.failover = true; } /** return the type of this SchemaObject */ isS() { return SchemaObjectFactoryInterface.ADDR_LIST; } /** initialize this object from the given string * @param string the string * Error thrown if invalid NV-string format (ie, bad parens) * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromString(s) { const nvp = createNVPair(s); this.initFromNVPair(nvp); } /** initialize this object from an NVPair * @param nvp the NVPair * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromNVPair(nvp) { /* for each child of "ADDRESS_LIST", create child or set SR/LB/FO */ this.children = []; let childnv, child; const listsize = nvp.getListSize(); if (listsize == 0) /* atom can not be valid */ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); for (let i = 0; i < listsize; i++) { childnv = nvp.getListElement(i); if (childnv.name.toUpperCase() == "SOURCE_ROUTE") { this.sourceRoute = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "LOAD_BALANCE") { this.loadBalance = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "FAILOVER") { this.failover = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "ADDRESS") { child = new NavAddress(); child.initFromNVPair(childnv); this.children.push(child); } else if (childnv.name.toUpperCase() == "ADDRESS_LIST") { child = new NavAddressList(); child.initFromNVPair(childnv); this.children.push(child); } else errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); } if (this.children.length == 0) errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); } /** return the string representation of this object */ toString() { let s = new String(""); if (this.children.size() < 1) // there is no address list without addresses return s; s += "(ADDRESS_LIST="; for (let i = 0; i < this.children.size(); i++) s += this.children[i].toString(); if (this.sourceRoute) s += "(SOURCE_ROUTE=yes)" + NavSchemaObject.HC; if (this.loadBalance) s += "(LOAD_BALANCE=yes)"; if (!this.failover) s += "(FAILOVER=false)"; s += ")"; return s; } } /** * Class represnting description object */ class Description { // description-level stuff constructor() { this.children = new Array(); this.sourceRoute = false; this.loadBalance = false; this.failover = true; this.delayInMillis = -1; this.params = {}; } /** * Return the type of this SchemaObject */ isS() { return SchemaObjectFactoryInterface.DESC; } /** * Initialize this object from the given string * * @param string * the string * Error rhrown if invalid NV-string format (ie, bad parens) * Error thrown if invalid syntax (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromString(s) { const nvp = createNVPair(s); this.initFromNVPair(nvp); } /** initialize this object from an NVPair * @param nvp the NVPair * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ //errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); initFromNVPair(nvp) { const listsize = nvp.getListSize(); let childnv, child; if (listsize == 0) // atom can not be valid errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); for (let i = 0; i < listsize; i++) { childnv = nvp.getListElement(i); if (childnv.name.toUpperCase() == "SOURCE_ROUTE") { this.sourceRoute = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "LOAD_BALANCE") { this.loadBalance = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "FAILOVER") { this.failover = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "USE_SNI") { this.params.useSNI = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "ADDRESS_LIST") { child = new NavAddressList(); child.initFromNVPair(childnv); this.children.push(child); } else if (childnv.name.toUpperCase() == "ADDRESS") { child = new NavAddress(); child.initFromNVPair(childnv); this.children.push(child); } else if (childnv.name.toUpperCase() == "CONNECT_DATA") { let tmpnv; const listsize = childnv.getListSize(); for (let i = 0; i < listsize; i++) { tmpnv = childnv.getListElement(i); if (tmpnv.name.toUpperCase() == "CONNECTION_ID_PREFIX") { this.params.connectionIdPrefix = tmpnv.atom; childnv.removeListElement(i); break; } } this.connectData = childnv.valueToString(); } else if (childnv.name.toUpperCase() == "RETRY_DELAY") { // Delay between retries. // If no unit is provided, it is interpreted in seconds. // The value is internally stored in milliseconds. if (childnv.atom > 0) this.delayInMillis = childnv.atom * 1000; } else if (childnv.name.toUpperCase() == "RETRY_COUNT") { this.retryCount = childnv.atom; } else if (childnv.name.toUpperCase() == "CONNECTION_ID_PREFIX") { this.conidPrefix = childnv.atom; } else if (childnv.name.toUpperCase() == "CONNECT_TIMEOUT") { if (childnv.atom > 0) this.params.connectTimeout = childnv.atom; } else if (childnv.name.toUpperCase() == "TRANSPORT_CONNECT_TIMEOUT") { if (childnv.atom > 0) this.params.transportConnectTimeout = childnv.atom; } else if (childnv.name.toUpperCase() == "ENABLE") { this.params.enable = childnv.atom; } else if (childnv.name.toUpperCase() == "RECV_TIMEOUT") { if (childnv.atom > 0) { this.params.recvTimeout = childnv.atom; } } else if (childnv.name.toUpperCase() == "SDU") { this.params.sdu = childnv.atom; } else if (childnv.name.toUpperCase() == "COMPRESSION") { this.params.networkCompression = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); this.params.networkCompressionLevels = []; } else if (childnv.name.toUpperCase() == "COMPRESSION_LEVELS") { const listsize = childnv.getListSize(); for (let i = 0; i < listsize; i++) { const tmpnv = childnv.getListElement(i); if (tmpnv.name.toUpperCase() == "LEVEL") { this.params.networkCompressionLevels.push(tmpnv.atom.toLowerCase()); } } } else if (childnv.name.toUpperCase() == "EXPIRE_TIME") { if (childnv.atom > 0) this.params.expireTime = childnv.atom; } else if (childnv.name.toUpperCase() == "SECURITY") { const listsize = childnv.getListSize(); let tmpnv; for (let i = 0; i < listsize; i++) { tmpnv = childnv.getListElement(i); if (tmpnv.name.toUpperCase() == "SSL_SERVER_CERT_DN") { this.params.sslServerCertDN = tmpnv.valueToString(); } else if (tmpnv.name.toUpperCase() == "SSL_SERVER_DN_MATCH") { this.params.sslServerDNMatch = (tmpnv.atom.toLowerCase() == "yes" || tmpnv.atom.toLowerCase() == "on" || tmpnv.atom.toLowerCase() == "true"); } else if (tmpnv.name.toUpperCase() == "SSL_ALLOW_WEAK_DN_MATCH") { this.params.sslAllowWeakDNMatch = (tmpnv.atom.toLowerCase() == "yes" || tmpnv.atom.toLowerCase() == "on" || tmpnv.atom.toLowerCase() == "true"); } else if ((tmpnv.name.toUpperCase() == "WALLET_LOCATION") || (tmpnv.name.toUpperCase() == "MY_WALLET_DIRECTORY")) { this.params.walletLocation = tmpnv.atom; } } } } } toString() { let s = new String(""), child ; // see if there are any endpoints child = new String(""); for (let i = 0; i < this.children.size(); i++) { child = this.children[i].toString(); if (!child == "") s += child; } // some parameters make sense only if there are endpoints defined if (!s == "" && this.sourceRoute) s += "(SOURCE_ROUTE=yes)"; if (!s == "" && this.loadBalance) s += "(LOAD_BALANCE=yes)"; if (!s == "" && !this.failover) s += "(FAILOVER=false)"; if (!s.equals("")) s = "(DESCRIPTION=" + s + ")"; return s; } } /** * Class representing DescriptionList object. */ class DescriptionList { constructor() { this.children = new Array(); this.sourceRoute = false; this.loadBalance = true; this.failover = true; } /** return the type of this SchemaObject */ isS() { return SchemaObjectFactoryInterface.ADDR_LIST; } /** initialize this object from the given string * @param string the string * Error thrown if invalid NV-string format (ie, bad parens) * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromString(s) { const nvp = createNVPair(s); this.initFromNVPair(nvp); } /** initialize this object from an NVPair * @param nvp the NVPair * Error thrown if invalid syntax * (ie, "(ADDRESS=(DESCRIPTION=...))") */ initFromNVPair(nvp) { const listsize = nvp.getListSize(); let child, childnv; if (listsize == 0) /* atom can not be valid */ errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); for (let i = 0; i < listsize; i++) { childnv = nvp.getListElement(i); if (childnv.name.toUpperCase() == "SOURCE_ROUTE") { this.sourceRoute = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase == "true"); } else if (childnv.name.toUpperCase() == "LOAD_BALANCE") { this.loadBalance = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "FAILOVER") { this.failover = (childnv.atom.toLowerCase() == "yes" || childnv.atom.toLowerCase() == "on" || childnv.atom.toLowerCase() == "true"); } else if (childnv.name.toUpperCase() == "DESCRIPTION") { child = new NavDescription(); child.initFromNVPair(childnv); this.children.push(child); } else errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); } if (this.children.length == 0) errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX); } /** return the string representation of this object */ toString() { let s = new String(""); if (this.children.size() < 1) // no descr list without descriptions return s; let child = new String(""); for (let i = 0; i < this.children.size(); i++) { child = this.children[i].toString(); if (!child.equals("")) s += child; } // some parameters make sense only if there are endpoints defined if (s.equals("") && this.sourceRoute) s += "(SOURCE_ROUTE=yes)"; if (s.equals("") && !this.loadBalance) s += "(LOAD_BALANCE=no)"; if (s.equals("") && !this.failover) s += "(FAILOVER=false)"; if (!s.equals("")) // no valid children were found s = "(DESCRIPTION_LIST=" + s + ")"; return s; } } /** * Class that contains information about a possible connection. */ class ConnOption { constructor() { this.CNdata = new Array(); } } const NavSchemaObject = { DEBUG: false, SR: "(SOURCE_ROUTE=yes)", HC: "(HOP_COUNT=0)", LB: "(LOAD_BALANCE=yes)", NFO: "(FAILOVER=false)", CD: "(CONNECT_DATA=", CONID: "(CONNECTION_ID=" }; const options = { all: true, }; /** * Class that navigates the address node in the tree. */ class NavAddress extends Address { constructor() { super(); } /** * Set the connection option to this address. * @param {object} cs */ async navigate(cs) { let addresses; let nullHost = false; let needToCloseDescription = false; if (!this.host) { nullHost = true; this.host = os.hostname(); try { await dnsPromises.lookup(this.host, options); } catch { this.host = 'localhost'; } } // Sometimes REDIRECT packets do not have DESCRIPTION // this is for handling such conditions. if (cs.getcurrentDescription() == null) { cs.newConnectionDescription(); needToCloseDescription = true; } if (!net.isIP(this.host)) { try { addresses = await dnsPromises.lookup(this.host, options); for (const addr of addresses) { const co = new ConnOption(); co.hostname = this.host; co.port = this.port; co.protocol = this.prot; co.httpsProxy = this.httpsProxy; co.httpsProxyPort = this.httpsProxyPort; co.desc = cs.getcurrentDescription(); co.CNdata.push(cs.sBuf.join("")); if (nullHost) co.CNdata.push('(address=(protocol=' + this.prot + ')(host=' + this.host + ')(port=' + this.port + '))'); else co.CNdata.push(this.toString()); co.host = addr.address; co.addr = this.addr; cs.getcurrentDescription().addConnectOption(co); } } catch { // do nothing // Any error in the try block is ignored, because we want to try // the next address } } else { const co = new ConnOption(); co.hostname = this.host; co.port = this.port; co.protocol = this.prot; co.httpsProxy = this.httpsProxy; co.httpsProxyPort = this.httpsProxyPort; co.desc = cs.getcurrentDescription(); co.CNdata.push(cs.sBuf.join("")); co.CNdata.push(this.toString()); co.host = this.host; co.addr = this.addr; cs.getcurrentDescription().addConnectOption(co); } if (needToCloseDescription) { cs.closeDescription(); } } /** * AddToString is used to construct a string representation of the TNS * Address. Constructing a string is mainly needed when source route is ON. */ addToString(cs) { const NVString = this.toString(); let cOpts = new Array(); cOpts = cs.getcurrentDescription().getConnectOptions(); for (let i = 0;i < cOpts.length; i++) { if (cOpts[i].done) { continue; } cOpts[i].CNdata.push(NVString); } } } /** * Class that navigates the addressList node in the tree. */ class NavAddressList extends AddressList { constructor() { super(); this.activeChildren = new Array(); this.sBuflength = 0; } /** * Method decides how to traverse and sets the active children based on * the loadbalancing, failover values. * @param {object} cs */ async navigate(cs) { await this.navigate2(cs, 0); } async navigate2(cs, reCurCnt) { reCurCnt++; this.sBuflength = cs.sBuf.length; cs.sBuf.push("(ADDRESS_LIST="); if (this.sourceRoute) { this.activeChildren = this.children; await this.activeChildren[0].navigate(cs); for (let i = 1; i < this.activeChildren.length; i++) { this.activeChildren[i].addToString(cs); } } else { // SR is off this.activeChildren = NavDescriptionList.setActiveChildren(this.children, this.failover, this.loadBalance); for (let i = 0; i < this.activeChildren.length; i++) { if (this.getChildrenType(i) == 1) { await this.activeChildren[i].navigate2(cs, reCurCnt); } else { await this.activeChildren[i].navigate(cs); } } } this.closeNVPair(cs); cs.sBuf.length = this.sBuflength; } addToString(cs) { const NVString = this.toString(); let cOpts = new Array(); cOpts = cs.getcurrentDescription().getConnectOptions(); for (let i = 0;i < cOpts.length; i++) { if (cOpts[i].done) { continue; } cOpts[i].CNdata.push(NVString); } } getChildrenSize() { let size = 0; for (let i = 0; i < this.activeChildren.length; i++) { if (this.getChildrenType(i) == 1) { size += this.activeChildren[i].getChildrenSize(); } else { size++; } if (this.sourceRoute) return size; } return (size); } /** * get children type */ getChildrenType(childNum) { return (this.activeChildren[childNum].isS()); } /** *get child at a given pos */ getChild(childNum) { return (this.children[childNum]); } closeNVPair(cs) { let cOpts = new Array(); const childS = this.getChildrenSize(); if (cs.getcurrentDescription() != null) { cOpts = cs.getcurrentDescription().getConnectOptions(); let numChildren = 0; let prevHost = null; let prevPort = null; for (let i = cOpts.length - 1 ; (i >= 0 && !cOpts[i].done); i--) { if (cOpts[i].hostname != prevHost || cOpts[i].port != prevPort) numChildren++; prevHost = cOpts[i].hostname; prevPort = cOpts[i].port; // close NV Pair for current active children if ((numChildren > childS)) { break; } if (this.sourceRoute) { cOpts[i].CNdata.push(NavSchemaObject.SR); cOpts[i].CNdata.push(NavSchemaObject.HC); cOpts[i].done = true; } // Always close the NV Pair with a ")" cOpts[i].CNdata.push(")"); } } } } /** * Class that navigates the description node in a tree. */ class NavDescription extends Description { constructor() { super(); this.activeChildren = new Array(); this.descProcessed = 0; } /** * Method decides how to traverse and sets the active children based on * the loadbalancing, failover values. Also creates connection description * object. * @param {object} cs */ async navigate(cs) { cs.sBuf.length = 0; //reset cs.sBuf.push("(DESCRIPTION="); const desc = cs.newConnectionDescription(); //connectiondescription if (this.retryCount != null) { cs.retryCount = this.getIntValue(this.retryCount, cs.retryCount); desc.retryCount = cs.retryCount; } if (this.delayInMillis != -1) { desc.delayInMillis = this.delayInMillis; } desc.params = this.params; if ('connectTimeout' in this.params) { cs.sBuf.push("(CONNECT_TIMEOUT=" + this.params.connectTimeout + ")"); } if ('transportConnectTimeout' in this.params) { cs.sBuf.push("(TRANSPORT_CONNECT_TIMEOUT=" + this.params.transportConnectTimeout + ")"); } if ('recvTimeout' in this.params) { cs.sBuf.push("(RECV_TIMEOUT=" + this.params.recvTimeout + ")"); } if ('sdu' in this.params) { cs.sBuf.push("(SDU=" + this.params.sdu + ")"); } if ('expireTime' in this.params) { cs.sBuf.push("(EXPIRE_TIME=" + this.params.expireTime + ")"); } if ('enable' in this.params) { cs.sBuf.push("(ENABLE=" + this.params.enable + ")"); } if ('useSNI' in this.params) { cs.sBuf.push("(USE_SNI=" + this.params.useSNI + ")"); } if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params) || ('sslAllowWeakDNMatch' in this.params)) { cs.sBuf.push("(SECURITY="); if ('sslServerCertDN' in this.params) { cs.sBuf.push("(SSL_SERVER_CERT_DN=" + this.params.sslServerCertDN + ")"); } if ('sslServerDNMatch' in this.params) { cs.sBuf.push("(SSL_SERVER_DN_MATCH=" + this.params.sslServerDNMatch + ")"); } if ('sslAllowWeakDNMatch' in this.params) { cs.sBuf.push("(SSL_ALLOW_WEAK_DN_MATCH=" + this.params.sslAllowWeakDNMatch + ")"); } if ('walletLocation' in this.params) { cs.sBuf.push("(WALLET_LOCATION=" + this.params.walletLocation + ")"); } cs.sBuf.push(")"); } if ('httpsProxyPort' in this.params) { cs.sBuf.push("(HTTPS_PROXY_PORT=" + this.params.httpsProxyPort + ")"); } if ('httpsProxy' in this.params) { cs.sBuf.push("(HTTPS_PROXY=" + this.params.httpsProxy + ")"); } if (!this.failover) { cs.sBuf.push(NavSchemaObject.NFO); } if (!this.sourceRoute) { // SR is off, navigate every child and close the NV Pair this.activeChildren = NavDescriptionList.setActiveChildren(this.children, this.failover, this.loadBalance); for (let i = 0; i < this.activeChildren.length; i++) { await this.activeChildren[i].navigate(cs); } this.closeNVPair(cs); } else { // SR is ON this.activeChildren = this.children; await this.activeChildren[0].navigate(cs); for (let i = 1; i < this.activeChildren.length; i++) { this.activeChildren[i].addToString(cs); } this.closeNVPair(cs); } cs.closeDescription(); } closeNVPair(cs) { if (cs.getcurrentDescription() == null) return; let cOpts = new Array(); cOpts = cs.getcurrentDescription().getConnectOptions(); for (let i = 0; i < cOpts.length; ++i) { if (this.sourceRoute) { cOpts[i].CNdata.push(NavSchemaObject.SR); } // Use default service, if no connect_data if (this.connectData == null) { this.connectData = "(SERVICE_NAME=)"; } let pgmName = cInfo.program; if (cs.program) { pgmName = cs.program; } let hostName = cInfo.hostName; if (cs.machine) { hostName = cs.machine; } let userName = cInfo.userName; if (cs.osUser) { userName = cs.osUser; } const cid = `(CID=(PROGRAM=${pgmName})(HOST=${hostName})(USER=${userName}))`; cOpts[i].CNdata.push(NavSchemaObject.CD); cOpts[i].CNdata.push(this.connectData); cOpts[i].CNdata.push(cid); cOpts[i].CNdata.push(")"); if (this.SID != null) { cOpts[i].sid = this.SID; } if (this.serviceName != null) { cOpts[i].service_name = this.serviceName; } if (this.instanceName != null) { cOpts[i].instance_name = this.instanceName; } // Close the description cOpts[i].CNdata.push(")"); cOpts[i].done = true; } } getIntValue(stringInt, defaultValue) { if (/^\d+$/.test(stringInt)) return parseInt(stringInt); return defaultValue; } } /** * Class that navigates descriptionlist node in a tree. */ class NavDescriptionList extends DescriptionList { constructor(activeChildren = new Array(), descProcessed = 0, done = 0) { super(); this.activeChildren = activeChildren; this.descProcessed = descProcessed; this.done = done; } /** * Method decides how to traverse and sets the active children based on * the loadbalancing, failover values. * @param {object} cs */ async navigate(cs) { cs.sBuf.push("(DESCRIPTION_LIST="); this.activeChildren = NavDescriptionList.setActiveChildren(this.children, this.failover, this.loadBalance); while (this.descProcessed < this.activeChildren.length) { await this.activeChildren[this.descProcessed].navigate(cs); this.descProcessed++; } } /** set active children based on lb and failover values. * @param children * @param failover * @param loadBalance */ static setActiveChildren(children, failover, loadBalance) { let randNumber; const listSize = children.length; let tmpChildren = new Array(); const rand = Math.floor(Math.random() * 10); const arr = new Array(listSize).fill(false); if (failover) { if (loadBalance) { for (let i = 0; i < listSize; i++) { do { randNumber = Math.abs(Math.floor(Math.random() * 10)) % listSize; } while (arr[randNumber]); arr[randNumber] = true; tmpChildren.push(children[randNumber]); } } else { tmpChildren = children; } } else { // not failover if (loadBalance) { randNumber = Math.abs(rand) % listSize; tmpChildren.push(children[randNumber]); } else { tmpChildren.push(children[0]); } } return (tmpChildren); } } module.exports = {NavAddress, NavAddressList, NavDescription, NavDescriptionList};