From 18510891e2ebcaf6f139db704f83b4ba67f1c149 Mon Sep 17 00:00:00 2001 From: Taka Cho Date: Tue, 14 May 2019 17:37:24 -0400 Subject: add node.js api server for CDT /api call need node.js api server to fix when clicking the Synchronize Definition Parameter. Change-Id: I4a3fd1ba045ed41fb2fdfec3b8f0364cd6ec05f5 Issue-ID: APPC-1600 Signed-off-by: Taka Cho --- Dockerfile | 56 --- package.json | 6 +- protractor.conf.js | 1 - src/app/deleteOldData.js | 117 +++++++ src/app/ndserver.js | 255 ++++++++++++++ src/app/server-data-svc.js | 656 +++++++++++++++++++++++++++++++++++ src/app/srvlogger.js | 96 ++++++ src/app/subnproc.js | 840 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1967 insertions(+), 60 deletions(-) delete mode 100644 Dockerfile create mode 100644 src/app/deleteOldData.js create mode 100644 src/app/ndserver.js create mode 100644 src/app/server-data-svc.js create mode 100755 src/app/srvlogger.js create mode 100644 src/app/subnproc.js diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 00dba2c..0000000 --- a/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ - -# ============LICENSE_START========================================== -#=================================================================== -#Copyright (C) 2018 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. - -#ECOMP is a trademark and service mark of AT&T Intellectual Property. -#============LICENSE_END============================================ - -### STAGE 1: Build ### - -# We label our stage as 'builder' -FROM node:8-alpine as builder - -COPY package.json . - -RUN npm set progress=false && npm config set depth 0 && npm cache clean --force - -## Storing node modules on a separate layer will prevent unnecessary npm installs at each build -RUN npm i && mkdir /ng-app && cp -R ./node_modules ./ng-app - -WORKDIR /ng-app - -COPY . . - -## Build the angular app in production mode and store the artifacts in dist folder -RUN $(npm bin)/ng build --env=prod - - -### STAGE 2: Setup ### - -FROM nginx:1.13.3-alpine - -## Copy our default nginx config -COPY nginx/default.conf /etc/nginx/conf.d/ - -## Remove default nginx website -RUN rm -rf /usr/share/nginx/html/* - -## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder -COPY --from=builder /ng-app/dist /usr/share/nginx/html - -CMD ["nginx", "-g", "daemon off;"] diff --git a/package.json b/package.json index 6771223..d06bc02 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "devBuild": "ng build", "dev3Build": "ng b --env=dev3 --aot=false", "dev4Build": "ng build --env=dev4 --aot=false" - }, + }, "private": true, "dependencies": { "@angular/animations": "^4.0.0", @@ -36,11 +36,13 @@ "file-saver": "^1.3.3", "font-awesome": "^4.7.0", "jquery": "^3.2.1", + "karma-remap-istanbul": "^0.6.0", "mdbootstrap": "4.5.5", "ng2-ace-editor": "0.2.0", "ng2-bootstrap-modal": "1.0.1", "ng2-bs3-modal": "0.10.4", "ngx-progressbar": "^2.1.1", + "ngx-cookie-service": "^2.1.0", "popper.js": "^1.12.1", "roboto-fontface": "^0.8.0", "rxjs": "5.4.1", @@ -51,7 +53,6 @@ "yamljs": "0.2.10", "zone.js": "^0.8.14", "ngx-spinner": "^1.2.0" - }, "devDependencies": { "@angular/cli": "1.2.3", @@ -64,7 +65,6 @@ "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.1.1", - "karma-remap-istanbul": "^0.6.0", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-firefox-launcher": "^1.1.0", diff --git a/protractor.conf.js b/protractor.conf.js index efb1afa..e408810 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -17,7 +17,6 @@ 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. -ECOMP is a trademark and service mark of AT&T Intellectual Property. ============LICENSE_END============================================ */ // Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts diff --git a/src/app/deleteOldData.js b/src/app/deleteOldData.js new file mode 100644 index 0000000..f219633 --- /dev/null +++ b/src/app/deleteOldData.js @@ -0,0 +1,117 @@ +/* +============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============================================ */ +//... deleteOldData.js - to be started by parent server process +const fs = require('fs'); + +var logger = require('./srvlogger'); + +var clName= "deleteOldData"; +var cdt_home = "."; + + this.thePid= process.pid; + console.log(clName+": thePid="+this.thePid ); + + console.log(clName+ + ": execArgv:["+process.execArgv+"]\n argv:["+process.argv+"]"); + var taskIdArgstr= process.argv[ 2 ]; + var CDT_HOME= process.argv[ 3 ]; + var LOG_DIR= process.argv[ 4 ]; + console.log( clName+": argv: CDT_HOME:["+CDT_HOME+"]" ); + var LogF= LOG_DIR+"/ndserver.log"; + logger.addLog( clName+": start: CDT_HOME:["+CDT_HOME+"]\n",LogF); + + var indT= taskIdArgstr.indexOf('=', 0); + if( indT < 0 ) { + this.taskId= taskIdArgstr; + } else { + this.taskId= taskIdArgstr.substr( indT+1 ); + } + console.log(clName+": taskId:["+this.taskId+"]\n"); + logger.addLog( clName+": taskId:["+this.taskId+"]\n",LogF); + if( this.taskId == null || this.taskId == undefined || this.taskId.length < 1 ) + { + var errMsg= clName+": Error: taskId is empty !\n"; + console.log( errMsg ); + throw new Error( errMsg ); + }; + var inpFilePfx= CDT_HOME+"/posted_data_"; + var outFilePfx= CDT_HOME+"/sync_template_res_"; + var parmFilePfx= CDT_HOME+"/template_params_"; + var pstatfNamePfx= CDT_HOME+"/proc_status_"; + + let timeStamp = new Date().toISOString(); + // console.log(clName+": timeStamp:["+timeStamp+"]\n"); + logger.addLog( clName+": timeStamp:["+timeStamp+"]\n",LogF); + + var inpFile= inpFilePfx +this.taskId +".txt"; + // console.log(clName+": deleting inpFile:\n"+inpFile ); + logger.addLog( clName+": deleting inpFile:\n"+inpFile+"\n",LogF); + + fs.unlink( inpFile, (err) => { + if( err) { + console.log(clName+ + ": Error while deleting "+inpFile+"\n "+err.message+"]\n"); + } + }); + + timeStamp = new Date().toISOString(); + console.log(clName+": timeStamp:["+timeStamp+"]\n"); + + var pstatfName= pstatfNamePfx +this.taskId+".json"; + console.log(clName+": deleting proc.status File:\n"+pstatfName ); + + fs.unlink( pstatfName, (err) => { + if( err) { + console.log(clName+ + ": Error while deleting "+pstatfName+"\n "+err.message+"]\n"); + } + }); + + timeStamp = new Date().toISOString(); + console.log(clName+": timeStamp:["+timeStamp+"]\n"); + + var outFile= outFilePfx+ this.taskId+".txt"; + console.log(clName+": deleting proc.result File:\n"+outFile ); + + fs.unlink( outFile, (err) => { + if( err) { + console.log(clName+ + ": Error while deleting "+outFile+"\n "+err.message+"]\n"); + } + }); + + timeStamp = new Date().toISOString(); + console.log(clName+": timeStamp:["+timeStamp+"]\n"); + + var parmFile= parmFilePfx+ this.taskId+".txt"; + console.log(clName+": deleting parameters File:\n"+parmFile+"]\n"); + + fs.unlink( parmFile, (err) => { + if( err) { + console.log(clName+ + ": Error while deleting "+parmFile+"\n "+err.message+"]\n"); + } + }); + + timeStamp = new Date().toISOString(); + console.log(clName+": timeStamp:["+timeStamp+"]\n"); + + console.log(clName+": finish."); diff --git a/src/app/ndserver.js b/src/app/ndserver.js new file mode 100644 index 0000000..5bbf0da --- /dev/null +++ b/src/app/ndserver.js @@ -0,0 +1,255 @@ +/* +============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============================================ */ +var express = require('express'); +var app = express(); +var https = require('https'); +var fs = require('fs'); + +const options = { + key: fs.readFileSync(process.env.HTTPS_KEY_FILE), + cert: fs.readFileSync(process.env.HTTPS_CERT_FILE) +}; + +var bodyParser = require('body-parser'); +var textParser = bodyParser.text({ type: 'text/*' }); + +const fs = require('fs'); + +const path = require('path'); + +const PORT = process.env.PORT || 8080; +const CDT_HOME= process.env.CDT_HOME; +const LOG_DIR= process.env.LOG_DIR; +const MaxLogSize= process.env.MaxLogSize || 3000000; +//const DIST_FOLDER = path.join(process.cwd(), 'dist'); +//const DIST_FOLDER = path.join( CDT_HOME, 'dist'); +const LogF = path.join( LOG_DIR, 'ndserver.log' ); + +var chproc = require("child_process"); + +//var serverDataSvc = require('./dist/server-data-svc'); +var serverDataSvc = require('./server-data-svc'); +var logger = require('./srvlogger'); + +app.get('/getUserRole*', (req, res) => { + console.log(`get: Start: /getUserRole/* route...`); + logger.addLog("get: Start: /getUserRole/* route...\n",LogF); + if( CDT_HOME != null ) { + logger.addLog("get: CDT_HOME:["+CDT_HOME+"]\n",LogF); + }; + var respData= serverDataSvc.getUserRoles( req.url ); + logger.addLog("get: /getUserRole/*: typeof response:["+ + (typeof respData)+"]\n",LogF); + + logger.addLog("get: /getUserRole/*: stringify respData:["+ + JSON.stringify(respData).substr(0,300)+"...]\n",LogF); + if( respData.length != null && respData.length != undefined ) { + logger.addLog("get: /getUserRole/*: respData.length="+ + respData.length+"\n",LogF); + } else { + logger.addLog("get: /getUserRole/*: respData.length not defined !\n",LogF); + }; + res.status(200).send( respData ); + let timeStamp = new Date().toISOString(); + logger.addLog("get: done: timeStamp:["+timeStamp+"]\n",LogF); +}); + +app.get('/api/*', (req, res) => { + console.log(`get: Start: /api/* route...`); + logger.addLog("get: Start: /api/* route...\n",LogF); + if( req.url == null ) { + console.log("get: /api/*: req.url is null !"); + logger.addLog("get: /api/*: req.url is null !\n",LogF); + } + else { + // console.log("get: /api/*: req.url:["+ req.url+"]"); + logger.addLog("get: /api/*: req.url:["+ req.url+"]\n",LogF); + }; + if( req.hostname == null ) { + console.log("get: /api/*: req.hostname is null !"); + logger.addLog("get: /api/*: req.hostname is null !\n",LogF); + } + else { + // console.log("get: /api/*: req.hostname:["+ req.hostname+"]"); + logger.addLog("get: /api/*: req.hostname:["+ req.hostname+"]\n",LogF); + }; + if( req.params != null ) { + // console.log("get: /api/*: Have req.params ..."); + logger.addLog("get: /api/*: Have req.params ...\n",LogF); + if( req.params.length != null ) { + // console.log("get: /api/*: req.params.length="+req.params.length ); + logger.addLog("get: /api/*: req.params.length="+req.params.length+"\n",LogF); + } + }; + if( req.socket != null ) { + // console.log("get: /api/*: Have req.socket ..."); + logger.addLog("get: /api/*: Have req.socket ...\n",LogF); + if( req.socket.remoteAddress != null ) { + // console.log("get: /api/*: remoteAddress:["+ req.socket.remoteAddress+"]"); + logger.addLog( + "get: /api/*: remoteAddress:["+ req.socket.remoteAddress+"]\n",LogF); + } + else { + console.log("get: /api/*: req.socket.remoteAddress is null !"); + logger.addLog("get: /api/*: req.socket.remoteAddress is null !\n",LogF); + } + }; + if( CDT_HOME != null ) { + logger.addLog("get: CDT_HOME:["+CDT_HOME+"]\n",LogF); + }; + var respData= serverDataSvc.getData( req.url ); + logger.addLog("get: /api/*: typeof response:["+(typeof respData)+"]\n",LogF); + if( typeof respData == "string" ) { + logger.addLog("get: /api/*: respData:length="+respData.length+"\n",LogF); + }; + logger.addLog("get: /api/*: stringify respData:["+ + JSON.stringify(respData).substr(0,300)+"...]\n",LogF); + if( respData.length != null && respData.length != undefined ) { + logger.addLog("get: /api/*: respData.length="+respData.length+"\n",LogF); + } else { + logger.addLog("get: /api/*: respData.length not defined !\n",LogF); + }; + res.status(200).send( respData ); + let timeStamp = new Date().toISOString(); + logger.addLog("get: /api/* done: timeStamp:["+timeStamp+"]\n\n",LogF); +}); + +app.post('/api/*', textParser, (req, res) => { + console.log(`post: Start: /api/* route...`); + logger.addLog("post: Start: /api/* route...\n",LogF); + let timeStamp = new Date().toISOString(); + logger.addLog("post: /api/*: timeStamp:["+timeStamp+"]\n\n",LogF); + if( req.url == null ) { + console.log("post: /api/*: req.url is null !"); + logger.addLog("post: /api/*: req.url is null !\n",LogF); + } + else { + console.log("post: /api/*: req.url:["+ req.url+"]"); + logger.addLog("post: /api/*: req.url:["+ req.url+"]\n",LogF); + }; + if( req.body == null ) { + console.log("post: /api/*: req.body is null !"); + } + else { + console.log("post: /api/*: req.body.length="+req.body.length ); + }; + if( req.headers != null ) { + console.log("post: /api/*: req.headers.length="+ req.headers.length ); + }; + var remAddr= ''; + if( req.socket != null ) { + console.log("post: /api/*: Have req.socket ..."); + logger.addLog("post: /api/*: Have req.socket ...\n",LogF); + if( req.socket.remoteAddress != null ) { + logger.addLog( + "post: /api/*: remoteAddress:["+ req.socket.remoteAddress+"]\n",LogF); + remAddr= req.socket.remoteAddress; + } + else { + console.log("post: /api/*: req.socket.remoteAddress is null !"); + logger.addLog("post: /api/*: req.socket.remoteAddress is null !\n",LogF); + } + }; + logger.addLog( + "post: /api/*: req.params:["+JSON.stringify(req.params)+"]\n",LogF); + //.. checking url + var rexpLR= new RegExp(/\/api\/post_logrec/); + var matchLR= rexpLR.exec( req.url ); + var rspData= 'r_undef'; + if( matchLR ) { + //.. posting server-side log record + logger.addLog("post: /api/*: start postLog: remAddr:["+remAddr+"]\n",LogF); + rspData= serverDataSvc.postSrvLogRec( req.url, req.body, remAddr ); + logger.addLog("post: /api/*: to send: response:["+rspData+"]\n",LogF); + } + else { //.. process data request + logger.addLog("post: /api/*: start procReq: remAddr:["+remAddr+"]\n",LogF); + rspData= serverDataSvc.procReq( req.url, req.body, remAddr ); + logger.addLog("post: /api/*: to send: response:["+rspData+"]\n",LogF); + var rspObj= JSON.parse(rspData); + if( rspObj.respStr != null && rspObj.respStr != undefined ) { + var respStrLen= rspObj.respStr.length; + logger.addLog("post: /api/*: respStr length="+respStrLen+"\n",LogF); + if( respStrLen < 60 ) { + logger.addLog("post: /api/*: rspObj.respStr:["+rspObj.respStr+"]\n",LogF); + } else { + logger.addLog("post: /api/*: rspObj.respStr(part):["+ + rspObj.respStr.substr(0,60)+"]\n",LogF); + } + } + } + res.status(200).send( rspData ); + timeStamp = new Date().toISOString(); + logger.addLog("post: done: timeStamp:["+timeStamp+"]\n\n",LogF); +}); + +//.. express.static to serve static files from /browser +//app.get('*.*', express.static(DIST_FOLDER) ); +app.get('*.*', express.static(CDT_HOME) ); + +// All regular routes use the Universal engine +app.get('*', (req, res) => { + console.log(`get: Start: regular route...`); + logger.addLog("get: * Start: regular route...\n",LogF); + if( req.url == null ) { + console.log("get: req.url is null !"); + logger.addLog("get: * regular route req.url is null !\n",LogF); + } + else { + console.log("get: req.url:["+ req.url+"]"); + logger.addLog("get: * regular route: req.url:["+ req.url+"]\n",LogF); + }; + if( CDT_HOME != null ) { + logger.addLog("get: * CDT_HOME:["+CDT_HOME+"]\n",LogF); + }; + if( req.socket != null ) { + logger.addLog("get: * Have req.socket ...\n",LogF); + if( req.socket.remoteAddress != null ) { + logger.addLog( + "get: *: remoteAddress:["+ req.socket.remoteAddress+"]\n",LogF); + } + else { + logger.addLog("get: *: req.socket.remoteAddress is null !\n",LogF); + } + }; + var respData= serverDataSvc.getData( req.url ); + logger.addLog("get: *: typeof response:["+(typeof respData)+"]\n",LogF); + if( typeof respData == "string" ) { + logger.addLog("get: *: respData:length="+respData.length+"\n",LogF); + }; + // logger.addLog("get: *: respData:["+JSON.stringify(respData)+"]\n",LogF); + res.status(200).send( respData ); + let timeStamp = new Date().toISOString(); + logger.addLog("get: * done: timeStamp:["+timeStamp+"]\n\n",LogF); +}); + +// Start up the Node server +https.createServer(options,app).listen(PORT, () => { + console.log(`Node server: CDT_HOME:[${CDT_HOME}]`); + console.log(`Node server: LOG_DIR:[${LOG_DIR}]`); + console.log(`Node server: opening Log in the file:[${LogF}]`); + console.log(`Node server listening on http://localhost:${PORT}`); + // console.log(" DIST_FOLDER:["+DIST_FOLDER+"]"); + logger.setMaxLogSize( MaxLogSize ); + logger.addLog("\n Node server: start: CDT_HOME:["+CDT_HOME+"]\n",LogF); + serverDataSvc.setHomeDir( CDT_HOME, LOG_DIR ); +}); + diff --git a/src/app/server-data-svc.js b/src/app/server-data-svc.js new file mode 100644 index 0000000..cb62f52 --- /dev/null +++ b/src/app/server-data-svc.js @@ -0,0 +1,656 @@ +/* +============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============================================ */ +//.. processing on server side +'use strict'; + +const fs = require('fs'); +//var spawn = require("child_process").spawn; +var Chproc = require("child_process"); +var logger = require('./srvlogger'); + +var clName= "ServerDataSvc"; +//const DIST_FLDR = join(process.cwd(), 'dist'); +//var DIST_FLDR = "dist"; +var cdt_home = "."; +var LOG_DIR = "/tmp"; +var LogF = "ndserver.log"; +var SubProcScript= "/app/subnproc.js"; +//var HTML_ROOT_FLDR= DIST_FLDR; +//var DelScript= DIST_FLDR +"/app/deleteOldData.js"; +//var inputFilePfx = DIST_FLDR +"/posted_data_"; +var fsAvSpaceKB= -1; +var rsfname= ""; +var remAddr= ""; //.. remote client address +var taskId= ""; +var fdI; +var fdRsf; +var fDelim= "&"; + + //.. to be called by server at initialization +exports.setHomeDir = function( homeDir, logDir ) { + this.cdt_home= homeDir; + this.LOG_DIR= logDir; + // this.DIST_FLDR= this.cdt_home+"/dist"; + this.LogF= this.LOG_DIR+"/ndserver.log"; + console.log( clName+": setHomeDir: cdt_home:["+this.cdt_home+"]"); + console.log( clName+": setHomeDir: LogF:["+this.LogF+"]"); +}; + + //.. to be called by server on receiving GET /getUserRole request + // (simulation only) +exports.getUserRoles = function( requrl ) { + var methName= "getUserRoles"; + logger.addLog( clName+": "+methName+ + ": start: url:["+ requrl+"]\n cdt_home:["+this.cdt_home+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + var resp= '{\"respStr\":\"notfoundResp\"}'; + this.urolfname= this.cdt_home+"/userRoles.json"; + resp= this.readResultFile( this.urolfname ); + logger.addLog( clName+": "+methName+ + ": result length="+resp.length+"\n",this.LogF); + return resp; +}; + + //.. to be called by server on receiving GET /api/* request +exports.getData = function( requrl ) { + var methName= "getData"; + //console.log(clName+": getData: start: url:["+ requrl+"]\n cdt_home:["+ + // this.cdt_home+"]"); + logger.addLog( clName+": "+methName+ + ": start: url:["+ requrl+"]\n cdt_home:["+this.cdt_home+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + var resp= '{\"respStr\":\"notfoundResp\"}'; + var taskStr= "taskId="; + //... Regular Expressions for different requests ... + //.. to get processing result + var rexpGRESUL= new RegExp(/\/api\/get_result/); + //.. to get progress percentage of the processing + var rexpGPROGR= new RegExp(/\/api\/get_progress/); + //.. to get parameters calculated via the processing + var rexpGPRMS= new RegExp(/\/api\/get_params/); + //.. to get parameters format-error file + var rexpPFMTERR= new RegExp(/\/api\/get_pfmterr/); + //.. to get Available space in server-side file-system + var rexpGFSAVSP= new RegExp(/\/api\/get_fsAvSpace/); + //.. to check for ACE-editor resource files + var rexpACERES= new RegExp(/\/node_modules\/ace-builds\/src-min/); + // + //... checking which url is matching ... + if( requrl == '/' ) { + // console.log(clName+": getData: this is a ROOT request ..."); + logger.addLog( clName+": getData: this is a ROOT request ...\n",this.LogF); + return this.getRoot(); + }; + //.. non-root, api url + var match1= null; + if( (match1= rexpGRESUL.exec(requrl)) != null ) { + logger.addLog( clName+": "+methName+": URL match /api/get_result\n",this.LogF); + //.. assuming: /api/get_result?taskId=f7be82e43e34cb4e960b45d35e8d9596 + var indT= requrl.indexOf( taskStr, 0); + if( indT < 0 ) { + var errMsg= + clName+": "+methName+": Error: No taskId found in the URL !\n"; + logger.addLog( errMsg,this.LogF); + resp= '{\"Error\":\"'+errMsg+'\"}'; + } + else { //.. indT > -1 - have taskId in URL + this.taskId= requrl.substr( indT+ taskStr.length ); + logger.addLog( clName+": "+methName+ + ": extracted from URL: taskId:["+this.taskId+"]\n",this.LogF); + this.rsfname= this.cdt_home+"/sync_template_res_"+this.taskId+".txt"; + resp= this.readResultFile( this.rsfname ); + logger.addLog( clName+": "+methName+ + ": result length="+resp.length+"\n",this.LogF); + logger.addLog( clName+": "+methName+ + ": got result -Start data cleanup...\n",this.LogF); + this.deleteOldFiles( this.taskId ); + }; + } + else + if( (match1= rexpGPROGR.exec(requrl)) != null ) { + logger.addLog( clName+": "+methName+ + ": URL match /api/get_progress\n",this.LogF); + //.. assuming: /api/get_progress?taskId=f7be82e43e34cb4e960b45d35e8d9596 + var indT= requrl.indexOf( taskStr, 0); + if( indT < 0 ) { + var errMsg= + clName+": "+methName+": Error: No taskId found in the URL !\n"; + logger.addLog( errMsg,this.LogF); + resp= '{\"Error\":\"'+errMsg+'\"}'; + } + else { //.. indT > -1 - have taskId in URL + this.taskId= requrl.substr( indT+ taskStr.length ); + logger.addLog( clName+": "+methName+ + ": extracted from URL: taskId:["+this.taskId+"]\n",this.LogF); + this.pgfname= this.cdt_home+"/proc_status_"+this.taskId+".json"; + // resp= '{\"percentage\":\"3\"}'; + resp= this.readResultFile( this.pgfname ); + } + logger.addLog( clName+": "+methName+ + ": result length="+resp.length+"\n",this.LogF); + logger.addLog( clName+": "+methName+": progress:["+resp+"]\n",this.LogF); + } + else + if( (match1= rexpGPRMS.exec(requrl)) != null ) { + logger.addLog( clName+": "+methName+ + ": URL match /api/get_params\n",this.LogF); + //.. assuming: /api/get_params?taskId=f7be82e43e34cb4e960b45d35e8d9596 + var indT= requrl.indexOf( taskStr, 0); + if( indT < 0 ) { + var errMsg= + clName+": "+methName+": Error: No taskId found in the URL !\n"; + logger.addLog( errMsg,this.LogF); + resp= '{\"Error\":\"'+errMsg+'\"}'; + } + else { //.. indT > -1 - have taskId in URL + this.taskId= requrl.substr( indT+ taskStr.length ); + logger.addLog( clName+": "+methName+ + ": extracted from URL: taskId:["+this.taskId+"]\n",this.LogF); + var prmfname= this.cdt_home+"/template_params_"+this.taskId+".txt"; + resp= this.readResultFile( prmfname ); + } + logger.addLog( clName+": "+methName+ + ": params length="+resp.length+"\n",this.LogF); + } + else + if( (match1= rexpPFMTERR.exec(requrl)) != null ) { + //.. parameter format error file + logger.addLog( clName+": "+methName+ + ": URL match /api/get_pfmterr\n",this.LogF); + //.. assuming: /api/get_pfmterr?taskId=f7be82e43e34cb4e960b45d35e8d9596 + var indT= requrl.indexOf( taskStr, 0); + if( indT < 0 ) { + var errMsg= + clName+": "+methName+": Error: No taskId found in the URL !\n"; + logger.addLog( errMsg,this.LogF); + resp= '{\"Error\":\"'+errMsg+'\"}'; + } + else { //.. indT > -1 - have taskId in URL + this.taskId= requrl.substr( indT+ taskStr.length ); + logger.addLog( clName+": "+methName+ + ": extracted from URL: taskId:["+this.taskId+"]\n",this.LogF); + var errfname= this.cdt_home+"/sync_template_err_"+this.taskId+".txt"; + resp= this.readResultFile( errfname ); + } + logger.addLog( clName+": "+methName+ + ": params length="+resp.length+"\n",this.LogF); + } + else + if( (match1= rexpGFSAVSP.exec(requrl)) != null ) { + //.. Available Space in Server-side file-system + logger.addLog( clName+": "+methName+ + ": URL match /api/get_fsAvSpace \n",this.LogF); + var errMsg= this.getFsAvailSpace( this.cdt_home ); + if( errMsg.length > 0 ) { + //.. return non-empty Error message + resp= '{\"Error\":\"'+errMsg+'\"}'; + }else{ + resp= fsAvSpaceKB; //.. empty return means no error + }; + } + else + if( (match1= rexpACERES.exec(requrl)) != null ) { + //.. (simulated env.) ACE-editor resource files + logger.addLog( clName+": "+methName+ + ": URL match /node_modules/ace-builds...\n",this.LogF); + var acebldStr= "src-min\/"; + var indAB= requrl.indexOf( acebldStr, 0); + if( indAB < 0 ) { + logger.addLog( clName+": "+methName+ + ": Warn: No URL match("+acebldStr+").\n",this.LogF); + } + else { //.. indAB > -1 -got acebldStr + var acefname= requrl.substr( indAB +acebldStr.length ); + logger.addLog( clName+": "+methName+ + ": req.file name:["+acefname+"]\n",this.LogF); + // if( acefname == "mode-velocity.js" || acefname == "theme-chrome.js" ) + if( acefname == "mode-velocity.js" ) + { + var aresfname= this.cdt_home+"/app/"+acefname; + resp= this.readResultFile( aresfname ); + } + else { + logger.addLog( clName+": "+methName+ + ": Warn: No ace URL match("+acebldStr+"...js).\n",this.LogF); + } + } + } + else { //.. + logger.addLog( clName+": "+methName+ + ": Warn: No URL match - nothing to do !\n",this.LogF); + }; + logger.addLog( clName+": "+methName+ + ": resp.length="+resp.length+"\n finish.\n",this.LogF); + return resp; +}; + +exports.deleteOldFiles = function( ctaskId ) { + var methName= "deleteOldFiles"; + logger.addLog( clName+": "+methName+ + ": start. the complete task Id:["+ctaskId+"]\n",this.LogF); + var cp_args= new Array( 0 ); + cp_args.push( ctaskId ); //.. give it taskId in args + cp_args.push( cdt_home ); + cp_args.push( LOG_DIR ); + var DelScript= this.cdt_home +"/app/deleteOldData.js"; + var chprocI= Chproc.fork( DelScript, cp_args ); + logger.addLog( clName+": "+methName+ + ": DelScript started ...\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); +}; + +exports.getRoot = function() { + var methName= "getRoot"; + logger.addLog( clName+": "+methName+": start. ROOT URL match \n",this.LogF); + logger.addLog( clName+": "+methName+ + ": cdt_home:["+this.cdt_home+"]\n",this.LogF); + var HTML_ROOT_FLDR= this.cdt_home; + this.rsfname= HTML_ROOT_FLDR+"/index.html"; + var resp= this.readResultFile( this.rsfname ); + logger.addLog( clName+": "+methName+ + ": result length="+resp.length+"\n",this.LogF); + logger.addLog( clName+": "+methName+": resp:["+resp+"]\n",this.LogF); + return resp; +}; + +exports.readResultFile = function( rfname ) { + var methName= "readResultFile"; + //.. read processing result from file and send back to the client + logger.addLog( clName+": "+methName+ + ": start. rfname:["+rfname+"]\n",this.LogF); + var rdata= ""; + try { + rdata= fs.readFileSync( rfname, 'utf8'); + } + catch( err ) { + logger.addLog( clName+": "+methName+ + ": result-file read: Error: code="+err.code+"\n",this.LogF); + throw err; + } + logger.addLog( clName+": "+methName+ + ": result-file content length="+rdata.length+"\n",this.LogF); + return rdata; +}; + +exports.postSrvLogRec = function ( requrl, inpdata, remaddr ) { + //.. to be called by server on receiving POST /api/post_logrec request + var methName= "postSrvLogRec"; + logger.addLog( clName+": "+methName+ + ": start: url:["+ requrl+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + logger.addLog( clName+": "+methName+ + ": cdt_home:\n["+cdt_home+"]\n",this.LogF); + logger.addLog( clName+": "+methName+ + ": client: remaddr:["+ remaddr+"]\n",this.LogF); + if( remaddr != null && remaddr != undefined ) { + this.remAddr= remaddr; + }; + logger.addLog( clName+": "+methName+ + ": Log Record:\n-["+inpdata+"]-\n",this.LogF); + var resp= '{\"respStr\":\"OK\"}'; + logger.addLog( clName+": "+methName+": done: resp:["+resp+"]\n",this.LogF); + return( resp ); +}; + +exports.procReq = function ( requrl, inpdata, remaddr ) { + //.. to be called by server on receiving POST /api/* request + // receive input data, save into a file and start server-side processing task + var methName= "procReq"; + logger.addLog( clName+": "+methName+ + ": start: url:["+ requrl+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + logger.addLog( clName+": "+methName+ + ": cdt_home:\n["+cdt_home+"]\n",this.LogF); + logger.addLog( clName+": "+methName+ + ": client: remaddr:["+ remaddr+"]\n",this.LogF); + if( remaddr != null && remaddr != undefined ) { + this.remAddr= remaddr; + }; + logger.addLog( clName+": "+methName+ + ": remAddr:["+ this.remAddr+"]\n",this.LogF); + var inpdLen= inpdata.length; + logger.addLog( clName+": "+methName+": inpdata length="+inpdLen+"\n",this.LogF); + if( inpdLen > 300 ) { + logger.addLog( clName+": "+methName+ + ": inpdata:\n["+inpdata.substr(0,299)+"...]\n",this.LogF); + }else{ + logger.addLog( clName+": "+methName+ + ": inpdata:\n["+inpdata+"]\n",this.LogF); + }; + var resp= '{\"respStr\":\"postNotFoundResp\"}'; + var taskStr= "taskId="; + var rexp2= new RegExp(/\/api\/proc_cont/); + var match2= rexp2.exec( requrl ); + if( match2 ) { + logger.addLog( clName+": "+methName+ + ": URL match: proc_cont - processing content...\n",this.LogF); + //.. check available space before server-side processiong + var emsg= this.getFsAvailSpace( this.cdt_home ); + var doAdd= ''; //.. false + var doProc= ''; //.. false + //.. assuming format: + // url: /api/proc_cont?taskId=1fcf9ebb05cec21caeb71ebac7e34b2c&part=2of2 + var indT= requrl.indexOf( taskStr, 0); + if( indT < 0 ) { + logger.addLog( clName+": "+methName+ + ": Warn: No taskId found in the URL - New Task !\n",this.LogF); + this.calcTaskId(); + logger.addLog( clName+": "+methName+ + ": calculated New taskId:["+this.taskId+"]\n", this.LogF); + resp= '{\"respStr\":\"proc_start\",\"taskId\":\"'+this.taskId+'\"}'; + } + else { //.. indT > -1 - have taskId in URL + var indTV= indT+ taskStr.length; + var indDL= requrl.indexOf( fDelim, indTV ); + if( indDL < 0 ) { + logger.addLog( clName+": "+methName+ + ": no more fields after taskId.\n",this.LogF); + this.taskId= requrl.substr( indTV ); + }else{ //.. found delimiter + this.taskId= requrl.substring( indTV, indDL ); + }; + logger.addLog( clName+": "+methName+ + ": extracted from URL: taskId:["+this.taskId+"]\n", this.LogF); + doAdd= "true"; //.. will add to old content + resp= '{\"respStr\":\"proc_upload\"}'; //.. no return of old taskId + } + var inputFilePfx = this.cdt_home +"/posted_data_"; + var infname= inputFilePfx +this.taskId +".txt"; + logger.addLog( clName+": "+methName+ + ": got input file name:["+infname+"]\n",this.LogF); + //.. extracting parts info, e.g.: "...&part=2of2" + var rexp2p= new RegExp(/part=(\d+)of(\d+)/); + var match2p= rexp2p.exec( requrl ); + if( match2p == null ) { + logger.addLog( clName+": "+methName+ + ": Warn: No part number found in the URL "+ + "-cant determine the last part !\n",this.LogF); + } + else { //.. match2p != null + logger.addLog( clName+": "+methName+ + ": match2p: length="+match2p.length+"\n",this.LogF); + for( var i1=0; i1 < match2p.length; i1++ ) { + logger.addLog( clName+": "+methName+ + ": match2p:["+match2p[i1]+"]\n",this.LogF); + }; + var partNum= match2p[ 1]; + var partCnt= match2p[ 2]; + logger.addLog( clName+": "+methName+ + ": partNum:["+partNum+"] partCnt:["+partCnt+"]\n",this.LogF); + if( partNum == partCnt ) { + logger.addLog( clName+": "+methName+ + ": this is the last part -need doProc\n",this.LogF); + doProc= "true"; + }; + }; + //.. write data into the file and start processing right after the close + var errW= this.writeInp2File( infname, inpdata, doAdd, doProc ); + if( errW.length > 0 ) { + resp= errW; + }; + } + else { //.. no match2 + logger.addLog( clName+": "+methName+": Warn: No URL match.\n",this.LogF); + } + logger.addLog( clName+": "+methName+": done: resp:["+resp+"]\n",this.LogF); + return( resp ); +}; + +exports.getFsAvailSpace = function ( fspath ) { + var methName= "getFsAvailSpace"; + //.. get available space (kB) in filesystem where the fspath is mounted + logger.addLog( clName+": "+methName+ + ": start: fspath:\n["+fspath+"]\n",this.LogF); + var timeStampI = Date.now(); + logger.addLog( clName+": "+methName+": timeStampI="+timeStampI+"\n",this.LogF); + var timeStamp = new Date( timeStampI ).toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + if( fspath.length < 1 ) { + var errMsg= methName+": Error: the filesystem directory path is empty !"; + logger.addLog( clName+ errMsg+"\n", this.LogF); + return errMsg; + }; + // var carg= "-k "+fspath; + // var mopts= { input: carg, timeout: 4000 }; + //var moutObj= Chproc.spawnSync('df',[],mopts); + var c_args= new Array( 0 ); + c_args.push( '-k' ); + c_args.push( fspath ); + var mopts= { timeout: 4000 }; + logger.addLog( clName+": "+methName+ + ": mopts:["+JSON.stringify(mopts)+"]\n",this.LogF); + //.. start + var moutObj= Chproc.spawnSync('df', c_args, mopts); + logger.addLog( clName+": "+methName+ + ": df done: moutObj: status:["+moutObj.status+"](0 means Ok)\n",this.LogF); + var timeStampI = Date.now(); + logger.addLog( clName+": "+methName+": timeStampI="+timeStampI+"\n",this.LogF); + if( moutObj.error != null ) { + var errMsg= clName+": "+methName+ + ": spawn df: Error:["+JSON.stringify(moutObj.error)+"]"; + logger.addLog( errMsg+"\n", this.LogF); + return errMsg; + }; + logger.addLog( clName+": "+methName+ + ": df moutObj.output: length="+moutObj.output.length+"\n",this.LogF); + if( moutObj.output.length > 0 ) { + for( var i0=0; i0 < moutObj.output.length; i0++ ) { + logger.addLog( clName+": "+methName+ + ": moutObj.output["+i0+"]:["+moutObj.output[i0]+"]\n",this.LogF); + }; //.. loop + //.. output[1]: should contain 2 lines: + // [Filesystem 1K-blocks Used Available Use% Mounted on\n + // /dev/dm-0 37383720 8933604 26528068 26% /\n] + var out1= moutObj.output[1]; + logger.addLog( clName+": "+methName+": to parse out1:["+out1+"]\n",this.LogF); + var rexp1= new RegExp(/\s+(\d+)\s+(\d+)\s+(\d+)\s+/); + logger.addLog( clName+": "+methName+": rexp1:["+rexp1+"]\n",this.LogF); + var matchArr= rexp1.exec( out1 ); + if( matchArr == null ) { + var errMsg= clName+": "+methName+ + ": spawn: Error: No digitals (bytes counts) found in the output !"; + logger.addLog( errMsg+"\n", this.LogF); + return errMsg; + }; + if( matchArr[3] == null || matchArr[3] == undefined ) { + var errMsg= clName+": "+methName+ + ": parsed: Error: The 3-rd byte count is empty (no Available Kbytes) !"; + logger.addLog( errMsg+"\n", this.LogF); + return errMsg; + }; + fsAvSpaceKB= matchArr[3]; + logger.addLog( clName+": "+methName+ + ": extracted fsAvSpaceKB="+fsAvSpaceKB+"\n",this.LogF); + }else{ + var errMsg= clName+": "+methName+ + ": spawn: Error: Empty df-command output array !"; + logger.addLog( errMsg+"\n", this.LogF); + return errMsg; + } + logger.addLog( clName+": "+methName+": finished.\n",this.LogF); + return ''; +}; + +exports.calcTaskId = function () { + var methName= "calcTaskId"; + //.. calculate taskId + logger.addLog( clName+": "+methName+": start:\n",this.LogF); + var timeStampI = Date.now(); + logger.addLog( clName+": "+methName+": timeStampI="+timeStampI+"\n",this.LogF); + var timeStamp = new Date( timeStampI ).toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + + var rawId = String( this.remAddr+'-'+timeStampI ); + logger.addLog( clName+": "+methName+": rawId:["+rawId+"]\n",this.LogF); + + var mopts= { input: rawId, timeout: 4000 }; + logger.addLog( clName+": "+methName+ + ": mopts:["+JSON.stringify(mopts)+"]\n",this.LogF); + + var moutObj= Chproc.spawnSync('md5sum',[],mopts); + logger.addLog( clName+": "+methName+ + ": moutObj: status:["+moutObj.status+"]\n",this.LogF); + if( moutObj.error != null ) { + logger.addLog( clName+": "+methName+ + ": moutObj calc.: Error:["+JSON.stringify(moutObj.error)+"]\n",this.LogF); + throw moutObj.error; + } + else { //.. no errors + logger.addLog( clName+": "+methName+ + ": moutObj: output: length="+moutObj.output.length+"\n",this.LogF); + if( moutObj.output.length > 0 ) { + for( var i0=0; i0 < moutObj.output.length; i0++ ) { + logger.addLog( clName+": "+methName+ + ": moutObj: output:["+moutObj.output[i0]+"]\n",this.LogF); + } + } + var out1= moutObj.output[ 1 ]; + logger.addLog( clName+": "+methName+": out1:["+out1+"]\n",this.LogF); + var rexp1= new RegExp(/\w+/); //.. alphanumeric + logger.addLog( clName+": "+methName+": rexp1:["+rexp1+"]\n",this.LogF); + var match1= rexp1.exec( out1 ); + if( match1 == null ) { + logger.addLog( clName+": "+methName+ + ": Warn.: No Match of rexp1 in the cmd output (No taskId) !\n",this.LogF); + } + else { + logger.addLog( clName+": "+methName+ + ": match1:["+match1[0]+"] length="+match1.length+"\n",this.LogF); + this.taskId= match1[0]; + }; + }; + logger.addLog( clName+": "+methName+ + ": done: calculated taskId:["+this.taskId+"]\n",this.LogF); +}; + +exports.writeInp2File = function ( fname, inpd, doAdd, doProc ) { + var methName= "writeInp2File"; + //.. write input data to the file + logger.addLog( clName+": "+methName+ + ": Start: file:["+fname+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + var inpdLen= inpd.length; + logger.addLog( clName+": "+methName+": inpd length="+ inpdLen+"\n",this.LogF); + if( inpdLen < 1 ) { + logger.addLog( clName+": "+methName+ + ": Warn.: Empty input - nothing to do !\n",this.LogF); + return ''; //.. not an error + }; + if( inpdLen > 300 ) { + logger.addLog( clName+": "+methName+ + ": inpd(begin):["+ inpd.substr(0,299)+"...]\n",this.LogF); + } + else { + logger.addLog( clName+": "+methName+": inpd:["+ inpd+"]\n",this.LogF); + }; + logger.addLog( clName+": "+methName+ + ": doAdd:["+doAdd+"] doProc:["+doProc+"]\n",this.LogF); + if( ! doAdd ) { + logger.addLog( clName+": "+methName+ + ": Dont doAdd - need new content.\n",this.LogF); + //.. removing old file if is there with the same name (async is Not OK !) + var fname_o= fname+".save"; + try { + fs.renameSync( fname, fname_o ); + } + catch( err ) { + var errMsg= clName+": "+methName+ + ": Warn.: Failed to rename old file:["+fname+"]"+ + " err.code="+err.code+"\n"; + logger.addLog( errMsg, this.LogF ); + }; + }; + logger.addLog( clName+": "+methName+": opening file:["+fname+"]\n",this.LogF); + try { + this.fdI= fs.openSync( fname, 'a' ); + } + catch( err ) { + var errMsg= clName+": "+methName+ + ": Error: Failed to open file:["+fname+"]"+ + " err.code="+err.code+"\n"; + logger.addLog( errMsg, this.LogF ); + return( errMsg ); + }; + logger.addLog( clName+": "+methName+ + ": writing data into the file: fdI="+ this.fdI+"\n",this.LogF); + try { + fs.appendFileSync( this.fdI, inpd, 'utf8' ); + } + catch( err ) { + var errMsg= clName+": "+methName+ + ": Error: Failed to append input data to file: err.code="+err.code+"\n"; + logger.addLog( errMsg, this.LogF ); + return( errMsg ); + }; + logger.addLog( clName+": "+methName+ + ": closing input data file...\n",this.LogF); + try { + fs.closeSync( this.fdI ); + } + catch( err ) { + var errMsg= clName+": "+methName+ + ": Error: Failed to close input data file: err.code="+err.code+"\n"; + logger.addLog( errMsg, this.LogF ); + return( errMsg ); + }; + logger.addLog( clName+": "+methName+ + ": input file was written and closed successfully.\n",this.LogF); + timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+": timeStamp:["+timeStamp+"]\n",this.LogF); + if( doProc ) { + logger.addLog( clName+": "+methName+ + ": starting processing...\n",this.LogF); + this.startProcFile(); + }; + return ''; //.. no error +}; + +exports.startProcFile = function () { + var methName= "startProcFile"; + //.. start processing of the input file in external sub-process + logger.addLog( clName+": "+methName+ + ": Start: taskId:["+this.taskId+"]\n",this.LogF); + let timeStamp = new Date().toISOString(); + logger.addLog( clName+": "+methName+ + ": timeStamp:["+timeStamp+"]\n",this.LogF); + console.log(methName+": cdt_home:["+this.cdt_home+"]"); + var SubProcScriptP= this.cdt_home + SubProcScript; + logger.addLog( clName+": "+methName+ + ": run SubProcScript:\n["+SubProcScriptP+"]\n",this.LogF); + var cp_args= new Array( 0 ); + cp_args.push( this.taskId ); //.. give it taskId in args + cp_args.push( this.cdt_home ); + cp_args.push( this.LOG_DIR ); + var chprocI= Chproc.fork( SubProcScriptP, cp_args ); + + // chprocI.on('message', (msg) => { + // console.log(methName+": chprocI got msgJ:["+JSON.stringify(msg)+"]"); + // }); + // console.log("startProcFile: sending a message to child."); + // chprocI.send({ hello: 'world' }); + logger.addLog( clName+": "+methName+" done submit.\n",this.LogF); +}; diff --git a/src/app/srvlogger.js b/src/app/srvlogger.js new file mode 100755 index 0000000..22c6d83 --- /dev/null +++ b/src/app/srvlogger.js @@ -0,0 +1,96 @@ +/* +============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============================================ */ +//.. srvlogger.js -logging in file system +const fs = require('fs'); + +const clName= "srvlogger"; + +var MaxLogSize= 5000000; +var LogFileNm; +var fdL; + +exports.addLog = function( logStr, fileNm ) { + + this.LogFileNm= fileNm + this.fdL= fs.openSync( this.LogFileNm, 'a' ); + // console.log(clName+": log opened. fdL="+this.fdL); + + var lfStats= fs.fstatSync( this.fdL ); + if( lfStats.size + logStr.length >= MaxLogSize ) + { + this.changeLogFile(); + }; + + try { + fs.appendFileSync( this.fdL, logStr, 'utf8' ); + } + catch( err ) { + console.log(clName+": log append: error:"+err.message ); + throw err; + }; + fs.closeSync( this.fdL ); +} + +exports.changeLogFile = function() { + + var msgO= "\n=== The Log reached max size. Changing the file. ===\n"; + try { + fs.appendFileSync( this.fdL, msgO, 'utf8' ); + } + catch( err ) { + console.log(clName+": log append: error:"+err.message ); + throw err; + }; + fs.closeSync( this.fdL ); + + var LogFileNm_o= this.LogFileNm +".old"; + try { + fs.renameSync( this.LogFileNm, LogFileNm_o ); + } + catch( err ) { + throw err; + }; + + try { + this.fdL= fs.openSync( this.LogFileNm, 'a' ); + } + catch( err ) { + console.log(clName+": New Log file open: error:["+err.message+"]\n"); + throw err; + } + console.log( clName+": New Log file opened: fdL="+this.fdL+"\n"); + + var msgN= "\n=== New Log file ===\n"; + try { + fs.appendFileSync( this.fdL, msgN, 'utf8' ); + } + catch( err ) { + console.log( clName+": new log append: error:"+err.message ); + throw err; + }; +} + +exports.setMaxLogSize = function( newMaxLogSize ) { + if( newMaxLogSize > 0 ) + MaxLogSize= newMaxLogSize; + else + console.log(clName+": Wrong arg: newMaxLogSize <= 0 !"); +} diff --git a/src/app/subnproc.js b/src/app/subnproc.js new file mode 100644 index 0000000..6719366 --- /dev/null +++ b/src/app/subnproc.js @@ -0,0 +1,840 @@ +/* +============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"); } +}; -- cgit 1.2.3-korg