BE-SPAN/node_modules/oracledb/lib/thin/sqlnet/paramParser.js

241 lines
7.0 KiB
JavaScript
Raw Permalink Normal View History

2024-10-20 15:04:16 +00:00
// Copyright (c) 2022, 2023, 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 {createNVPair, findValue} = require("./nvStrToNvPair.js");
const fs = require('fs');
const process = require('process');
const readline = require('readline');
const errors = require("../../errors.js");
const MAX_IFILE_DEPTH = 4;
/**
* Returns File path of the tnsnames.ora if it exists.
*/
function tnsnamesFilePath(configDir) {
let filePathVal = null;
const tnsAdminVal = process.env.TNS_ADMIN;
if (configDir) {
filePathVal = configDir + '/tnsnames.ora';
if (fs.existsSync(filePathVal)) {
return filePathVal;
} else {
errors.throwErr(errors.ERR_TNS_NAMES_FILE_MISSING, configDir);
}
} else {
if (!tnsAdminVal) {
errors.throwErr(errors.ERR_NO_CONFIG_DIR);
} else {
filePathVal = tnsAdminVal;
filePathVal += '/tnsnames.ora';
if (!fs.existsSync(filePathVal)) {
errors.throwErr(errors.ERR_TNS_NAMES_FILE_MISSING, tnsAdminVal);
}
}
return filePathVal;
}
}
class NLParamParser {
constructor() {
this.waiters = [];
this.readInProgress = false;
}
/**
* Reads the given file line by line and stores the
* network service names mapped to connect descriptors in the hashtable.
* @param {string} file_path
* @returns {Promise}
*/
async initializeNlpa(file_path) {
if (this.readInProgress) {
await new Promise((resolve) => {
this.waiters.push(resolve);
});
}
if (!this.checkModfTime()) {
/* No File has been modified */
return this.ht;
}
this.ht = new Map();
this.modTime = new Map(); //stores modified time of each IFile
this.readInProgress = true;
await this.start(file_path, 0); //start with 0 depth (tnsnames.ora)
return this.ht;
}
async start(file_path, depth) {
if (depth > MAX_IFILE_DEPTH)
return; //ignore after max depth
const stat = fs.statSync(file_path);
// store file path and its modified time.
this.modTime.set(file_path, stat.mtime);
// Creating a readable stream from file
// readline module reads line by line
// but from a readable stream only.
const file = readline.createInterface({
input: fs.createReadStream(file_path),
output: process.stdout,
terminal: false
});
let nvElem = "";
for await (let line of file) {
if (line.length == 0) { // ignore empty lines
continue;
} else if (line[0] == '#') { // comment line
continue;
} else if ((line[0] == ' ') || // continued input on new line
(line[0] == '\t') ||
(line[0] == ')') ||
(line[0] == '(')) {
line = line.replace(/\s+/g, '');
line = this.checkNLPforComments(line);
if (line.length == 0)
continue;
else {
nvElem = nvElem + line;
}
} else { // new NV Element starting here
if (nvElem.length == 0) {
line = this.checkNLPforComments(line);
nvElem = nvElem + line;
} else if (nvElem.length != 0) {
await this.addNLPListElement(nvElem, depth); // Add Parameter to Hashtable
nvElem = ""; // Clear first, before storing current line
line = this.checkNLPforComments(line);
nvElem = nvElem + line;
}
}
}
if (nvElem.length != 0) { // at eof, still one more parameter to read
await this.addNLPListElement(nvElem, depth);
nvElem = ""; // clear nvElem buffer after added
}
this.readInProgress = false;
let waiter;
while ((waiter = this.waiters.pop())) {
waiter();
}
}
/**
* Given a string, this method looks if the '#' character is present.
* If true, the line is truncated from that point onwards until the end
* of the line; else, the original line is returned unchanged.
*
* @param str The String that is going to be tested for inline comments
* @return String The modified String returned
*/
checkNLPforComments(str) {
const str1 = new Array(str.length);
for (let i = 0; i < str.length; i++) {
const current_char = str[i];
if (current_char == '#') {
if (i != 0) {
break; // No need to continue. Return the line
} else {
// Entire line is a comment
return "";
}
} else
str1.push(current_char);
}
return str1.join('');
}
// check if any of the IFiles has been changed
checkModfTime() {
if (this.modTime) {
for (const [key, value] of this.modTime) {
if (fs.existsSync(key)) {
const stat = fs.statSync(key);
if ((stat.mtime - value > 0)) {
return true;
}
} else
return true;
}
} else {
return true;
}
return false;
}
/**
* adds name value pairs from the input buffer into the hash table.
* @param {string} ibuf
*/
async addNLPListElement(ibuf, depth) {
const res = ibuf.split(/\r?\n/).filter(element => element);
for (let i = 0; i < res.length; i++) {
if (res[i].charAt(0) != '(') {
res[i] = '(' + res[i] + ')';
}
const nvp = createNVPair(res[i]);
const name = nvp.name;
const uname = name.toUpperCase();
nvp.name = uname;
// support for ifile
if (uname == 'IFILE') {
await this.start(nvp.atom, depth + 1);
} else {
const unames = uname.split(","); //multiple aliases (alias1, alias2, alias3)
for (let i = 0; i < unames.length; i++) {
this.ht.set(unames[i], nvp);
}
}
}
}
toString() {
let out = "";
this.ht.forEach((value) => {
out = out + value.toString() + "\n";
});
return out;
}
/**
* if key is address/port then it returns the port value from the
* address NVPAIR.
* @param {string} key
* @returns {string}
*/
findValueOf(key) {
const myarr = key.split('/');
return (findValue(this.ht.get(myarr[0].toUpperCase()), myarr));
}
}
module.exports = {
NLParamParser,
tnsnamesFilePath
};