How to make while loop with switch case synchrounous in nodejs? - node.js

How can I make the while loop with switch-case synchronous in nodejs? Below is the code I am trying to iterate for 2 iterations of the while loop. But the problem is the next iteration gets iterated even before completing all the synchronous functions here which are readdirSync, readFileSync, etc.
What I want is with each whileloop iteration it should run all the methods and then again for next iteration.
Currently the output is:
i = 0
i = 1
Below is my code:
const dir4Data = 'C:/Users/em/Desktop/Regex_test_case/data/google_forms';
const dir4Polls = 'C:/Users/em/Desktop/Regex_test_case/Poll_Report';
var dir, i=0;
var regex4Data = /^\d{1,2}([./-])\d{1,2}\1\d{4}$/;
var regex4Polls = /^[1-9]\d*$/;
while(i < 2)
{
switch (i) {
case 0:
dir = dir4Data;
break;
case 1:
dir = dir4Polls;
break;
}
console.log('i = ', i);
fs.readdirSync(dir, function(err,files){ //Get a listing of all the files in the dir
if (err) throw err;
files.forEach(function(file){
//console.log("file = "+ file);
const writePath = 'C:/Users/em/Desktop/Regex_test_case/output/'+file;
fs.readFileSync(dir+'/'+file, function(err, data) {
console.log("data = "+ data);
var csvContent = data.toString().split('\n'); // read file and convert to array by line break
csvContent.forEach((item, index) => {
var csv;
if(!regex4Data.test(item.toString().split(' ')[0]) && index != 0 && i == 0) {
csv = csvContent[index-1].replace(/(\r\n|\n|\r)/gm, ""); // remove the breaks
// console.log(index, ' Replaced', csv);
fs.appendFileSync(writePath, csvContent[index].toString()+ ' ', function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
else if(!regex4Polls.test(item.toString().split(',')[0]) && index != 0 && i == 1) {
csv = csvContent[index-1].replace(/(\r\n|\n|\r)/gm, ""); // remove the breaks
// console.log(index, ' Replaced', csv);
fs.appendFileSync(writePath, csvContent[index].toString()+ ' ', function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
else {
csv = item.toString();
fs.appendFileSync(writePath, "\n"+csv + " ", function (err, data) {
if (err) throw err;
//console.log('Saved!');
})
}
});
})
})
})
i++;
}

There are two main error in your script.
First of all, you are using wrong the FS module function.
From the doc, https://nodejs.org/api/fs.html#fs_synchronous_example, all the FS Sync function are synchronous. That means that you don't have to pass them a callback.
You can just write
var response = fs.readFileSync(path);
And the value of response is your file.
The other thing is, if you wont to iterate an async function, you cannot with callback, but you can do it using async/await.
Here an example of loop working:
async function loop() {
var i = 0
while (i < 2) {
var response = await fs.promises.readFile(path);
console.log(response)
i++
}
}

Related

Modify the value of a variable outside callback with the callback inside loop

I am new to Nodejs and I am facing with a problem: Modify the value of a variable outside callback with the callback inside a loop.
I am coding online-judgle project, this is my function to check output of a program with answer from database. I created result object to store amount of correct testcase.
function compareResult(fileName, problem, timeLimit, callback) {
const cp = require('child_process');
const exePath = 'submit\\' + fileName + '.exe';
const child = cp.spawn(exePath, ['--from=markdown', '--to=html'], {timeout: timeLimit});
MongoClient.connect(uri, function(err, db) {
if (err) throw err;
var dbo = db.db(dbName);
var query = { id_problem: problem, is_eg: "false" };
var proj = { projection: {input: 1, output: 1} };
dbo.collection("sample").find(query, proj).toArray(function(err, arr) {
if (err) throw err;
if (arr != null) {
var result = {
correct: 0,
total: arr.length
};
for (const json of arr) {
const answer = json['output'];
child.stdin.write(json['input']);
child.stdout.on('data', function(data) {
if (data == answer) {
result.correct += 1; // I want to modify result object here.
}
});
child.stdin.end();
};
console.log(result);
callback(result);
}
});
});
I want to modify result object in that place. How will I do it?
function compareResult(fileName, problem, timeLimit, callback) {
const cp = require('child_process');
const exePath = 'submit\\' + fileName + '.exe';
const child = cp.spawn(exePath, ['--from=markdown', '--to=html'], {timeout: timeLimit});
MongoClient.connect(uri, function(err, db) {
if (err) throw err;
var dbo = db.db(dbName);
var query = { id_problem: problem, is_eg: "false" };
var proj = { projection: {input: 1, output: 1} };
dbo.collection("sample").find(query, proj).toArray(function(err, arr) {
if (err) throw err;
if (arr != null) {
var result = {
correct: 0,
total: arr.length
};
for (const json of arr) {
const answer = json['output'];
child.stdin.write(json['input']);
child.stdout.on('data', function(data) {
if (data == answer) {
result.correct += 1;
}
// Decrement total here to track how many 'data' events have been emitted
result.total--;
if (result.total === 0) {
// All 'data' events have been emitted, so call the callback function
callback(result);
}
});
child.stdin.end();
};
}
});
});
}

NodeJS Appending File differently to source file

So I have some code that takes an input file, Replaces strings in that file and appends those replaced strings to another file.
The problem is that the append function outputs a slightly different file (not where the replaces are). The strings are replaced fine its just some of the lines are swapped and some lines do not have a break.
Code:
const settings = require('../settings.json')
const lineReader = require('line-reader');
const sleep = require('system-sleep')
const Promise = require('bluebird');
var eachLine = Promise.promisify(lineReader.eachLine);
const fs = require('fs')
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
}
return result;
}
fs.stat('./unblacklisted.rbxlx', function(err, stat) {
if(err == null) {
fs.unlink('./unblacklisted.rbxlx', function(err) {
if (err) throw err
})
} else if(err.code === 'ENOENT') {
// file does not exist
} else {
console.log('Some other error: ', err.code);
}
})
eachLine(`./${settings['CorrectMapName/fileName']}`, function(line) {
if (typeof line.split('referent=')[1] !== 'undefined') {
let treatedline = line.replace(/(\r\n|\n|\r)/gm, "");
let test = treatedline.split('referent=')[1]
let hello = (treatedline.replace(test, `"RBX${Buffer.from(makeid(17), 'ascii').toString('hex').toUpperCase()}">`))
fs.appendFile('./unblacklisted.rbxlx',`${hello}\n`, function (err) {
if (err) throw err;
});
} else {
let treatedline = line.replace(/(\r\n|\n|\r)/gm, "");
fs.appendFile('./unblacklisted.rbxlx', `${treatedline}\n`, function (err) {
if (err) throw err;
return;
});
}
}).then(function() {
__callback()
})
The input and output files are XML and I will provide two pastebin URL's for the input file and output file
Input: https://pastebin.com/cHbzL1W6
Output: https://pastebin.com/C53YBwMy
These look very similar but if you run them through a file comparer some lines are switched and vise versa
Would love to fix this, Any help would be GREATLY appreciated
Using jifriend00's first comment I saw that fs.appendFile() was not appending Synchronously
I fixed this by using fs.appendFileSync()
If anyone reading has this problem just use fs.appendFileSync() :D

Increment the filename if it already exists when saving files in node.js?

Is there a simple way to make node.js increment the filename of a file (i.e., append a number, so that it doesn't overwrite previous files) when saving it?
Below is my attempt:
// can i make this a one-liner?:)
async function incrementIfExists(dirPath, fileName, data, increment=1) {
const fs = require('fs'),
path = require('path'),
errorFunc = (err) => console.error(err);
// Get the last file saved with same fileName (i.e., the one that has the greatest increment number), if there is one
let lastFile = await fs.promises.readdir(dirPath)
.then(files => {
let result = '';
for (const name of files) {
if (!name.startsWith(fileName)) continue;
if ((name.length < result.length) || (name.length === result.length && name < result)) continue;
result = name;
}
return result;
})
.catch(errorFunc);
if (lastFile) {
const lastIncrementNr = Number(lastFile.slice((fileName + '_').length));
if (increment <= lastIncrementNr) increment = lastIncrementNr + 1;
}
fileName = path.join(dirPath, fileName);
while (true) {
let breakLoop = await fs.promises.writeFile(lastFile ? fileName + '_' + increment : fileName, data, {encoding: 'utf8', flag: 'wx'})
.then(fd => true)
.catch(err => {
if (err.code === 'EEXIST') {console.log(err);
return false;
}
throw err;
});
if (breakLoop) break;
increment++;
}
}
incrementIfExists('.', fileName, data);
Related:
How to not overwrite file in node.js
Creating a file only if it doesn't exist in Node.js
I use something similar to version uploaded image files on disk. I decided to use the "EEXIST" error to increment the number rather than explicitly iterating the files in the directory.
const writeFile = async(filename, data, increment = 0) => {
const name = `${path.basename(filename, path.extname(filename))}${increment || ""}${path.extname(filename)}`
return await fs.writeFile(name, data, { encoding: 'utf8', flag: 'wx' }).catch(async ex => {
if (ex.code === "EEXIST") return await writeFile(filename, data, increment += 1)
throw ex
}) || name
}
const unversionedFile = await writeFile("./file.txt", "hello world")
const version1File = await writeFile("./file.txt", "hello world")
const version2File = await writeFile("./file.txt", "hello world")

How to get code to execute in order in node.js

I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));

node.js how to get data from redis database inside in middleware

I'm doing middleware module that will extract data from redis and put to req.my_session.[here]
This is function that call inside app.use();
function parse_cookies(req){
if(req.headers.cookie != null){
var result = req.headers.cookie.match(new RegExp('m:[^=]*=[^; ]*', 'ig'));
if(result != null){
for(var i = 0; i < result.length; i++){
var result1 = result[i].split('=');
req.my_session[result1[0].substr(2)] = result1[1];
// get from redis value
client.get('sess:'+result1[1], function(err, reply) {
// reply is null when the key is missing
console.log(reply);
let li = i;
req.my_session[result1[0].substr(2)] = reply;
console.log('li = ' + li);
console.log('result1.lenght= ' + result.length);
if(i == result.length){
console.log('call the next');
}
});
}
}
}
} // parse_cookies
in console i outputs always 3, how can I get all data from database using redis.get and on last data call next() function for get out from my function?
problem it's get data from database in my middleware, I can't because redis has callback function
client.get("missingkey", function(err, reply) {
// reply is null when the key is missing
console.log(reply);
});
I think the issue is becuase of async in loop you can try the following
function parse_cookies(req){
if(req.headers.cookie != null){
var result = req.headers.cookie.match(new RegExp('m:[^=]*=[^; ]*', 'ig'));
if(result != null){
var promises = [];
for(var i = 0; i < result.length; i++){
var result1 = result[i].split('=');
promises.push(getFromRd(req, result1));
}
return Promise.all(promises)
.then(() => {
return next()
})
.catch((e) => {
return next({error: e})
})
}
}
} // parse_cookies
function getFromRd(req, result1) {
req.my_session[result1[0].substr(2)] = result1[1];
// get from redis value
return client.get('sess:'+result1[1], function(err, reply) {
if (err) {
throw Error(' failed to find ' + 'sess:' + result1[1])
}
// reply is null when the key is missing
console.log(reply);
let li = i;
req.my_session[result1[0].substr(2)] = reply;
console.log('li = ' + li);
console.log('result1.lenght= ' + result.length);
return {success:true}
});
}

Resources