Node run multiple instances and close only requested instance - node.js

I am using xvbf in node application to run a chrome client for capturing web site screens in background. From a web page i am passing data to my webservice as at the bottom of this code part to START_CAPTURE and STOP_CAPTURE.
const puppeteer = require('puppeteer');
const Xvfb = require('xvfb');
var exec = require('child_process').exec;
const os = require('os');
const homedir = os.homedir();
const platform = os.platform();
const http = require('http');
const StringDecoder = require('string_decoder').StringDecoder;
const http_port = 8000;
const ffmpegServer = config.ffmpegServer + ":" + config.ffmpegServerPort;
var xvfb = new Xvfb({
silent: true,
xvfb_args: ["-screen", "0", "1280x800x24", "-ac", "-nolisten", "tcp", "-dpi", "96", "+extension", "RANDR"]
});
var action = "";
var width = 1280;
var height = 720;
var options = {
headless: false,
args: [
'--enable-usermedia-screen-capturing',
'--allow-http-screen-capture',
'--load-extension=' + __dirname,
'--disable-extensions-except=' + __dirname,
'--disable-infobars',
'--start-fullscreen',
'--app=https://www.google.com/'`
],
}
options.executablePath = "/usr/bin/google-chrome"
async function main() {
try{
if(platform == "linux"){
xvfb.startSync()
}
var exportname = 'video.webm'
var url = 'https://www.google.com/';
var duration = 30;
const browser = await puppeteer.launch(options)
const pages = await browser.pages()
const page = pages[0]
page.on('console', msg => {
var m = msg.text();
console.log('PAGE LOG:', m)
});
await page._client.send('Emulation.clearDeviceMetricsOverride')
await page.goto(url, {waitUntil: 'networkidle2'})
await page.setBypassCSP(true);
if(duration > 0){
await page.waitFor((duration * 1000))
}else{
while(action!="STOP_CAPTURE"){
try {
await page.waitForSelector('[class^=modal] > [class^=content] > button[description="Logs you out"]', {
timeout: 1000
});
} catch (err) {
// Do nothing
}
}
}
await page.close()
await browser.close()
if(platform == "linux"){
xvfb.stopSync()
}
fs.unlinkSync(homedir + "/video.webm");
}catch(err) {
console.log(err)
}
}
// Instantiate the HTTP server.
const httpServer = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
if (req.method == 'POST') {
var jsonString = '';
var buffers = [];
req.on('data', function (chunk) {
buffers.push(chunk);
});
req.on('error', (err) => {
// This prints the error message and stack trace to `stderr`.
console.log("Error: %s \n" + err.stack);
});
req.on('end', function () {
try {
jsonString = JSON.parse(Buffer.concat(buffers).toString());
var action = jsonString.markers[0]['action'];
if(action=="START_CAPTURE"){
main();
}
}
catch(e) {
jsonString = JSON.parse(JSON.stringify(Buffer.concat(buffers).toString()));
console.log('\nError \n ' + JSON.stringify(jsonString));
}
});
}
res.end();
console.log('Response ended here. \n ');
});
httpServer.listen(http_port, () => {
console.log("Web server is listening on port %s \n", http_port);
});
This is how it works.
I am clicking a button (START_CAPTURE) from my web site to start capturing. Then capture start. Then i am clicking a button (STOP_CAPTURE) to stop capturing.
everything is working fine. If i do like this.
But if i click START_CAPTURE using two different browsers, then i clicked on STOP_CAPTURE button from any browser window, both instances are getting stop.
I know it is happened because of this lines.
while(action!="STOP_CAPTURE"){
try {
await page.waitForSelector('[class^=modal] > [class^=content] > button[description="Logs you out"]', {
timeout: 1000
});
} catch (err) {
// Do nothing
}
}
Is there anyway to stop only requested instance ? How can i achieve it ?

Related

webpush not wokring in chrome on localhost

I'm building a website with node.js and I' m making some push notifications and it doesn' t send them on chrome version 109.0.5414.120 . I tried running it on opera gx and it worked there. I have to use chrome because its for a school project and all my teachers use chrome and the don't want to download new programms
the code;
app.js
const express = require("express")
const webpush = require('web-push')
const app = express()
app.use(express.json());
const path = require("path")
app.use(express.static(path.join(__dirname, 'client')))
const publicKey = "BL2QpTNn-CZARUqJhm4tDPPful3TMIjugZdyi1WNIcaps21w7KJFy4cjilMNk-NbeEIwWVA5ddCXpOStd6RTuXA"
const privateKey = "dWcFCcnNS-uBYS6GISodobLXht-9KpOQmeHh1h89T7w"
webpush.setVapidDetails("mailto:thdegroote18#gmail.com", publicKey, privateKey)
app.post("/subscribe", async (req, res) => {
try {
// Subscription Details From the client side , We would get back to this
const subscription = req.body;
subscribers.push(subscription);
// Save the new subscrber to the subscribers file
fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));
res.status(201).send("Subscription Saved");
} catch (error) {
console.error(error);
}
});
const subscribers = require("./subscribers.json")
const fs = require("fs")
async function sendPushNotificaiton() {
for (let i = 0; i < subscribers.length; i++) {
const subscription = subscribers[i];
//Notification Payload, this could contain more information about the notification
const payload = {
title: "Push Test",
body: " Push Notification Message",
icon: "https://blog.mensaiah.com/assets/round_logo.png",
};
//Pass object into sendNotification
await webpush.sendNotification(subscription, JSON.stringify(payload));
}
}
//Send Notification Every Minute
const durationInMillisecond = 60 * 10000
setInterval(sendPushNotificaiton,durationInMillisecond);
const port = 1999
app.listen(port, () => {
console.log(`server started on port ${port}`)
})
client.js
const publicVapidKey = "BL2QpTNn-CZARUqJhm4tDPPful3TMIjugZdyi1WNIcaps21w7KJFy4cjilMNk-NbeEIwWVA5ddCXpOStd6RTuXA";
async function subscribeToPush() {
console.log("Registering service worker...");
const register = await navigator.serviceWorker.register("/worker.js", {
scope: "/"
});
console.log("Service Worker Registered...");
console.log("Registering Push...");
const subscription = await register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
});
console.log("Push Registered...");
console.log("Subscribing for Push ...");
await fetch("http://localhost:1999/subscribe", {
method: "POST",
body: JSON.stringify(subscription),
headers: {
"Content-Type":"application/json"
}
});
}
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
if ('serviceWorker' in navigator) {
subscribeToPush().catch(console.log);
}
worker.js
self.addEventListener("push", e => {
// Data from service
const data = e.data.json();
console.log("Push Recieved...");
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon,
});
});

How To LongPool in Node.js and Javascript without not making alot of network request

I make a Longpolling for this little project but alot of Network Request are been sent and later ther browser froze
.
Is there anything that i am doing wrong here
On the server side
server.js
`
//...
const PORT = 3000;
let subscribers = Object.create(null);
const server = createServer((req, res) => {
const parsedUrl = parse(req.url, true);
const urlPath = parsedUrl.pathname;
const queryStringObject = parsedUrl.query;
const method = req.method.toLowerCase();
if (urlPath === "/" && method === "get") {
res.writeHead(200, {
"Content-Type": "text/html",
"Access-Control-Allow-Origin": "*",
});
res.end(`<h1>Home Page of the API</h1>`);
return;
}
if (urlPath === "/datas" && method === "get") {
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Cache-Control": "no-cache, must-revalidate",
});
let id = Math.random();
subscribers[id] = res;
fs.readFile(`${process.cwd()}/data/datas.json`, "utf-8", (err, data) => {
res.end(data);
});
req.on("close", function () {
delete subscribers[id];
// console.log(`${id} deleted`);
});
return;
}
});
server.listen(PORT, (err) => {
console.log(`Server up and running,\nYou can now visit http://localhost:3000`);
});
`
and on the client Side
app.js
`
const prices = document.querySelector(".prices");
function createEl(resultDatas) {
prices.innerHTML = "";
resultDatas.forEach((resultData) => {
const div = document.createElement("div");
div.classList.add("element-container");
const p = document.createElement("p");
p.innerHTML = resultData.title;
if (resultData.title.toLowerCase() === "silver") {
p.classList.add(`silver`);
}
p.classList.add(`title`);
div.appendChild(p);
const h3 = document.createElement("h3");
h3.innerHTML = resultData.price;
h3.classList.add("price");
div.appendChild(h3);
prices.append(div);
});
}
let tickerData = null;
const fetchTickerValue = async () => {
try {
const response = await fetch("http://localhost:3000/datas");
const data = await response.json();
createEl(data);
} catch (error) {
console.error(error?.message ?? "ticker call failed");
} finally {
fetchTickerValue();
}
};
fetchTickerValue();
if (tickerData) console.log(tickerData);
`
I want only one request to be send while waiting for the response from the server

Azure: INFO - Waiting for response to warmup request for container ... Elapsed time = x sec

My app fails on prod and can't find a way how to fix. It works on another environments.
Some logs from the console:
2022-08-22T23:56:05.760Z INFO - Waiting for response to warmup request for container projectprod-fe_0_fd84e. Elapsed time = [225.2643051] sec
2022-08-22T23:56:35.818Z ERROR - Container projectprodfe_0_fd84e for site teamgullitpreview-fe did not start within expected time limit. Elapsed time = 255.322965 sec
It is next.js app and I create middlewares for it.
const next = require('next');
const { parse } = require('url');
nextMiddleware
async function nextMiddleware(dev = false) {
const app = next({ dev });
const handle = app.getRequestHandler();
await app.prepare();
return function nextHandler(req, res) {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
};
}
redirectMiddleware
const path = require('path');
const fs = require('fs');
const staticFiles = ['_next', '/', 'images', 'api'];
const getRedirect = async (srcPath) => {
try {
const url = `${process.env.NEXT_PUBLIC_apiUrl}/redirect?path=${srcPath}`;
const response = await fetch(url);
const json = await response.json();
return json;
} catch (e) {
throw new Error(e);
}
};
function redirecter(pathname) {
return new Promise((resolve, reject) => {
const pathParts = pathname.split('/');
if (staticFiles.indexOf(pathParts[1]) > -1) {
resolve({
shouldRedirect: false,
redirectData: {},
});
} else {
const possibleFile = `${path.resolve(
__dirname,
'../../public',
)}${pathname}`;
if (fs.existsSync(possibleFile)) {
resolve({
shouldRedirect: false,
redirectData: {},
});
} else {
getRedirect(pathname)
.then((result) => {
resolve({
shouldRedirect: true,
redirectData: result,
});
})
.catch((e) => {
reject(e);
});
}
}
});
}
async function redirectMiddleware(req, res, next) {
const parsedUrl = parse(req.url, true);
const { pathname } = parsedUrl;
try {
const { shouldRedirect, redirectData } = await redirecter(pathname);
if (shouldRedirect && redirectData.destination) {
const redirectUri = `${process.env.NEXT_PUBLIC_hostname}${
redirectData.type ? redirectData.type : ''
}${redirectData.destination}`;
res.writeHead(redirectData.statusCode[0], {
Location: redirectUri,
});
res.end();
}
} catch (e) {
next();
} finally {
next();
}
}
What I do wrong in this file or whenever?
const http = require('http');
const express = require('express');
const redirectMiddleware = require('./src/server/redirectMiddleware');
const nextMiddleware = require('./src/server/nextMiddleware');
const port = process.env.PORT || 3000;
async function bootstrap() {
const isDevelopment = process.argv.includes('--dev');
const app = express();
app.use(await redirectMiddleware);
app.use(await nextMiddleware(isDevelopment));
const server = http.createServer(app);
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
}
bootstrap().catch((err) => {
console.error('something went wrong booting up the server.');
console.error(err);
process.exit(1);
});
I have no idea what's wrong and how to debugg it. Is anyone who experienced it before?

NodeJS Error in if else case - Can't set headers after they are sent

I know, this is something old. There are many questions regarding to this. But none of them didn't guide me or didn't gave me the actual concept.
My case is:
if something
render something
else
render somethingAnother
Why is this logic generates this error enter image description here
After 1st execution, I'm not able to continue this process (I could continue for a while, but after some time error will come), by pressing back button of browser and then returning back to the home page. Everytime I should restart my server using node command. Why headers won't reset if I press back button of browser, how to do some header reset or something which will correct my logic.
const cv = require('opencv4nodejs');
var async = require('async');
var OrderID;
var OrderNo;
var compare = 0;
var CompanyName;
var notSimilar = 0;
const download = require('image-downloader')
const distanceThreshold = 30;
var url;
var FolderPath;
var isSimilar = 0;
var j = 0;
var image1;
var dbPath;
var filterCount = 0;
var image2;
var dbImgCount = 0;
var express = require('express');
var request = require('request');
var app = express();
app.set('view engine', 'pug')
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('userPhoto');
const sql = require("mssql");
var config = {
user: '***',
password: '****',
server: '192.168.5.100\\SQLEXPRESS',
database: 'Test_MatdesignDB1',
connectionTimeout: 300000,
requestTimeout: 300000,
pool: {
idleTimeoutMillis: 300000,
max: 100
}
};
sql.connect(config).then(pool => {
return pool.request()
.query('select count(*) from OrderImageUpload; select FolderPath from OrderImageUpload;')
}).then(result => {
var a = JSON.stringify(result.recordset[0]);
dbImgCount = a.slice(4,6);
FolderPath = result.recordsets[1];
sql.close();
}).catch(err => {
console.log(err);
sql.close();
})
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/api/photo',function(req,res){
compare = 1;
upload(req,res,function(err) {
if(err) {
console.log(err);
res.send("File uploading error");
}
else{
// console.log("Success");
image1 = req.file.filename;
var matchFeatures = ({ url, img1, img2, detector, matchFunc }) => {
// detect keypoints
const keyPoints1 = detector.detect(img1);
const keyPoints2 = detector.detect(img2);
// compute feature descriptors
const descriptors1 = detector.compute(img1, keyPoints1);
const descriptors2 = detector.compute(img2, keyPoints2);
// match the feature descriptors
const matches = matchFunc(descriptors1, descriptors2);
// only keep good matches
const bestN = 40;
const bestMatches = matches.sort(
(match1, match2) => (match1.distance - match2.distance)
).slice(0, bestN);
//console.log(bestMatches);
for(var i=0; i<bestN; i++){
if((bestMatches[i].distance) <= (distanceThreshold)){
filterCount++;
}
}
if(filterCount >= (bestN/4))
isSimilar = 1;
if(isSimilar){
notSimilar = 0;
filterCount = 0;
isSimilar = 0;
console.log("Similar images\n");
dbPath = url;
sql.close();
(async function() {
try {
let pool = await sql.connect(config)
let result1 = await pool.request()
.query("select OrderID from Test_MatdesignDB1.dbo.OrderImageUpload where FolderPath = '"+dbPath+"';")
OrderID = result1.recordset[0].OrderID;
let result2 = await pool.request()
.query('select OrderNo , CompanyName from Test_MatdesignDB1.dbo.[Order] where OrderID = '+OrderID);
OrderNo = result2.recordset[0].OrderNo;
CompanyName = result2.recordset[0].CompanyName;
res.render('similar', { title: 'Similar', CompanyName: CompanyName, OrderID: OrderID, OrderNo: OrderNo, img_path_var : dbPath }) //Render number 1 in 'if' case
} catch (err) {
console.log(err);
sql.close();
}
sql.close();
})()
sql.on('error', err => {
console.log(err);
})
}
else{
isSimilar = 0;
filterCount = 0;
notSimilar++;
if(notSimilar >= (dbImgCount ))
{
notSimilar = 0;
res.render('notSimilar', { title: 'Not Similar', message: 'No Similar Images' }) //Render number 2 in 'else' case
}
console.log("Not similar\n");
}
return cv.drawMatches(
img1,
img2,
keyPoints1,
keyPoints2,
bestMatches
);
};
for (j=0; j<dbImgCount; j++) {
(function(j) {
async.waterfall([
async function downloadIMG(done) {
try {
var options = {
url: FolderPath[j].FolderPath,
dest: '/home/ubuntu/imgCompare/DBimages/'
}
const { filename, image } = await download.image(options);
return [filename, options.url];
} catch (e) {
console.error(e)
}
},
async function featureMatching([a, MatchURL], done){
const img1 = cv.imread(image1);
url = MatchURL;;
const img = a.slice(33);
const img2 = cv.imread('./DBimages/'+img);
const orbMatchesImg = matchFeatures({
url,
img1,
img2,
detector: new cv.ORBDetector(),
matchFunc: cv.matchBruteForceHamming
});
done(null);
}
],
function (err) {});
})(j);
}
}
});
});
app.listen(5000,function(){
console.log("Working on port 5000");
});
You need to add return before rendering a view. It's happening because the view rendering is happening more than 1 time there must be a condition in your code which is letting views to render multiple times. Add this return statement:
return res.render();
You're getting this error because you're calling matchFeatures() multiple times within a for loop.
app.post('/api/photo', function (req, res) {
var matchFeatures = ({url, img1, img2, detector, matchFunc}) => {
if (isSimilar) {
res.render('similar', {
title: 'Similar',
...
}) //Render number 1 in 'if' case
} else {
res.render('notSimilar', {
title: 'Not Similar',
message: 'No Similar Images'
}) //Render number 2 in 'else' case
}
};
for (j = 0; j < dbImgCount; j++) {
async function featureMatching() {
const orbMatchesImg = matchFeatures({ // since you're calling it multiple times here
url, // matchFeatures() will attempt to send
img1, // responses multiple times
img2,
detector: new cv.ORBDetector(),
matchFunc: cv.matchBruteForceHamming
});
}
}
});
To fix this, You need to consolidate all these responses and send to client only once.
I figured out the error. I didn't reset the variable notSimilar at the entry point.
Done resetting of notSimilar as below, no error! Thanks Everyone.
app.post('/api/photo',function(req,res){
notSimilar = 0;

Chunk/Stream API data using Node.js

We have requirement where we need to write a node application which can read URL of image from database (approx more than million). Use image-size npm package to retrieve image meta data like height, width. Here should be an API which can list out result.
I am able to console log data but when i convert it to API, i need to chunk data so it can start appearing on browser and i'm unable to do that and need help. Here is my code
var express = require('express');
var url = require('url');
var http = require('http');
var sizeOf = require('image-size');
const sql = require('mssql');
var app = express();
var port = process.env.PORT || 3000;
const hostname = 'localhost';
var config1 = {
user: '*********',
password: '*********',
server: '*********',
database: '*******',
port: 1433,
debug: true,
options: {
encrypt: false // Use this if you're on Windows Azure
}
};
app.get('/', function(req, res){
//res.writeHead(200, { 'Content-Type': 'application/json' });
var finalResult = [];
sql.close();
sql.connect(config1, function (err) {
if (err) console.log(err);
const request = new sql.Request()
var myQuery = `select imagename from media`;
request.stream = true;
request.query(myQuery);
request.on('row', row => {
//console.log('Image : ' + row.ImageUrl);
if (row.ImageUrl != ''){
if (row.ImageUrl.indexOf('http') < 0)
row.ImageUrl = "http:" + row.ImageUrl;
var options = url.parse(row.ImageUrl);
http.get(options, function (response) {
if (response.statusCode == 200)
{
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function() {
var buffer = Buffer.concat(chunks);
//console.log(options.href);
//console.log(sizeOf(buffer).height);
var result = {};
result.MaskUrl = row.MaskUrl;
result.ImageUrl = options.href;
result.Height = sizeOf(buffer).height;
result.Width = sizeOf(buffer).width;
result.statusCode = 200;
finalResult.push(result);
//console.log(result);
console.log(finalResult);
res.write(result, function(){
res.end();
});
});
}
else
{
var result = {};
result.MaskUrl = row.MaskUrl;
result.ImageUrl = options.href;
result.Height = 0;
result.Width = 0;
result.statusCode = response.statusCode;
finalResult.push(result);
console.log(result);
res.write(result, function(){
res.end();
});
}
});
}
})
request.on('error', err => {
console.log ('Error for ' + row.ImageUrl );
})
request.on('done', err => {
console.log('Last Time' + finalResult.length);
})
// request.query(myQuery,(err,result) =>{
// console.log(result);
// });
});
console.log('Last Time' + finalResult.length);
res.send(finalResult);
});
app.listen(port, hostname, function(){
console.log('ImageSize running on PORT: ' + port);
});
I tried res.write, res.end without any success.
The probable reason for your problem is that here:
res.write(result, function(){
res.end();
});
You end and close the request just after the first image is read.
I would rewrite the code a little and use some functional framework, like scramjet, to stream the data straight from the DB. As Nicholas pointed out it's not super easy to run your code so I'm writing blindly - but if you fix any of my obvious error this should just work:
First:
npm install scramjet JSONStream node-fetch
Next, try this code:
var express = require('express');
var sizeOf = require('image-size');
const sql = require('mssql');
var app = express();
var port = process.env.PORT || 3000;
const hostname = 'localhost';
const {DataStream} = require('scramjet');
const fetch = require('node-fetch');
const JSONStream = require('JSONStream');
var config1 = {
user: '*********',
password: '*********',
server: '*********',
database: '*******',
port: 1433,
debug: true,
options: {
encrypt: false // Use this if you're on Windows Azure
}
};
app.get('/', function(req, res, next){
// you should consider not doing these two lines on each request,
// but I don't want to mess you code...
sql.close();
sql.connect(config1, function (err) {
if (err) next(err);
res.writeHead(200, { 'Content-Type': 'application/json' });
const request = new sql.Request();
var myQuery = `select imagename from media`;
request.stream = true;
request.query(myQuery);
const stream = new DataStream();
request.on('row', row => stream.write(row));
stream.filter(
row => row.ImageUrl !== ''
)
.map(
async row => {
if (row.ImageUrl.indexOf('http') !== 0) // url must start with http.
row.ImageUrl = "http:" + row.ImageUrl;
const response = await fetch(row.ImageUrl);
let size = {width:0, height:0};
if (response.status === 200) {
const buffer = await response.buffer();
size = sizeOf(buffer);
}
return {
MaskUrl: row.MaskUrl,
ImageUrl: row.ImageUrl,
Height: size.height,
Width: size.width,
statusCode: response.status
};
}
)
.pipe(
JSONStream.stringify()
).pipe(
res
);
request.on('error', () => {
res.writeHead(500, { 'Content-Type': 'application/json' });
stream.end("{error:true}");
});
request.on('done', () => stream.end());
});
});
app.listen(port, hostname, function(){
console.log('ImageSize running on PORT: ' + port);
});

Resources