/* ============LICENSE_START========================================== =================================================================== Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. =================================================================== Unless otherwise specified, all software contained herein is licensed under the Apache License, Version 2.0 (the License); you may not use this software except in compliance with the License. You may obtain a copy of the License at http://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. ============LICENSE_END============================================ */ //.. subnproc.js -to be started by parent server process const fs = require('fs'); const Chproc = require('child_process'); var clName= "subnproc"; var thePid= 0; var taskId= ''; //.. assuming all these files are in CDT_HOME var inpFilePfx= "posted_data_"; var outFilePfx= "sync_template_res_"; //.. processing results var errFilePfx= "sync_template_err_"; //.. error found while processing var parmFilePfx= "template_params_"; var pstatfNamePfx= "proc_status_"; //.. pDlm -delimiter of params // (cant be: alphanumeric,underbar,dollar,dot,comma,brackets,dash,equal sign,etc) var pDlm= '\n'; var logfname= clName+".log"; var logfname_o= logfname+".save"; //.. to keep old content var fdL; var fdIn; var fdOut; var errMsgBadParm= ''; //.. create error message to report to client //var checkSpecialCharsReg= new RegExp(/[^\w\s-]/); var checkSpecialCharsReg= new RegExp(/[^\w\s-\.]/); var doStopOnSpecChars= 'Y'; var doCheckComments= 'Y'; //var SYNC_T_KEY_EXPRES= '\\${.+?\\}'; var VSTART= '${'; var VEND= '}'; var lenVS= VSTART.length, lenVE= VEND.length; var KEY_START= '${('; var KEY_MID= ')=('; var KEY_END= ')}'; var LD= "\n"; //.. LD -line delimeter in the input file var lenLD= LD.length; var percAtRngs= 55; //.. percentage defining report to client var traceLvl= 1; //var CCnt= 52; var CCnt= 2; var taskIdArgstr= process.argv[ 2 ]; var CDT_HOME= process.argv[ 3 ]; var LOG_DIR= process.argv[ 4 ]; this.thePid= process.pid; console.log(clName+": Start: thePid="+this.thePid ); console.log(clName+": CDT_HOME:["+CDT_HOME+"]" ); console.log(clName+": LOG_DIR:["+LOG_DIR+"]" ); try { //.. need renameSync (not asynchronous) ! fs.renameSync( LOG_DIR+"/"+logfname, LOG_DIR+"/"+logfname_o); } catch( err ) { console.log(clName+": log rename error: code="+ err.code ); console.log(clName+": log rename error.msg:["+err.message+"]"); //throw err; }; fs.open( LOG_DIR+"/"+logfname, 'a', (err, fd) => { if( err ) { console.log(clName+": log file open error:"+err.message ); throw err; } this.fdL= fd; console.log(clName+": log opened. fdL="+this.fdL); this.logWr( clName+": Start: thePid="+this.thePid+"\n"); this.logWr( clName+ ": execArgv:["+process.execArgv+"]\n argv:["+process.argv+"]\n"); var indT= taskIdArgstr.indexOf('=', 0); if( indT < 0 ) { // this.logWr(clName+": Error: Failed to extract taskId from args:["+ // taskIdArgstr+"]\n"); // this.taskId= "000"; this.taskId= taskIdArgstr; } else { this.taskId= taskIdArgstr.substr( indT+1 ); } this.logWr(clName+": taskId:["+this.taskId+"]\n"); if( this.taskId == null || this.taskId == undefined || this.taskId.length < 1 ) { var errMsg= clName+": Error: taskId is empty !\n"; console.log( errMsg ); this.logWr( errMsg ); throw new Error( errMsg ); }; this.logWr(clName+": CDT_HOME:["+CDT_HOME+"]\n"); var timeStampI = Date.now(); this.logWr(clName+": timeStampI="+timeStampI+" \n"); var timeStamp = new Date( timeStampI ).toISOString(); this.logWr(clName+": timeStamp:["+timeStamp+"]\n"); //.. setup callback waiting for message from parent // process.on('message', (msg) => { // console.log('subnp: got message:', msg); // }); //this.logWr("subnp: sending msg to parent.\n"); // var msg2parent = { taskid: taskId }; // this.logWr("subnp: msg2parent:["+JSON.stringify(msg2parent)+"]\n"); // process.send( msg2parent ); var inpFile= CDT_HOME+"/"+ inpFilePfx +this.taskId +".txt"; this.logWr(clName+": opening inpFile for reading:["+inpFile+"]\n"); fs.open( inpFile, 'r', (err, fd0) => { if( err ) { console.log(clName+": inpFile file open: Error: code="+err.code ); this.logWr(clName+": inpFile file open: Error: code="+err.code+"\n"); throw err; } this.fdIn= fd0; console.log(clName+": Input file opened. fdIn="+this.fdIn); fs.readFile( this.fdIn, (err, data) => { if( err ) { console.log(clName+": Failed to read inpFile: Error: code="+err.code ); this.logWr(clName+": Failed to read inpFile: Error: code="+err.code+"\n"); throw err; } this.processData( data ); //.. close log console.log(clName+": close: fdL="+this.fdL ); fs.closeSync( this.fdL ); this.fdL= -1; }); }); }); exports.processData = function ( data ) { //.. processing data content from already opened input file var methName= "processData"; this.logWr(methName+": start...\n"); var timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); var fcontStr= new String( data ); let fcontLen= fcontStr.length; this.logWr(methName+": fcontLen="+fcontLen+"\n"); this.logWr(methName+": trying to close inpFile: fdIn="+this.fdIn+"\n"); fs.closeSync( this.fdIn ); this.logWr(methName+": inpFile closed.\n"); var pstatfName= CDT_HOME+"/"+ pstatfNamePfx +this.taskId+".json"; var percent= 1; var stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatfName, stmsg ); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); var perrorfName= CDT_HOME+"/"+ errFilePfx+ this.taskId+".txt"; var formatErr= ''; var lineEnds= new Array( 0 ); //.. indexes of new-line chars var selecRanges= new Array( 0 ); //.. indexes of ${variables} var parmNamVals= new Map(); //.. parameter Name-Value pairs from inside ${...} var ind0= 0; var ind1= fcontStr.indexOf( LD,ind0 ); //.. line delimeter var rn= 0, li= 0; while( ind1 > -1 ) { lineEnds.push( ind1 ); this.logWr( methName+":--line #:"+li+" beg: ind0="+ind0+" end: ind1="+ind1+ " array:"+lineEnds[li]+"\n"); var line0= fcontStr.substring( ind0, ind1 ); //.. not including LD var liLen= line0.length; this.logWr( methName+": liLen="+liLen+"\n"); if( liLen > 60 ) { this.logWr( methName+": line(p):["+line0.substr(0,60)+"]\n"); } else { this.logWr( methName+": line:["+line0+"]\n"); } //.. look for ${param variables} rn= this.getRangesForVars( line0, li, rn, selecRanges ); if( rn < 0 ) { this.logWr( methName+": got Error:\n["+errMsgBadParm+"]"); this.reportParamBadFmt( li, '', errMsgBadParm, perrorfName, pstatfName ); this.logWr( methName+": Stopping processing !\n"); return; } if( traceLvl > 1 ) this.logWr( methName+": added ranges at li="+li+": next rn="+rn+"\n"); ind0= ind1 +lenLD; //.. for next search of LD if( ind0 >= fcontLen ) { break; }; li++; ind1= fcontStr.indexOf( LD,ind0 ); //.. line delimeter }; //.. loop //.. process the last line if( ind0 < fcontLen ) { this.logWr( methName+": have the last line: ind0="+ind0+"\n"); lineEnds.push( fcontLen ); var line0= fcontStr.substring( ind0 ); //.. up to the end var liLen= line0.length; this.logWr( methName+": liLen="+liLen+"\n"); if( liLen > 60 ) { this.logWr( methName+": line(p):["+line0.substr(0,60)+"]\n"); } else { this.logWr( methName+": line:["+line0+"]\n"); } //.. look for ${param variables} rn= this.getRangesForVars( line0, li, rn, selecRanges ); if( rn < 0 ) { this.logWr( methName+": got Error in getRangesForVars:\n["+ errMsgBadParm+"]"); this.reportParamBadFmt( li, '', errMsgBadParm, perrorfName, pstatfName ); this.logWr( methName+": Stopping processing !\n"); return; } }; this.logWr( methName+": -=- lineEnds array length="+lineEnds.length+"\n"); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); percent= percAtRngs; stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatfName, stmsg ); //.. Cycle through Ranges this.logWr( methName+": selecRanges array length="+selecRanges.length+"\n"); if( doCheckComments ) { this.logWr( methName+": doCheckComments is True.\n"); } else { this.logWr( methName+": doCheckComments is False\n"); }; var rnAtUpd= Math.floor( selecRanges.length/ 3.); var percStep= (100.0 - percAtRngs); this.logWr( methName+": range number for proc.status update="+rnAtUpd+ "\n percentage step="+percStep ); var outLinBuf= new Array( 0 ); //.. array of output lines var outLnLast=-1; //.. last processed var rngLnLast=-1; for( var rn0=0; rn0 < selecRanges.length; rn0++ ) { var rng= selecRanges[rn0]; this.logWr( methName+":--- range #:"+rn0+" lineNm="+rng.lineNm+ " colBg="+rng.colBg+" colEn="+rng.colEn+"\n"); this.logWr( methName+": outLnLast="+outLnLast+"\n"); if( rn0 > 0 && (rn0 % rnAtUpd) == 0 && rn0 < selecRanges.length -rnAtUpd ) { percent= Math.floor( percAtRngs + percStep *(rn0/selecRanges.length) ); this.logWr( methName+": need to update proc.status: percent="+percent+"\n"); stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatfName, stmsg ); }; rngLnLast= rng.lineNm; //.. prepare previous lines with no ranges if( rng.lineNm - outLnLast > 1 ) { this.logWr( methName+": prepare previous lines...\n"); var plinNm0= outLnLast +1; var plinesIndB= 0; if( plinNm0 > 0 ) { plinesIndB= lineEnds[outLnLast] + lenLD; }; var plinesIndE= lineEnds[rng.lineNm -1] + lenLD; this.logWr( methName+": plinesIndB="+plinesIndB+ " plinesIndE="+plinesIndE+"\n"); var plinStr= fcontStr.substring( plinesIndB, plinesIndE ); if( traceLvl > 1 ) { if( plinStr.length > 60 ) { this.logWr( methName+": plinStr(p):["+plinStr.substr(0, 60)+"]\n"); } else { this.logWr( methName+": plinStr:["+plinStr+"]\n"); } }; outLinBuf.push( plinStr ); outLnLast= rng.lineNm -1; }; var linIndB= 0; var linIndE= lineEnds[rng.lineNm]; if( rng.lineNm > 0 ) { linIndB= lineEnds[rng.lineNm - 1] + lenLD; }; var linLen= linIndE - linIndB; var line0= fcontStr.substr( linIndB, linLen ); this.logWr( methName+": linIndB="+linIndB+" linIndE="+linIndE+ " line length="+linLen+"\n"); if( traceLvl > 1 ) { if( linLen > 60 ) { this.logWr( methName+": line0(p):\n["+line0.substr(0,60)+"]\n"); } else { this.logWr( methName+": line0:\n["+line0+"]\n"); } }; //.. content between ${ and } var vword= line0.substring( rng.colBg+lenVS, rng.colEn+1-lenVE ); this.logWr( methName+": vword:["+vword+"]\n"); //.. try to check for (pvalue)=(pname) let specialKeys= null; var parmNamAndVal= Array( 0 ); var pName= null; var pValue= null; formatErr= this.parseParmValAndName( vword, parmNamAndVal ) if( formatErr ) { this.reportParamBadFmt( rng.lineNm, vword, formatErr, perrorfName, pstatfName ); this.logWr( methName+": Stopping processing !\n"); return; } //.. No errors - parsing done OK pName= parmNamAndVal[0]; //.. to be added to parmNamVals pValue= parmNamAndVal[1]; this.logWr( methName+": parsing done: param.name:["+ pName+"] value:["+pValue+"]\n"); if( pName != null && pName.length > 0 ) { this.logWr( methName+": check spec.chars in Non empty pName.\n"); specialKeys= checkSpecialCharsReg.exec( pName ); if( specialKeys == null ) { this.logWr( methName+": specialKeys obj is null\n"); } else if( specialKeys.length > 0 ) { this.logWr( methName+": specialKeys obj Not null:["+specialKeys+ "] length="+specialKeys.length+"\n"); if( doStopOnSpecChars ) { formatErr= "The parameter name("+pName+") contains prohibited character(s):("+ specialKeys+") !"; this.logWr( methName+": formatErr:["+formatErr+"]\n"); this.reportParamBadFmt( rng.lineNm, vword, formatErr, perrorfName, pstatfName ); this.logWr( methName+": Stopping processing !\n"); return; }; }; }; var haveComment= ''; if( doCheckComments ) { this.logWr( methName+": doCheckComments is True.\n"); if( line0.trim().startsWith("//") ) haveComment= 'Y'; }; if( haveComment ) { this.logWr( methName+": haveComment is True !\n"); }; //.. prepare parameter name and value if( pName != null && pName.length > 0 && !specialKeys && !haveComment ) { this.logWr( methName+": checking non-empty param.name:["+pName+"]\n"); if( parmNamVals.has(pName) ) { this.logWr( methName+": the param. is already accounted.\n"); } else { this.logWr( methName+": adding new param. with value:["+pValue+"]\n"); parmNamVals.set( pName, pValue ); }; }; //.. prepare for template output var colB= 0; if( rn0 > 0 ) { var rngP= selecRanges[rn0 - 1]; if( rngP.lineNm == rng.lineNm ) { colB= rngP.colEn+lenVE; }; }; var colE= rng.colEn; //.. check range content for replacement let checkApplForNamOn= this.checkAppliedForNamesOnly( line0, rng.colBg, rng.colEn ); this.logWr( methName+": checkApplForNamOn:["+checkApplForNamOn+"]\n"); if( checkApplForNamOn && !specialKeys && !haveComment ) { this.logWr( methName+": Need Name Replacement... \n"); var replacWrd= KEY_START +KEY_MID +vword +KEY_END; // ${()=(...)} this.logWr( methName+": replacWrd:["+replacWrd+"]\n"); var colM= rng.colBg; //.. not including beginning of VSTART var brngStr= line0.substring( colB, colM ); this.logWr( methName+": part before word:["+brngStr+"]\n"); outLinBuf.push( brngStr + replacWrd ); } else { this.logWr( methName+": No Replacement for this range !\n"); var rsubs= line0.substring( colB, colE+lenVE ); this.logWr( methName+": rsubs:["+rsubs+"]\n"); outLinBuf.push( rsubs ); }; outLnLast= rng.lineNm; //.. check tail of the line if( rn0 == selecRanges.length - 1 ) { var tailStr= line0.substring(colE+lenVE) + LD; this.logWr( methName+": last range: adding line tail:\n["+tailStr+"]\n"); outLinBuf.push( tailStr ); } else { //.. not the last range var rngN= selecRanges[rn0 + 1]; if( rngN.lineNm == rng.lineNm ) { //.. next range on the same line - no tail yet } else { //.. next range on different line var tailStr= line0.substring(colE+lenVE) + LD; this.logWr( methName+": adding line tail:\n["+tailStr+"]\n"); outLinBuf.push( tailStr ); }; }; }; //... loop if( rngLnLast < lineEnds.length - 1) { this.logWr( methName+": adding last lines having no ranges...\n"); var llinesIndB= 0; if( rngLnLast > 0 ) { llinesIndB= lineEnds[rngLnLast] + lenLD; }; var llinesIndE= lineEnds[lineEnds.length -1] + lenLD; this.logWr( methName+": llinesIndB="+llinesIndB+ " llinesIndE="+llinesIndE+"\n"); var llinStr= fcontStr.substring( llinesIndB, llinesIndE ); if( traceLvl > 1 ) { if( llinStr.length > 60 ) { this.logWr( methName+": llinStr(p):\n["+llinStr.substr(0,60)+"]\n"); } else { this.logWr( methName+": llinStr:["+llinStr+"]\n"); } } outLinBuf.push( llinStr ); }; this.logWr( methName+": -=- outLinBuf: array length="+outLinBuf.length+"\n"); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); var outFile= CDT_HOME+"/"+ outFilePfx+ this.taskId+".txt"; var outFile_o= outFile+".save"; try { fs.renameSync( outFile, outFile_o ); } catch( err ) { this.logWr(clName+": old output file rename: error:["+err.message+"]\n"); // throw err; }; try { this.fdOut= fs.openSync( outFile, 'a' ); } catch( err ) { this.logWr(clName+": output file open: error:["+err.message+"]\n"); throw err; } this.logWr(methName+": output file opened: fdOut="+this.fdOut+"\n"); for( let outLine of outLinBuf ) { try { fs.appendFileSync( this.fdOut, outLine, 'utf8' ); } catch( err ) { this.logWr(clName+": output file append: error: code="+err.code ); throw err; } }; //... loop this.logWr(methName+": closing output file: fdOut="+this.fdOut+"\n"); fs.closeSync( this.fdOut ); this.logWr(methName+": output file closed.\n"); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); this.logWr( methName+": -=- parmNamVals (Parameters): map.size="+ parmNamVals.size+"\n"); var parmFile= CDT_HOME+"/"+ parmFilePfx+ this.taskId+".txt"; var parmFile_o= parmFile+".save"; try { fs.renameSync( parmFile, parmFile_o ); } catch( err ) { this.logWr(clName+": old Params file rename: error:["+err.message+"]\n"); // throw err; }; try { this.fdParm= fs.openSync( parmFile, 'a' ); } catch( err ) { this.logWr(clName+": Params file open: error:["+err.message+"]\n"); throw err; }; this.logWr(methName+": Params file opened: fdParm="+this.fdParm+"\n"); //.. writing parameters into parameter-output file try { // fs.appendFileSync( this.fdParm, "[\n", 'utf8' ); var iw= 0; for( let pnm of parmNamVals.keys() ) { let pv= parmNamVals.get( pnm ); let pnv= pnm+"="+pv; this.logWr( methName+": iw="+iw+" param.Name-Value:["+pnv+"]\n"); //.. need delimiter after each item ! fs.appendFileSync( this.fdParm, pnv+pDlm, 'utf8' ); iw++; }; //... loop // fs.appendFileSync( this.fdParm, "]", 'utf8' ); } catch( err ) { this.logWr(clName+": Params file append: error: code="+err.code ); throw err; } this.logWr(methName+": closing Params file: fdParm="+this.fdParm+"\n"); fs.closeSync( this.fdParm ); this.logWr(methName+": Params file closed.\n"); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); percent= 100; stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatfName, stmsg ); //.. simulated updates /* for( var i1=0; i1 < this.CCnt; i1++ ) { this.wait( 2 ); percent += 2; if( percent > 100 ) { percent= 100; }; stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatfName, stmsg ); }; this.wait( 1 ); */ this.logWr(methName+": finishing.\n"); timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); }; exports.checkAppliedForNamesOnly = function( line, colBg, colEn ) { var methName= "checkAppliedForNamesOnly"; this.logWr( methName+": start: colBg="+colBg+" colEn="+colEn+"\n"); if( traceLvl > 1 ) { if( line.length > 60 ) { this.logWr( methName+": line(p):\n["+line.substr(0,60)+"]\n"); } else { this.logWr( methName+": line:\n["+line+"]\n"); } }; this.logWr( methName+": check for: KEY_START:["+KEY_START+"]\n"); var lenKS= KEY_START.length; var indMax= colBg + lenKS var subline= line.substring( 0, indMax ); var indKS= subline.lastIndexOf( KEY_START, subline.length ); //.. ${( if( indKS < 0 ) { if( traceLvl > 1 ) this.logWr( methName+": No KEY_START at all - return true.\n"); return true; //.. no KEY_START at all } else { //.. have KEY_START, check KEY_END this.logWr( methName+": check for: KEY_END:["+KEY_END+"]\n"); indMax= colBg + KEY_END.length; subline= line.substring( indKS +lenKS, indMax ); var indKE= subline.indexOf( KEY_END, 0 ); //.. )} if( indKE < 0 ) { if( traceLvl > 1 ) this.logWr( methName+": Only KEY_START there - return false.\n"); return false; //..only KEY_START there } else { if( traceLvl > 1 ) this.logWr( methName+": Have both - return true.\n"); return true; //.. have both: KEY_START and then KEY_END } } } exports.getRangesForVars = function( line, lnum, rnum, selRangesArr ) { var methName= "getRangesForVars"; this.logWr( methName+": start: lnum="+lnum+" rnum="+rnum+"\n"); if( traceLvl > 0 ) { if( line.length > 60 ) { this.logWr( methName+": line(p):["+line.substr(0,60)+"]\n"); } else { this.logWr( methName+": line:["+line+"]\n"); } }; var haveComment= ''; if( line.trim().startsWith("//") ) haveComment= 'Y'; //.. look for ${variables} var indV0= 0; var indV1= line.indexOf( VSTART, indV0 ); while( indV1 > -1 ) { var indB= indV1; indV0= indB + 1; indV1= line.indexOf( VEND, indV0 ); if( indV1 < 0 ) { errMsgBadParm= methName+": Parameter ending delimiter ("+VEND+ ") not found in line #="+lnum+" after pos.#="+indV0+" !\n" this.logWr( "Error: "+errMsgBadParm); if( ! haveComment ) { return -1; } else { //.. haveComment - do not stop processing this.logWr( methName+": This line is commented out -ignore the error."); break; }; }; var indE= indV1 + lenVE-1; //.. check for VSTART inside the range (must find either old or new one) indB= line.lastIndexOf( VSTART, indE ); this.logWr( methName+": found a ${param} at:"+indB+" - "+indE+"\n"); //.. lineNm - line number in the input file //.. colBg - begin index of VSTART //.. colEn - after end index of VEND (both within the line) var range = { lineNm: lnum, colBg: indB, colEn: indE }; selRangesArr.push( range ); this.logWr( methName+": range #:"+rnum+ " param.string:["+JSON.stringify(selRangesArr[rnum])+"]\n"); rnum++; indV0= indV1 + lenVE; indV1= line.indexOf( VSTART, indV0 ); }; return rnum; }; //.. assuming the word format is like: "(value)=(name)" or "name" // returning error message or empty string (which means no errors) exports.parseParmValAndName = function( word, parmNamAndVal ) { var methName= "parseParmValAndName"; this.logWr( methName+": start: input word:["+word+"]\n"); var lenW= word.length; var errorMsg= ''; if( traceLvl > 0 ) this.logWr( methName+": word length="+lenW+"\n"); if( lenW < 1 ) { errorMsg= methName+": the parameter string is empty !\n"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg ); return errorMsg; }; var lastCh= lenW - 1; var OBR= '('; var lenOBR= OBR.length; var CBR= ')'; var lenCBR= CBR.length; var EQS= '='; var lenEQS= EQS.length; var name, val; var ic0= 0; var ic1= word.indexOf( OBR, ic0 ); if( ic1 < 0 ) { if( traceLvl > 0 ) this.logWr( methName+": no open round brackets -assuming the word has "+ "param.name only.\n"); parmNamAndVal.push( word ); parmNamAndVal.push( '' ); return ''; //.. empty errorMsg means OK }; //.. got 1-st open round bracket if( traceLvl > 0 ) this.logWr( methName+": found 1-st open round bracket at:"+ic1+"\n"); if( ic1 > 0 ) { errorMsg= methName+": Unexpected chars before open round bracket at:"+ic1+"\n"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg ); return errorMsg; }; ic0= ic1 + lenOBR; if( ic0 >= lastCh ) { errorMsg= methName+": missing next expected round brackets after pos.#="+ic1+ " -bad format\n"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg ); return errorMsg; }; var ic2= word.indexOf( CBR, ic0 ); if( ic2 < 0 ) { errorMsg= methName+": no closing round bracket after 1-st open bracket -bad format\n"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg ); return errorMsg; }; //.. got 1-st closing round bracket (after Value) if( traceLvl > 0 ) this.logWr( methName+": found 1-st closing round bracket at:"+ic2+"\n"); val= word.substring( ic0, ic2 ); if( traceLvl > 0 ) this.logWr( methName+": got val:["+val+"]\n"); ic0= ic2 + lenCBR; if( ic0 >= lastCh ) { errorMsg= methName+": missing next expected round brackets after pos.#="+ic2+ " -bad format\n"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg ); return errorMsg; }; var ic3= -1; if( word.substr(ic0).startsWith(EQS) ) { //.. found EQS ic3= ic0; } else { errorMsg= methName+": no equal sign after 1-st closing round bracket at pos.#="+ic2+ " -bad format"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg+"\n" ); return errorMsg; }; //.. got Equal sign after 1-st closing round bracket ic0= ic3 + lenEQS; if( ic0 >= lastCh ) { errorMsg= methName+": missing next expected round brackets after pos.#="+ic3+ " -bad format"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg+"\n" ); return errorMsg; }; var ic4= -1; if( word.substr(ic0).startsWith(OBR) ) { //.. found ic4= ic0; } else { errorMsg= methName+": no 2-nd open round bracket after equal sign at pos.#="+ic3+ " -bad format"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg+"\n" ); return errorMsg; }; //.. got 2-nd open round bracket ic0= ic4 + lenOBR; if( ic0 >= lastCh ) { errorMsg= methName+": missing next expected round bracket after pos.#="+ic4+ " -bad format"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg+"\n" ); return errorMsg; }; var ic5= word.indexOf( CBR, ic0 ); if( ic5 < 0 ) { errorMsg= methName+": no 2-nd closing round bracket after 2-nd open bracket at pos.#="+ ic4+" -bad format"; errMsgBadParm= errorMsg; this.logWr( "Error: "+errorMsg+"\n" ); return errorMsg; }; //.. got 2-nd closing round bracket // (also assuming the remaining chars are whitespaces) parmNamAndVal.push( word.substring(ic0, ic5) ); parmNamAndVal.push( val ); if( traceLvl > 1 ) this.logWr( methName+": got param: name:["+parmNamAndVal[0]+"]\n value:["+ parmNamAndVal[1]+"]\n"); return ''; //.. empty error message means OK }; exports.reportParamBadFmt = function ( lineNm, pword, formatErr, perrorFName, pstatFName ) { var methName= "reportParamBadFmt"; this.logWr( methName+": start: the param.name-value format is bad -Error!\n"); this.logWr( methName+": signalling error via percent = -1 \n"); var percent=-1; var stmsg= '{\"percentage\":'+percent+'}'; this.updateProcStatus( pstatFName, stmsg ); this.logWr( methName+": writing the error message into a file "+ "for next request from the server..."); procErrorMsg= "Error: Bad Format of the parameter string"; if( pword != null && pword.length > 0 ) { procErrorMsg += ":["+pword+"]"; }; var lineNmE= lineNm + 1; //.. line numbering in screen editor starts from 1 procErrorMsg += "\n Error found at line #:"+lineNmE; procErrorMsg += "\n Error Details:["+formatErr+"]"; procErrorMsg += "\n Please, correct the error and try again."; //.. using updateProcStatus to save the error message in a file this.updateProcStatus( perrorFName, procErrorMsg ); }; exports.logWr = function ( msg ) { // console.log(clName+": logWr: fdL="+this.fdL+" msg:["+msg+"]"); try { fs.appendFileSync( this.fdL, msg, 'utf8' ); } catch( err ) { console.log(clName+": log uppend: error:"+err.message ); throw err; }; // fs.appendFile( this.fdL, msg, 'utf8', (err) => { // if( err ) { // throw err; // } // }); }; //.. processing percentage or error message exports.updateProcStatus = function ( pstfname, statusMsg ) { var methName= "updateProcStatus"; this.logWr(methName+": start: pstfname:["+pstfname+"]\n"); var pstfname_p= pstfname+".pre"; this.logWr(methName+": new status: message["+statusMsg+"]\n"); var timeStamp = new Date().toISOString(); this.logWr( methName+": timeStamp:["+timeStamp+"]\n"); //.. pre-file try { this.fdPSt= fs.openSync( pstfname_p, 'a' ); } catch( err ) { this.logWr(clName+": status file open: error:["+err.message+"]\n"); throw err; } this.logWr(methName+": writing status: fdPSt="+this.fdPSt+"\n"); try { fs.appendFileSync( this.fdPSt, statusMsg, 'utf8' ); } catch( err ) { this.logWr(clName+": status file append: error: code="+err.code ); throw err; } this.logWr(methName+": closing status file: fdPSt="+this.fdPSt+"\n"); fs.closeSync( this.fdPSt ); this.logWr(methName+": status file closed - final renaming...\n"); fs.renameSync( pstfname_p, pstfname ); this.logWr(methName+": status file renamed - finished.\n"); }; exports.wait = function ( secs ) { var methName= "wait"; this.logWr(methName+": start: secs="+secs+"\n"); var inStr= String( secs ); // this.logWr(methName+": inStr:["+inStr+"]\n"); var s_args= new Array( 0 ); s_args.push( inStr ); var tmoutms= 500 +1000*secs; var mopts= { timeout: tmoutms }; // this.logWr(methName+": mopts:["+ JSON.stringify(mopts)+"]\n"); var moutObj= Chproc.spawnSync( 'sleep', s_args, mopts); this.logWr(methName+": moutObj: status:["+moutObj.status+"](0=ok)\n"); if( moutObj.error != null ) { console.log(methName+": moutObj: Error:["+JSON.stringify(moutObj.error)+"]\n"); } };