Deploy whatsapp-web bot on heroku - javascript

I'm creating a whatsapp bot using the node library whatsapp-web.js After I'm done with the script it looks something like (I just put a overview of the orignal script) -
index.js
const {Client, LocalAuth, MessageMedia } = require('whatsapp-web.js');
const qrcode = require('qrcode-terminal');
const client = new Client({
puppeteer: {
args: ['--no-sandbox', "--disable-setuid-sandbox"]
},
authStrategy: new LocalAuth()
});
client.on('qr', (qr) => {
console.log('qr received: ', qr);
qrcode.generate(qr, {small:true});
});
client.on('ready', () => {
console.log('READY');
});
client.on('message', async msg => {
let type = msg.type;
let chat = await msg.getChat();
if(chat.isGroup) {
//do something
}else {
//
if(msg.body === "ping") {
msg.reply("pong");
}
}
});
Everything is fine with the script and it works good on linux or ubuntu (I already added puppeteer build pack on that Heroku app). As I need to run that script continuously I decided to put that on a worker process.
Procfile
worker: node index.js
But now the problem comes in role, how can I authenticate here? I decided to remove that line from index.js
qrcode.generate(qr,{small:true});
And insted I thought I will print all the logs on heroku-cli
heroku logs -a wweb-bot
#my app named as wweb-bot
and from there access the key generated as qr. After that I'll turn it into a qrcode and scan it. When I did all setup and try it I was getting a continuously generating logs of qr keys. It's nonstop, and keep generating keys after every 15-20 sec. What's the problem here? Is it because Heroku has a read only environment or anything else is missing? Please help me how can i do it

remove or comment this code
// authStrategy: new LocalAuth()
it will not work on heroku
but as the code is on server, you don't need to scan again and again, you need to scan only you restart your server
but if you are facing puppeteer error then add these buildpacks in heroku /your project/settings/ scrol down to adduildpack
add these two buildpacks
https://github.com/jontewks/puppeteer-heroku-buildpack
https://github.com/heroku/heroku-buildpack-google-chrome
then redeploy your app

Edit: now whatsapp-web.js added new functionality of doing this called RemoteAuthStatergy just go throughout it.

Related

Discord.js not logging in

I cannot figure out why my bot is not working. Can someone please tell me why it is not logging in?? It shows the logo (the last console.log line), but does not say, "logged in as foo#1234". (I am not getting any errors as well.)
code removed because of answered question. the code worked fine ;)
Use client.once(‘ready’, async () => {//code here}); as a a pose to client.on()
As mentioned on discord.js Guide, here's the base code to get you started:
// Require the necessary discord.js classes
const { Client, Intents } = require('discord.js');
const { token } = require('./config.json');
// Create a new client instance
const client = new Client({ intents: [Intents.FLAGS.GUILDS] });
// When the client is ready, run this code (only once)
client.once('ready', () => {
console.log('Ready!');
});
// Login to Discord with your client's token
client.login(token);
Open your terminal and run node index.js (assuming that your file name is index.js) to start the process. If you see "Ready!" after a few seconds, you're good to go!
I recommend for you to follow this guide, it helped me a lot with the first steps with the discord bot.
The Token had reset for some reason, I do not remember resetting it, but after updating the token, it worked fine. Thank you for your answers and helpful comments.
If somebody else is having this problem, try resetting the token again.

How to deploy Next JS App with Mongoose(MongoDB) connection on Vercel?

I am facing issue while deploying my next js app on vercel with mongodb connection. I have added env variable also on vercel site where we deploy next js app. Is there something going wrong in the below file ?
next.config.js
module.exports = {
env: {
MONGODB_URI: "mongodb://localhost/tasksdb",
},
};
I have add env variable as well into my next js project
.env.local
MONGODB_URI = "mongodb://localhost/tasksdb"
I establish this mongodb connection from this doc https://mongoosejs.com/. It's provide us to connect with mongodb straightaway .
And this my mongodb connection establish code
import { connect, connection } from "mongoose";
const conn = {
isConnected: false,
};
export async function dbConnect() {
if (conn.isConected) return;
const db = await connect(process.env.MONGODB_URI);
conn.isConnected = db.connections[0].readyState;
// console.log(conn.isConnected);
// console.log(db.connection.db.databaseName)
}
connection.on("connected", () => {
console.log("Mongodb connected to db");
});
connection.on("error", (err) => {
console.error("Mongodb connected to", err.message);
});
Is there something wrong by creating the database this way because in local everything working fine ?
I don't think vercel's servers can comunicate with your localhost. You can try hosting your database in the mongodb cloud
The code seems to be fine, but you can not connect to Vercel using localhost. You can use Serverless Atlas version of MongoDB which is free you can host your database there and then connect using the link they will provide.
See : https://www.mongodb.com/pricing

Firestore function deployment error when using Twilio

I'm trying to integrate Twilio into a triggered Firestore function. The problem I'm having is when I add this code, I am unable to deploy ANY functions. As far as I know this is how to use twilio inside a cloud function. At the top I have this and I think firebase doesn't like something here because ALL functions stop deploying with this code.
// Used to send text messages
const twilio = require('twilio')
// const accountSid = functions.config().twilio.sid
// const authToken = functions.config().twilio.token
/* eslint new-cap: ["error", { "newIsCap": false }] */
const client = new twilio('ACblahblahblah', 'ccblahblahblah') // sid and token
const twilioNumber = '+13344714571' // your twilio phone number
Within the triggered function I have this. But I don't think the issue is here:
return client.messages.create({
to: someNumber,
from: twilioNumber,
body: 'Some message.'
}).then((data) => {
console.log(data)
}).catch((error) => {
console.log(error)
})
I have a valid Twilio account set up. The function logs don't tell me much other than that the function cannot be initialized. What am I missing? Seems like this has worked for others.
Figured it out about 5 minutes after posting the question. I had not installed twilio in the functions folder but rather the root of the project. Once I executed
npm install twilio
in the functions folder, the functions started deploying. Too bad there was no error in the logs that said something like "required package is missing" or something like that.

Have array from Puppeteer/Cheerios program. Have ionic phone app design. How to move the array to the angular code?

This is my first phone app. I am using Ionic for the cross-platform work which uses Angular as you know I'm sure. I have a separate program which scrapes a webpage using puppeteer and cheerio and creates an array of values from the web page. This works.
I'm not sure how I get the array in my web scraping program read by my ionic/angular program.
I have a basic ionic setup and am just trying a most basic activity of being able to see the array from the ionic/angular side but after trying to put it in several places I realized I really didnt know where to import the code to ionic/angular which returns the array or where to put the webscraper code directly in one of the .ts files or ???
This is my web scraping program:
const puppeteer = require('puppeteer'); // live webscraping
let scrape = async () => {
const browser = await puppeteer.launch({
headless: true
});
const page = await browser.newPage();
await page.goto('--page url here --'); // link to page
const result = await page.evaluate(() => {
let data = []; // Create an empty array that will store our data
let elements = document.querySelectorAll('.list-myinfo-block'); // Select all Products
let photo_elements = document.getElementsByTagName('img'); //
var photo_count = 0;
for (var element of elements) { // Loop through each product getting photos
let picture_link = photo_elements[photo_count].src;
let name = element.childNodes[1].innerText;
let itype = element.childNodes[9].innerText
data.push({
picture_link,
name,
itype
}); // Push an object with the data onto our array
photo_count = photo_count + 1;
}
return data;
});
browser.close();
return result; // Return the data
};
scrape().then((value) => {
console.log(value); // Success!
});
When I run the webscraping program I see the array with the correct values in it. Its getting it into the ionic part of it. Sometimes the ionic phone page will show up with nothing in it, sometimes it says it cannot find "/" ... I've tried so many different places and looked all over the web that I have quite a combination of errors. I know I'm putting it in the wrong places - or maybe not everywhere I should. Thank you!
You need a server which will run the scraper on demand.
Any scraper that uses a real browser (ie: chromium) will have to run in a OS that supports it. There is no other way.
Think about this,
Does your mobile support chromium and nodeJS? It does not. There are no chromium build for mobile which supports automation with nodeJS (yet).
Can you run a browser inside another browser? You cannot.
Way 1: Remote wsEndpoint
There are some services which offers wsEndpoint but I will not mention them here. I will describe how you can create your own wsEndPoint and use it.
Run browser and Get wsEndpoint
The following code will launch a puppeteer instance whenever you connect to it. You have to run it inside a server.
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = new httpProxy.createProxyServer();
http
.createServer()
.on('upgrade', async(req, socket, head) => {
const browser = await puppeteer.launch();
const target = browser.wsEndpoint();
proxyy.ws(req, socket, head, { target })
})
.listen(8080);
When you run this on the server/terminal, you can use the ip of the server to connect. In my case it's ws://127.0.0.1:8080.
Use puppeteer-web
Now you will need to install puppeteer-web on your mobile/web app. To bundle Puppeteer using Browserify follow the instruction below.
Clone Puppeteer repository:
git clone https://github.com/GoogleChrome/puppeteer && cd puppeteer
npm install
npm run bundle
This will create ./utils/browser/puppeteer-web.js file that contains Puppeteer bundle.
You can use it later on in your web page to drive another browser instance through its WS Endpoint:
<script src='./puppeteer-web.js'></script>
<script>
const puppeteer = require('puppeteer');
const browser = await puppeteer.connect({
browserWSEndpoint: '<another-browser-ws-endpont>'
});
// ... drive automation ...
</script>
Way 2: Use an API
I will use express for a minimal setup. Consider your scrape function is exported to a file called scrape.js and you have the following index.js file.
const express = require('express')
const scrape= require('./scrape')
const app = express()
app.get('/', function (req, res) {
scrape().then(data=>res.send({data}))
})
app.listen(8080)
This will launch a express API on the port 8080.
Now if you run it with node index.js on a server, you can call it from any mobile/web app.
Helpful Resources
I had some fun with puppeteer and webpack,
playground-react-puppeteer
playground-electron-react-puppeteer-example
To keep the api running, you will need to learn a bit about backend and how to keep the server alive etc. See these links for full understanding of creating the server and more,
Official link to puppeteer-web
Puppeteer with docker
Docker with XVFB and Puppeteer
Puppeteer with chrome extension
Puppeteer with local wsEndpoint
Avoid memory leak on server

http-server net serving the fresh js file

I haven't used http-server npm module before!
i was just getting starting with using service worker by creating an example app using this blog as a source
In this the author have used http-server to demonstrate service worker!
From the blog, I copied the code snippet to check if chrome is supported
const check = () => {
if (!('serviceWorker' in navigator)) {
throw new Error('No Service Worker support!')
}
if (!('PushManager' in window)) {
throw new Error('No Push API Support!')
}
console.log('Everything works fine')
}
const main = () => {
check()
}
main()
Notice the console.log('Everything works fine')
Now, as i proceeded with Article, I changed my main.js as instructed to this
const check = () => {
if (!('serviceWorker' in navigator)) {
throw new Error('No Service Worker support!')
}
if (!('PushManager' in window)) {
throw new Error('No Push API Support!')
}
console.log(`Browser supports Pushmanager and Service worker`)
}
// Async so we can use await
const main = async () => {
check()
const swRegistration = await registerServiceWorker();
}
//To run service worker we need to first register service worker
//Registering Service Worker
const registerServiceWorker = async () => {
const swRegistration = await navigator.serviceWorker.register('service.js'); //notice the file name
return swRegistration;
}
but when I go the page, it keeps logging this from our first code snippet in the console
Everything works fine
I checked the main.js, and it appears the server is still serving the previous main.js instead of new one.
If I go manually to my file and open it without the server, the main.js shows my new code changes.
I have tried turning of the server (using ctrl/cmd + c) and restarting it again but no help.
Can someone help me out in fixing it?
Looks like http-server tells the browser to cache pages for an hour by default:
-c Set cache time (in seconds) for cache-control max-age header, e.g. -c10 for 10 seconds (defaults to '3600'). To disable caching, use -c-1.
Restart the server with http-server -c-1, then do a hard refresh in the browser (Ctrl/Cmd+Shift+R in Firefox or Chrome).

Categories

Resources