I am using puppeteer in the following project https://github.com/gatwirival/Whatsapp-api.git .It's working fine locally but during deployment in Heroku, it runs for a little while then crashes with the following error FATAL:zygote_host_impl_linux.cc(117)] No usable sandbox!
App.js
const express = require('express');
const puppeteer = require("puppeteer");
const fs = require('fs');
const createError = require('http-errors');
const morgan = require('morgan');
const { Client } = require('whatsapp-web.js');
require('dotenv').config();
const app = express();
const SESSION_FILE_PATH = './session.json';
let sessionCfg;
if (fs.existsSync(SESSION_FILE_PATH)) {
sessionCfg = require(SESSION_FILE_PATH);
}
const client = new Client({
puppeteer: { headless: false }, // Make headless true or remove to run browser in background
session: sessionCfg,
});
client.initialize();
client.on('qr', qr => {
// NOTE: This event will not be fired if a session is specified.
console.log('QR RECEIVED', qr);
app.get('/getqr', (req, res, next) => {
res.send({ qr });
});
});
client.on('authenticated', session => {
console.log('AUTHENTICATED', session);
sessionCfg = session;
fs.writeFile(SESSION_FILE_PATH, JSON.stringify(session), function (err) {
if (err) {
console.error(err);
}
});
});
client.on('auth_failure', msg => {
// Fired if session restore was unsuccessfull
console.error('AUTHENTICATION FAILURE', msg);
});
client.on('ready', () => {
console.log('READY');
});
// Run `npm i qrcode-terminal` before this
const qrcode = require('qrcode-terminal')
client.on('qr', qr => {
// NOTE: This event will not be fired if a session is specified.
console.log('QR RECEIVED', qr);
qrcode.generate(qr, { small: true });
app.get('/getqr', (req, res, next) => {
res.send({ qr });
});
});
app.post('/sendmessage', async (req, res, next) => {
try {
// Magic happens here
} catch (error) {
next(error)
}
})
app.post('/sendmessage', async (req, res, next) => {
try {
const { number, message } = req.body; // Get the body
const msg = await client.sendMessage(`${number}#c.us`, message); // Send the message
res.send({ msg }); // Send the response
} catch (error) {
next(error);
}
});
//puppeter
app.listen(process.env.PORT || 3000, function(){
const browser = puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
app.get("/", (req, res) => {
let page;
(async () => {
page = await (await browser).newPage();
await page.setContent(`<p>web running at ${Date()}</p>`);
res.send(await page.content());
})()
.catch(err => res.sendStatus(500))
.finally(async () => await page.close())
;
});
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});
What I have tried:
Added the following code snippet and yet I get the error
const browser = puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
After this failed I tried this.
-sudo sysctl -w kernel.unprivileged_userns_clone=1
to access the sandbox of chromium.
Related
Creating a chat server.
However, when I send a message, it goes into the queue, but then mysql doesn't have data. I think the server is turning on, but I keep getting an error like Socket closed absolutely during opening handshake Help me
consumer.js
`
Consumer: async () => {
try {
const connect = await amqp.connect(amqpURL);
const ch = await connect.createChannel();
const queue = "queue";
await ch.assertQueue(queue, async (message) => {
console.log(message.value.toString());
});
arr.push(JSON.parse(message.value.toString()));
console.log(arr);
if (arr.length == 5) {
try {
const rows = await chatting
.bulkCreate(arr, { hooks: true })
.catch((err) => {
console.log(err);
});
arr.splice(0);
console.log(rows);
return;
} catch (err) {
console.log(err);
}
ch.ack(message);
}
} catch (err) {
console.log(err);
}
},
app.js
`
const express = require("express");
const app = express();
const cors = require("cors");
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const { chatting, sequelize } = require("./models");
const rabbitmq = require("./rabbit");
//const consumer = require("./consumer");
const amqp = require("amqplib");
const amqpURL = "amqp://localhost:5672";
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
sequelize
.sync({ force: false })
.then(() => {
console.log("연결됨");
})
.catch((err) => {
console.log(err);
});
const send = async (message) => {
try {
console.log(message);
const connect = await amqp.connect(amqpURL);
const channel = await connect.createChannel();
const exchange = "exchange";
const queue = "queue";
const routingkey = "sample.routing";
await channel
.assertExchange(exchange, "direct", { durable: true })
.catch((err) => console.log(err));
await channel.assertQueue(queue, { durable: true });
await channel.bindQueue(queue, exchange, routingkey);
await channel.publish(exchange, routingkey, Buffer.from(message));
} catch (err) {
console.log(err);
}
};
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.get("/test", async (req, res) => {
try {
const { idx } = req.body;
const rows = await chatting.findOne({ idx: idx });
if (rows) return res.status(200).json({ result: rows });
} catch (err) {
console.log(err);
}
});
io.on("connection", (socket) => {
console.log("connect");
socket.on("disconnect", () => {
console.log("disconnect");
});
});
io.emit("some event", {
someProperty: "some value",
otherProperty: "other value",
});
io.on("connection", (socket) => {
socket.on("chat message", async (message) => {
try {
await send(JSON.stringify(message));
io.emit("chat message", message);
console.log(message);
} catch (err) {
console.log(err);
}
});
});
server.listen(2022, () => {
console.log("listening on :2022");
});
rabbitmq.Consumer();
`
`
pic
enter image description here
I tried many things and I want to solve
Error: Socket closed abruptly during opening handshake
at Socket.endWhileOpening
this error
im working on a vidoe conferencing application and I cant seem to get the screen sharing working getting an error "mediaTypeError: Cannot read properties of undefined (reading 'getSender')". The screensharing is able to start but nothing is being shared
This is my server file.
const express = require("express");
const app = express();
const server = require("http").Server(app);
const { v4: uuidv4 } = require("uuid");
const io = require("socket.io")(server);
// Peer
const { ExpressPeerServer } = require("peer");
const peerServer = ExpressPeerServer(server, {
debug: true,
});
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use("/peerjs", peerServer);
app.get("/", (req, rsp) => {
rsp.redirect(`/${uuidv4()}`);
});
app.get("/:room", (req, res) => {
res.render("room", { roomId: req.params.room });
});
io.on("connection", (socket) => {
socket.on("join-room", (roomId, userId) => {
socket.join(roomId);
socket.to(roomId).emit("user-connected", userId);
socket.on("message", (message) => {
io.to(roomId).emit("createMessage", message);
});
});
});
server.listen(process.env.PORT || 3030);
Codes for screensharing where there seem to be an issue with getSender
share__Btn.addEventListener("click", (e) => {
navigator.mediaDevices.getDisplayMedia({
video: {
cursor: "always"
},
audio: {
echoCancellation: true,
noiseSuppression: true
}
}).then((stream) => {
let videoTrack = stream.getVideoTracks()[0];
let sender = currentPeer.getSender().find(function (s) {
return s.track.kind == videoTrack.kind
})
sender.replaceTrack(videoTrack)
}).catch((err) => {
console.log("unable to get display media" + err)
})
})
});
peer.on("call", function (call) {
getUserMedia(
{ video: true, audio: true },
function (stream) {
call.answer(stream); // Answer the call with stream.
const video = document.createElement("video");
call.on("stream", function (remoteStream) {
if (!peerList.includes(call.peer)) {
addVideoStream(video, remoteStream);
currentPeer = call.peerConnection
peerList.push(call.peer);
}
});
},
function (err) {
console.log("Failed to get local stream", err);
}
);
});
Github link for the full codes: https://github.com/sucxh/simLearn
I'm assuming that currentPeer is an RTCPeerConnection as documented here: https://peerjs.com/docs.html#dataconnection-peerconnection. In that case it's a simple typo. The method is called getSenders() and not getSender(). Adding the missing "s" should make the error go away.
Whenever I try to run the function refreshStock() in an endpoint in one of the API endpoints /api/seller/deactivate it gives me this error:
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1318:16)
at listenInCluster (net.js:1366:12)
at Server.listen (net.js:1452:7)
at C:\Users\***\Documents\GitHub\***\***\.next\server\pages\api\seller\deactivate.js:191:10
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command
It looks like it's trying to restart the server, but it happens after it compiles, is there something I'm doing wrong, I've followed a couple of tutorials on medium, and they give this same type of code, just not ES Modules. I want to use ES Modules because it is what my database functions are written in.
Server.js:
import express from 'express';
import { createServer } from 'http';
import next from 'next';
import models from './server/models';
import { genStock } from './server/lib/functions';
import { Server } from 'socket.io';
const port = parseInt(process.env.PORT || '3000', 10);
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
const app = express();
const server = createServer(app);
const io = new Server(server);
const Users = models.users;
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
if (!socket.handshake.auth.token) return next(err);
let user = await Users.findOne({
where: {
socket_token: socket.handshake.auth.token,
},
});
if (!user) {
console.log('unauthenticated socket');
socket.disconnect();
next(err);
}
await Users.update(
{ socket_id: socket.id },
{
where: {
socket_token: socket.handshake.auth.token,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
// Works fine
const stock = await genStock();
socket.emit('updateStock', stock);
});
// Fails with address already in use :::3000
export async function refreshStock() {
const stock = await genStock();
io.emit('updateStock', stock);
}
nextApp.prepare().then(async () => {
app.all('*', (req, res) => nextHandler(req, res));
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
This is meant to refresh the stock after a seller deactivates their account and sends all users the new stock.
/api/seller/deactivate
....
await refreshStock();
....
I figured it out, I just split up the WebSocket server and the next.js one. I have whitelisted local IPs that may appear to only allow server-to-server communication. Although I don't think this is full-proof as there is most likely a better way to have this type of communication but for now it works.
/**
* This server cannot be imported in /api folders, it won't work.
* Although it can import other functions
* */
import express from 'express';
import { createServer } from 'http';
import session from 'express-session';
import { Server } from 'socket.io';
import { genStock } from './server/lib/stockFunctions';
import { sessionStore } from './server/lib/session';
import passport from './server/lib/passport';
import models from './server/models';
const authorizedIPs = ['::1', '127.0.0.1', '::ffff:127.0.0.1'];
const Users = models.users;
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: `http://localhost:3000`,
methods: ['GET', 'POST'],
credentials: true,
},
});
const wrap = (middleware) => (socket, next) => middleware(socket.request, {}, next);
io.use(
wrap(
session({
secret: "---",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/',
sameSite: 'lax',
},
store: sessionStore,
}),
),
);
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
const user = socket.request.user;
if (!user) return next(err);
await Users.update(
{ socket_id: socket.id },
{
where: {
id: user.id,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
const stock = await genStock();
socket.emit('updateStock', stock);
});
app.post('/refresh-stock', async function (req, res) {
const ip = req.ip;
if (!authorizedIPs.includes(ip)) {
console.log(ip);
return res.status(401).json({ success: false });
}
const newStock = await genStock();
io.emit('updateStock', newStock);
return res.status(200).json({ success: true });
});
httpServer.listen(3001);
console.log(`> Websockets ready on http://localhost:3001`);
I've created a simple next.js application and provide it with a backend of express.js, now all I want is whenever someone visits the site a hit should originate on the server and the server should communicate the number of hits back to next.js application. The code of server.js file goes here:
const express = require("express");
const next = require("next");
var counter = 0;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
server.get("*", (req, res) => {
counter++;
return handle(req, res);
});
server.listen(3000, (err) => {
if (err) throw err;
console.log("> Ready on http://localhost:3000");
});
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
});
as seen here I've set counter variable to zero and want it to be increased whenever a get request is made (so wrote counter++ inside server.get function) but how could I display this number of hits on the route visitor is visiting?
You can use express's res.locals in order to pass the data on the request object.
app
.prepare()
.then(() => {
const server = express();
server.get('*', (req, res) => {
counter++;
res.locals.counter = counter;
//----^
return handle(req, res);
});
server.listen(3000, (err) => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
});
Then this request object will be available in getInitialProps of the page that is needed.
// some-page.js
const Page = ({ counter }) => <div>{counter}</div>;
Page.getInitialProps = ({ req, res }) => {
if (res) {
// this means that you are on the server
return { counter: res.locals.counter };
}
return {};
};
I am trying to get the username of the profile on the url of that users page. Just to figure out the basic of getting Instagram data
The code below is what I have tried to do and miserably failed(also I am a beginner sorry for bad code)
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request-promise');
const path = require('path');
var cheerio = require('cheerio');
const app = express()
var followers = [];
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs')
app.get('/', function (req, res) {
request({
method: 'GET',
url: 'https://www.instagram.com/unrivaledhype/'
}, function(err, response, body, callback) {
if(err) return console.error(err);
$ = cheerio.load(url);
var post = $("*");
var follwerCount = post.find('h1').text();
console.log(follwerCount);
followers.push({follwerCount: follwerCount})
});
res.send(JSON.stringify(followers, null, 4));
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
It just displays follwerCount:"" but(even though I named it misspelled followerCount I went for the username) although if someone can show me how to get the follower count that would be greatly appreciated.
Unfortunately, Instagram pages are rendered on the client side, so it is not possible to get information like the number of followers through this way.
A solution to this problem would be to use puppeteer.
With puppeteer you can start a headless version of chrome, which also interprets javascript, so that Instagram pages get rendered completely.
Example code:
const puppeteer = require('puppeteer')
class InstagramClient {
async start() {
this.browser = await puppeteer.launch({
headless: true //When set to true, a new browser window will ge opened
})
}
async stop() {
await this.browser.close()
}
async getFollowers(username) {
if (!this.browser) throw new Error('Browser not started')
const page = await this.browser.newPage()
await page.goto(`https://instagram.com/${username}/`)
const pageExists = await page.evaluate(_ => {
return document.querySelector('.error-container') === null
})
if (!pageExists) {
throw new Error(`Page of ${username} doesn't exist`)
}
//Wait until the page got completly renderer
await page.waitForSelector('h1')
const followers = await page.evaluate(username => {
//This code will get executed on the instagram page
//Get the number of followers
const followers = document.querySelector(`a[href="/accounts/login/?next=%2F${username}%2Ffollowers%2F&source=followed_by_list"]`).querySelector('span').innerText
//Return the number of followers back to the node process
return followers
}, username)
page.close()
return followers
}
}
module.exports = InstagramClient
const InstagramClient = require('./utils/instagram-client')
async function start() {
const client = new InstagramClient()
await client.start()
console.log('#instagram:', await client.getFollowers('instagram'))
console.log('#unrivaledhype:', await client.getFollowers('unrivaledhype'))
console.log('#teslamotors:', await client.getFollowers('teslamotors'))
await client.stop()
}
start()
Output:
#instagram: 309m
#unrivaledhype: 3,230
#teslamotors: 6m
If you want a more detailed explanation, check out this video:
A Guide to Web Scraping with NodeJS
Express example:
const express = require('express')
const InstagramClient = require('./utils/instagram-client')
const app = express()
const client = new InstagramClient()
app.get('/:instagramName/followers', async (request, response) => {
const instagramName = request.params.instagramName
try {
const followers = await client.getFollowers(instagramName)
response.json({
success: true,
followers: followers
})
} catch (e) {
response.json({
success: false,
error: e.toString()
})
return
}
})
async function start() {
await client.start()
app.listen(3000, _ => console.log('Server is listening on port 3000'))
}
start()