Whatsapp-Lite (Beta Mode) Added in Config Node

This commit is contained in:
rawee 2023-01-26 03:40:30 +05:30
parent 1830190943
commit f0221c4c70
14 changed files with 1456 additions and 251 deletions

BIN
.github/WhatsaaLite.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -4,8 +4,6 @@ Simple node for connecting Node-Red to Whatsapp :iphone:
Currently in developing mode, Continous updated may encounter. :sweat_smile: Currently in developing mode, Continous updated may encounter. :sweat_smile:
Working on WhatsappLite (Lite version of whatsapp Web baised on web sockets.)
## To Connect with Whatsapp ## To Connect with Whatsapp
![](./.github/admin_login.gif) ![](./.github/admin_login.gif)
@ -16,6 +14,15 @@ Working on WhatsappLite (Lite version of whatsapp Web baised on web sockets.)
4. Done - Whatsapp Connected. 4. Done - Whatsapp Connected.
5. Send "`!nodered`" to get a reply from Node-Red in Chats/Groups. 5. Send "`!nodered`" to get a reply from Node-Red in Chats/Groups.
### if Whatsapp Web not working ?
Their is lite version also avilable in it. Totally different from Whatapp-Web,
Whatsapp-Lite (Beta Mode) works on Web-Sockets only, It might work for you also.
Simply chosse `Whatsapp Lite` in Whatsapp-Link configration node.
![](./.github/WhatsaaLite.png)
*It will create a Whatsapp Web instance in your machine and store your session locally in Node-RED. All data are store in users `<user>/.node-red/Whatsapp-Link` folder. Near you Node-Red's settings.js file.* *It will create a Whatsapp Web instance in your machine and store your session locally in Node-RED. All data are store in users `<user>/.node-red/Whatsapp-Link` folder. Near you Node-Red's settings.js file.*
@ -62,7 +69,7 @@ Admin Node generate QR Code just below the node for easy connection with whatsap
|--------|-------------| |--------|-------------|
| `msg.image` | Base64 (encoded image) | | `msg.image` | Base64 (encoded image) |
| `msg.payload` | Image Caption | | `msg.payload` | Image Caption |
| `msg.toNumber` | Sender number (if number not provided in node) | | `msg.toNumber` | Reciver number (if number not provided in node) |
Don't forget to mention international dialing code befor your number. Don't forget to mention international dialing code befor your number.
Number must be in format like <b>+11 99999 99999</b> without any space. Number must be in format like <b>+11 99999 99999</b> without any space.
@ -88,7 +95,7 @@ Issues and Suggestions are welcome [here.](https://github.com/raweee/node-red-co
* `Ver-0.1.23` : Nodes are formatted correctly and names are updated. * `Ver-0.1.23` : Nodes are formatted correctly and names are updated.
* `Ver-0.1.28` : Now QR Codes are directlly avilable in run time on Whatsapp-Admin-Node. * `Ver-0.1.28` : Now QR Codes are directlly avilable in run time on Whatsapp-Admin-Node.
* `Ver-0.1.30` : Message can be send to an Array of contacts provided at `msg.toNumber`. * `Ver-0.1.30` : Message can be send to an Array of contacts provided at `msg.toNumber`.
* Working on WhatsappLite. * `Ver-0.1.32` : Socket based `Whatsapp Lite` config node added in beta mode. Image message sending support added in chats-out node.
## Future Nodes ## Future Nodes
Currently working on more Whatsapp Node and will be avilable soon - Currently working on more Whatsapp Node and will be avilable soon -

View File

@ -24,10 +24,15 @@
} }
}; };
var creatImageContainer = function(NodeID, qrImage) { var adminNodeId = null;
RED.comms.subscribe("whatsappLinkNodeID", function (e, currentID) {
adminNodeId = currentID;
})
var creatImageContainer = function(NodeID) {
let img = document.getElementById("whatsappLink-QRcode-" + NodeID) let img = document.getElementById("whatsappLink-QRcode-" + NodeID)
if (!img) { if (!img) {
const container = document.getElementById(NodeID) const container = document.getElementById(adminNodeId)
if (!container) { return } if (!container) { return }
const img = document.createElementNS("http://www.w3.org/2000/svg", 'image') const img = document.createElementNS("http://www.w3.org/2000/svg", 'image')
img.setAttribute('id', "whatsappLink-QRcode-" + NodeID) img.setAttribute('id', "whatsappLink-QRcode-" + NodeID)
@ -39,7 +44,7 @@
}; };
var renderQrCode = function(id, qrCodeImage){ var renderQrCode = function(id, qrCodeImage){
creatImageContainer(id, qrCodeImage) creatImageContainer(id)
let qrImage = document.getElementById("whatsappLink-QRcode-" + id); let qrImage = document.getElementById("whatsappLink-QRcode-" + id);
qrImage.setAttribute('href', qrCodeImage) qrImage.setAttribute('href', qrCodeImage)
qrImage.addEventListener("click", ()=> removeQrCode(id), {once:true}) qrImage.addEventListener("click", ()=> removeQrCode(id), {once:true})

View File

@ -5,10 +5,8 @@ module.exports = function(RED) {
RED.nodes.createNode(this,config); RED.nodes.createNode(this,config);
var node = this; var node = this;
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink); var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
node.waClient = whatsappLinkNode.client; node.client = whatsappLinkNode.client;
node.WARestart = whatsappLinkNode.WARestart; RED.comms.publish("whatsappLinkNodeID", node.id)
node.WAConnect = whatsappLinkNode.WAConnect;
node.destroy = whatsappLinkNode.WAClose;
function SetStatus(WAStatus, color){ function SetStatus(WAStatus, color){
node.status({fill:color,shape:"dot",text:WAStatus}); node.status({fill:color,shape:"dot",text:WAStatus});
@ -16,28 +14,39 @@ module.exports = function(RED) {
node.send(msg); node.send(msg);
}; };
// Commands recived for Whatsapp Admin. // Commands recived for Whatsapp Admin.
this.on('input', async function(msg, send){ this.on('input', async function(msg, send){
if (msg.payload === "destroy") { if (msg.payload === "destroy") {
node.destroy(); if(node.client.clientType === "waWebClient"){
node.clinet.WAClose();
SetStatus("Disconnected","red"); SetStatus("Disconnected","red");
} }
}
else if (msg.payload==="logout") { else if (msg.payload==="logout") {
node.waClient.logout(); if(node.client.clientType === "waWebClient"){
node.client.logout();
SetStatus("Logged Out","red"); SetStatus("Logged Out","red");
} }
}
else if (msg.payload === "test"){ else if (msg.payload === "test"){
msg.payload = await node.waClient.getState(); if(node.client.clientType === "waWebClient"){
msg.payload = await node.client.getState();
node.send(msg); node.send(msg);
} }
}
else if (msg.payload === "restart"){ else if (msg.payload === "restart"){
node.WARestart(); if(node.client.clientType === "waWebClient"){
node.client.WARestart();
SetStatus("Connecting...", "yellow"); SetStatus("Connecting...", "yellow");
}
}; };
}); });
if(node.client.clientType === "waWebClient"){
//Group Add/leave status----- //Group Add/leave status-----
node.waClient.on('group_join', async (notification)=>{ node.client.on('group_join', async (notification)=>{
msg.chat = await notification.getChat(); msg.chat = await notification.getChat();
msg.payload = msg.chat.name; msg.payload = msg.chat.name;
msg.chatID = msg.chat.id.user || `No ID Avilable`; msg.chatID = msg.chat.id.user || `No ID Avilable`;
@ -47,7 +56,7 @@ module.exports = function(RED) {
notification.reply('!Node-Red joined'); notification.reply('!Node-Red joined');
}); });
node.waClient.on('group_leave', async (notification)=>{ node.client.on('group_leave', async (notification)=>{
msg.chat = await notification.getChat(); msg.chat = await notification.getChat();
msg.payload = msg.chat.name; msg.payload = msg.chat.name;
msg.type = notification.type; msg.type = notification.type;
@ -55,7 +64,7 @@ module.exports = function(RED) {
node.send(msg); node.send(msg);
}); });
node.waClient.on('group_update', (msg)=>{ node.client.on('group_update', (msg)=>{
node.send(msg); node.send(msg);
}); });
@ -63,7 +72,7 @@ module.exports = function(RED) {
//whatsapp Status Parameters---- //whatsapp Status Parameters----
SetStatus("Connecting whatsapp...", "yellow"); SetStatus("Connecting whatsapp...", "yellow");
node.waClient.on('qr', (qr) => { node.client.on('qr', (qr) => {
SetStatus("Scan QR code to connect.", "yellow"); SetStatus("Scan QR code to connect.", "yellow");
QRCode.toDataURL(qr, function(err, url){ QRCode.toDataURL(qr, function(err, url){
msg = {payload : url}; msg = {payload : url};
@ -75,11 +84,11 @@ module.exports = function(RED) {
}); });
}); });
node.waClient.on('auth_failure', () => { node.client.on('auth_failure', () => {
SetStatus('Connection Fail.','red'); SetStatus('Connection Fail.','red');
}); });
node.waClient.on('loading_screen', () => { node.client.on('loading_screen', () => {
SetStatus('Connecting...','yellow'); SetStatus('Connecting...','yellow');
let qrImageWithID = {}; let qrImageWithID = {};
qrImageWithID.id = node.id; qrImageWithID.id = node.id;
@ -87,13 +96,43 @@ module.exports = function(RED) {
RED.comms.publish("whatsappLinkQrCode", qrImageWithID); RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
}); });
node.waClient.on('ready', () => { node.client.on('ready', () => {
SetStatus('Connected','green'); SetStatus('Connected','green');
}); });
node.waClient.on('disconnected', () => { node.client.on('disconnected', () => {
SetStatus("Disconnected","red"); SetStatus("Disconnected","red");
}); });
};
if(node.client.clientType === "waSocketClient"){
var client = null
async function clientFromWhatsappLite(){
client = await node.client;
client.ev.on('connection.update', (updates)=>{
var {connection} = updates
//Setting conncetion status indication
if(connection === 'open'){
SetStatus("Connected", "green");
}
else if(updates.isOnline){
SetStatus("Connected", "green");
}
else if(connection === 'close'){
SetStatus("Disconnected", "red");
}
else if(connection === 'connecting'){
SetStatus("Connecting...", "yellow");
}
else if(updates.is){
SetStatus("Scan QR Code to Connect.", "yellow");
}
})
}
clientFromWhatsappLite();
};
this.on(`close`, ()=>{ this.on(`close`, ()=>{
SetStatus("Disconnected", "red"); SetStatus("Disconnected", "red");

View File

@ -4,10 +4,12 @@ module.exports = function(RED) {
var node = this; var node = this;
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink); var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
node.waClient = whatsappLinkNode.client; node.waClient = whatsappLinkNode.client;
function SetStatus(WAStatus, color){ function SetStatus(WAStatus, color){
node.status({fill:color,shape:"dot",text:WAStatus}); node.status({fill:color,shape:"dot",text:WAStatus});
}; };
if(node.waClient.clientType === "waWebClient"){
node.waClient.on('message', async message => { node.waClient.on('message', async message => {
let msg = {}; let msg = {};
msg.payload = message.body; msg.payload = message.body;
@ -38,6 +40,53 @@ module.exports = function(RED) {
node.waClient.on('disconnected', () => { node.waClient.on('disconnected', () => {
SetStatus("Disconnected","red"); SetStatus("Disconnected","red");
}); });
}
else if (node.waClient.clientType === "waSocketClient"){
var client = null
async function clientFromWhatsappLite(){
client = await node.waClient;
client.ev.on('messages.upsert', msgs =>{
msgs.messages.forEach(async msg =>{
msg.payload = msg.message.conversation;
msg.from = msg.key.participant || msg.key.remoteJid;
msg.from = msg.from.replace(/\D/g, '') || msg.from;
msg.chatID = msg.key.remoteJid.replace(/\D/g, '') || msg.key.remoteJid ;
node.send(msg)
})
});
//Setting conncetion status indication
client.ev.on('connection.update', (updates)=>{
var {connection} = updates
if(connection === 'open'){
SetStatus("Connected", "green");
}
else if(updates.isOnline){
SetStatus("Connected", "green");
}
else if(connection === 'close'){
SetStatus("Disconnected", "red");
}
else if(connection === 'connecting'){
SetStatus("Connecting...", "yellow");
}
else if(updates.is){
SetStatus("Scan QR Code to Connect.", "yellow");
}
})
}
clientFromWhatsappLite();
}
} }
RED.nodes.registerType("chats-in", WhatsappIn); RED.nodes.registerType("chats-in", WhatsappIn);

View File

@ -52,7 +52,7 @@ MultiMedia Message Out: Requirments-
|--------|-------------| |--------|-------------|
| `msg.image` | Base64 (encoded image) | | `msg.image` | Base64 (encoded image) |
| `msg.payload` | Image Caption | | `msg.payload` | Image Caption |
| `msg.toNumber` | Sender number (if number not provided in node) | | `msg.toNumber` | Reciver number (if number not provided in node) |
-*Don't forget to mention international dialing code befor your number. Number must be in format like `+11 99999 99999` without any space.* -*Don't forget to mention international dialing code befor your number. Number must be in format like `+11 99999 99999` without any space.*
</script> </script>

View File

@ -12,21 +12,34 @@ module.exports = function(RED) {
}; };
const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
function whatsappMessage(numb , inputMessage){ async function whatsappMessage(numb , inputMessage){
if (node.waClient){
try {
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, ''); numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
if (node.waClient.clientType === "waWebClient"){
try {
numb = `${numb}@c.us`; numb = `${numb}@c.us`;
node.waClient.sendMessage(numb, inputMessage); node.waClient.sendMessage(numb, inputMessage);
SetStatus("Message Send.", "green");
setTimeout(()=>{
SetStatus('Connected','green');
}, 2000)
} }
catch(e) { catch(e) {
node.log(`Error Sending Msg: ${e}`); node.log(`Error Sending Msg: ${e}`);
} }
} else { node.log(`Error Sending Msg: ${e}`)} }
else if (node.waClient.clientType === "waSocketClient"){
try {
let client = await node.waClient;
numb = `${numb}@s.whatsapp.net`;
const msgStatus = await client.sendMessage(numb, {text : inputMessage});
}
catch(e) {
node.log(`Error Sending Msg: ${e}`);
}
}
else {
node.log(`Error Sending Msg: ${e}`)
}
SetStatus("Message Send.", "green");
setTimeout(()=>{
SetStatus('Connected','green');
}, 2000)
}; };
function whatsappMultiMediaMessage(numb, whatsappImage, whatsappCaption){ function whatsappMultiMediaMessage(numb, whatsappImage, whatsappCaption){
@ -76,6 +89,7 @@ module.exports = function(RED) {
}); });
//whatsapp Status Parameters---- //whatsapp Status Parameters----
if (node.waClient.clientType === "waWebClient"){
node.waClient.on('qr', (qr) => { node.waClient.on('qr', (qr) => {
SetStatus("QR Code Generated", "yellow"); SetStatus("QR Code Generated", "yellow");
}); });
@ -96,6 +110,32 @@ module.exports = function(RED) {
SetStatus("Disconnected","red"); SetStatus("Disconnected","red");
}); });
} else if (node.waClient.clientType === "waSocketClient"){
async function checkStatusOfSockets(){
let client = await node.waClient;
client.ev.on('connection.update', (updates)=>{
var {connection} = updates
if(connection === 'open'){
SetStatus("Connected", "green");
}
else if(updates.isOnline){
SetStatus("Connected", "green");
}
else if(connection === 'close'){
SetStatus("Disconnected", "red");
}
else if(connection === 'connecting'){
SetStatus("Connecting...", "yellow");
}
else if(updates.is){
SetStatus("Scan QR Code to Connect.", "yellow");
}
})
}
checkStatusOfSockets();
}
} }
RED.nodes.registerType("chats-out", WhatsappOut); RED.nodes.registerType("chats-out", WhatsappOut);
} }

View File

@ -2,37 +2,169 @@ module.exports = function(RED) {
function WhatsappGroupOut(config) { function WhatsappGroupOut(config) {
RED.nodes.createNode(this,config); RED.nodes.createNode(this,config);
var node = this; var node = this;
node.gID = config.gID; node.number = config.gID;
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink); var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
node.waClient = whatsappLinkNode.client; node.waClient = whatsappLinkNode.client;
const { MessageMedia } = require('whatsapp-web.js')
let SetStatus = function(WAStatus, color){ let SetStatus = function(WAStatus, color){
node.status({fill:color,shape:"dot",text:WAStatus}); node.status({fill:color,shape:"dot",text:WAStatus});
}; };
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
node.on('input', (message)=> { async function whatsappMessage(numb , inputMessage){
if(node.gID){ numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
if (node.waClient.clientType === "waWebClient"){
try { try {
node.gID = node.gID.replace(/\D/g, ''); numb = `${numb}@g.us`;
node.gID = `${node.gID}@g.us`; node.waClient.sendMessage(numb, inputMessage);
node.waClient.sendMessage(node.gID, message.payload);
SetStatus("Message Send.", "green");
setTimeout(()=>{
SetStatus('Connected','green');
}, 3000)
} }
catch(e) { catch(e) {
node.log(`Error Sending Msg: ${e}`); node.log(`Error Sending Msg: ${e}`);
}; }
}
else if (node.waClient.clientType === "waSocketClient"){
try {
let client = await node.waClient;
numb = `${numb}@g.us`;
const msgStatus = await client.sendMessage(numb, {text : inputMessage});
}
catch(e) {
node.log(`Error Sending Msg: ${e}`);
}
} }
else { else {
SetStatus("No Chat-ID","red"); node.log(`Error Sending Msg: ${e}`)
}
SetStatus("Message Send.", "green");
setTimeout(()=>{
SetStatus('Connected','green');
}, 2000)
};
function whatsappMultiMediaMessage(numb, whatsappImage, whatsappCaption){
try {
numb = node.number;
whatsappImage = whatsappImage.split(',')[1] || whatsappImage;
var myMessage = new MessageMedia('image/png', whatsappImage, null, null);
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
numb = `${numb}@g.us`;
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
SetStatus("Message Send.", "green");
setTimeout(()=>{
SetStatus('Connected','green');
}, 2000)
} catch(e) {
node.log(`Error sending MultiMedia Message : ${e}`)
}
};
node.on('input', (message)=> {
if (node.number){
if (message.image){
whatsappMultiMediaMessage(node.number, message.image, message.payload);
}
else {
whatsappMessage(node.number, message.payload);
}
} else if (message.toNumber){
var numbers = typeof message.toNumber === 'number' ? Array.of(message.toNumber) : message.toNumber;
for (number of numbers) {
if(message.image){
whatsappMultiMediaMessage(number, message.image, message.payload)
delay(2000);
} else {
whatsappMessage(number, message.payload)
delay(2000)
}
}
} else {
SetStatus("No number","red");
setTimeout(()=>{ setTimeout(()=>{
SetStatus('Connected','green'); SetStatus('Connected','green');
}, 5000) }, 5000)
}; }
}); });
//whatsapp Status Parameters----
if (node.waClient.clientType === "waWebClient"){
node.waClient.on('qr', (qr) => {
SetStatus("QR Code Generated", "yellow");
});
node.waClient.on('auth_failure', () => {
SetStatus('Not Connected','red');
});
node.waClient.on('loading_screen', () => {
SetStatus('Connecting...','yellow');
});
node.waClient.on('ready', () => {
SetStatus('Connected','green');
});
node.waClient.on('disconnected', () => {
SetStatus("Disconnected","red");
});
} else if (node.waClient.clientType === "waSocketClient"){
async function checkStatusOfSockets(){
let client = await node.waClient;
client.ev.on('connection.update', (updates)=>{
var {connection} = updates
if(connection === 'open'){
SetStatus("Connected", "green");
}
else if(updates.isOnline){
SetStatus("Connected", "green");
}
else if(connection === 'close'){
SetStatus("Disconnected", "red");
}
else if(connection === 'connecting'){
SetStatus("Connecting...", "yellow");
}
else if(updates.is){
SetStatus("Scan QR Code to Connect.", "yellow");
}
})
}
checkStatusOfSockets();
}
// node.on('input', (message)=> {
// if(node.gID){
// try {
// node.gID = node.gID.replace(/\D/g, '');
// node.gID = `${node.gID}@g.us`;
// node.waClient.sendMessage(node.gID, message.payload);
// SetStatus("Message Send.", "green");
// setTimeout(()=>{
// SetStatus('Connected','green');
// }, 3000)
// }
// catch(e) {
// node.log(`Error Sending Msg: ${e}`);
// };
// }
// else {
// SetStatus("No Chat-ID","red");
// setTimeout(()=>{
// SetStatus('Connected','green');
// }, 5000)
// };
// });
//whatsapp Status Parameters---- //whatsapp Status Parameters----
node.waClient.on('qr', (qr) => { node.waClient.on('qr', (qr) => {
SetStatus("QR Code Generated", "yellow"); SetStatus("QR Code Generated", "yellow");

848
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "node-red-contrib-whatsapp-link", "name": "node-red-contrib-whatsapp-link",
"version": "0.1.30", "version": "0.1.32",
"description": "Node to send and receive whatsapp messages in groups and chats. | No third party APIs", "description": "Node to send and receive whatsapp messages in groups and chats. | No third party APIs",
"repository": { "repository": {
"type": "git", "type": "git",
@ -25,13 +25,14 @@
"whatsapp chats-in": "chats-in.js", "whatsapp chats-in": "chats-in.js",
"whatsapp chats-out": "chats-out.js", "whatsapp chats-out": "chats-out.js",
"whatsapp group-out": "group-out.js", "whatsapp group-out": "group-out.js",
"whatsapp reply": "reply.js", "whatsapp reply": "whatsappReply.js",
"whatsapp Link": "whatsappLink.js" "whatsapp Link": "whatsappLink.js"
} }
}, },
"dependencies": { "dependencies": {
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"whatsapp-web.js": "latest" "whatsapp-web.js": "latest",
"@adiwajshing/baileys": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">=8.0.0" "node": ">=8.0.0"

View File

@ -3,21 +3,35 @@
category: 'config', category: 'config',
defaults: { defaults: {
cName : {value:"whatsapp-web",required:true}, cName : {value:"whatsapp-web",required:true},
name : {value : "Web"} name : {value : "Web"},
clientType: {}
}, },
label: function() { label: function() {
return this.cName ; return this.clientType;
},
oneditprepare: function(){
$("#node-config-input-clientType").typedInput({
types: [
{
value: "Select Client Type",
options: [
{ value: "waWebClient", label: "Whatsapp Web"},
{ value: "waSocketClient", label: "Whatsapp Lite"},
]
}
]
})
} }
}); });
</script> </script>
<script type="text/html" data-template-name="whatsappLink"> <script type="text/html" data-template-name="whatsappLink">
<div class="form-row"> <div>
<label for="node-config-input-cName"><i class="fa fa-gear"></i>Name</label> <label for="node-config-input-client" ><i class="fa fa-cog"></i> Select type of Whatsapp Client : </label>
<input type="text" id="node-config-input-cName"> <input type="text" id="node-config-input-clientType">
</div> </div>
<br>
<div class="form-tips"> <div class="form-tips">
<p> All done here just <b>click the ok button</b> and proceed. <p> All done here just <b>Select the type of Whatsapp Client</b> and proceed.</p>
Name can be update if required but with no-space.</p>
</div> </div>
</script> </script>

View File

@ -1,17 +1,24 @@
module.exports = function(RED) { module.exports = function(RED) {
const { Client, LocalAuth } = require('whatsapp-web.js'); const { Client, LocalAuth } = require('whatsapp-web.js');
const makeWASocket = require('@adiwajshing/baileys');
const { useMultiFileAuthState } = makeWASocket
const QRCode = require('qrcode'); const QRCode = require('qrcode');
const FS = require('node:fs')
const OS = require('os'); const OS = require('os');
const Path = require('path'); const Path = require('path');
let userDir = OS.homedir(); let userDir = OS.homedir();
let whatsappLinkDir = Path.join(userDir, '.node-red', 'Whatsapp-Link'); let whatsappLinkDir = Path.join(userDir, '.node-red', 'Whatsapp-Link');
let whatsappLinkDirSocket = Path.join(whatsappLinkDir, 'WA-Sockets')
function RemoteClientNode(n) { function RemoteClientNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
let WAnode = this; var WAnode = this;
let whatsappConnectionStatus; var clientType = n.clientType;
var whatsappConnectionStatus;
var client
const client = new Client({ var WAConnect = function(){
const webClient = new Client({
authStrategy : new LocalAuth({ authStrategy : new LocalAuth({
dataPath : whatsappLinkDir dataPath : whatsappLinkDir
}), }),
@ -21,18 +28,52 @@ module.exports = function(RED) {
} }
}); });
let WAConnect = function(){
try { try {
client.initialize(); webClient.initialize();
WAnode.log("Status : Initializing Whatsapp.."); WAnode.log("Status : Initializing Whatsapp..");
} }
catch(e) { catch(e) {
WAnode.log(`Error : Unable to start Whatsapp. Try Again..`); WAnode.log(`Error : Unable to start Whatsapp. Try Again..`);
}; };
return webClient ;
};
if (clientType ==="waWebClient"){
client = WAConnect();
WAnode.connectionSetupID = setInterval(connectionSetup, 10000);
function WAClose(){
try {
client.destroy();
}
catch(e){
WAnode.err(`Error : Too many instructions! Try again.`)
}
};
var WARestart = function(){
WAClose();
WAConnect();
}
async function connectionSetup(){
try {
whatsappConnectionStatus = await client.getState();
if(whatsappConnectionStatus === "CONNECTED"){
clearInterval(WAnode.connectionSetupID);
}
else {
WAnode.log(`Status : Connecting to Whatsapp...`);
}
}
catch(e){
WAnode.log(`Error : Waiting for Initializion...`);
}
};
//QR-Code on Terminal and Ready Status. //QR-Code on Terminal and Ready Status.
client.on("qr", (qr)=>{ client.on("qr", (qr)=>{
clearInterval(connectionSetupID); clearInterval(WAnode.connectionSetupID);
QRCode.toString(qr, {type : 'terminal', small:true }, function(err, QRTerminal){ QRCode.toString(qr, {type : 'terminal', small:true }, function(err, QRTerminal){
WAnode.log(`To Connect, Scan the QR Code through your Whatsapp Mobile App.`) WAnode.log(`To Connect, Scan the QR Code through your Whatsapp Mobile App.`)
console.log(""); console.log("");
@ -42,8 +83,6 @@ module.exports = function(RED) {
client.on("ready", ()=>{ client.on("ready", ()=>{
WAnode.log(`Status : Whatsapp Connected`); WAnode.log(`Status : Whatsapp Connected`);
}); });
};
WAConnect();
//Whatsapp-Link Test Features (For Status and Testing Only.) //Whatsapp-Link Test Features (For Status and Testing Only.)
client.on('message_create', async (msg)=> { client.on('message_create', async (msg)=> {
@ -52,12 +91,12 @@ module.exports = function(RED) {
let contact = await msg.getContact(); let contact = await msg.getContact();
if (chat.isGroup){ if (chat.isGroup){
let msgReply = let msgReply =
`Hi From Node-Red. `Hi From Node-Red.
------------------ ------------------
Group Name : ${chat.name}, Group Name : ${chat.name},
Group Id : ${chat.id.user}, Group Id : ${chat.id.user},
Group Admin : ${chat.groupMetadata.owner.user}, Group Admin : ${chat.groupMetadata.owner.user},
Participants : ${chat.groupMetadata.size}` Participants : ${chat.groupMetadata.size}`
msg.reply(msgReply); msg.reply(msgReply);
} }
else { else {
@ -71,56 +110,99 @@ Participants : ${chat.groupMetadata.size}`
}); });
function WAClose(){ client.WAConnect = WAConnect;
try { client.WARestart = WARestart;
client.destroy(); client.WAClose = WAClose;
WAnode.client.destroy(); client.clientType = clientType;
} WAnode.client = client;
catch(e){
WAnode.err(`Error : Too many instructions! Try again.`)
}
}; };
async function connectionSetup(){ if (clientType === "waSocketClient"){
try {
whatsappConnectionStatus = await client.getState();
if(whatsappConnectionStatus === "CONNECTED"){
clearInterval(connectionSetupID);
}
else {
WAnode.log(`Status : Connecting to Whatsapp...`);
}
}
catch(e){
WAnode.log(`Error : Waiting for Initializion...`);
}
};
let connectionSetupID = setInterval(connectionSetup, 10000);
let WARestart = function(){ async function connectSocketClient() {
WAClose(); const { state, saveCreds } = await useMultiFileAuthState(whatsappLinkDirSocket);
WAConnect(); const socketClient = makeWASocket.default({
printQRInTerminal: false,
auth : state
})
socketClient.ev.on('creds.update', saveCreds)
socketClient.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if (connection === 'close') {
// reconnect if not logged out
if (
lastDisconnect &&
lastDisconnect.error &&
lastDisconnect.error.output &&
(lastDisconnect.error.output.statusCode === 410 ||
lastDisconnect.error.output.statusCode === 428 ||
lastDisconnect.error.output.statusCode === 515)
) {
connectSocketClient()
} else {
if (
lastDisconnect &&
lastDisconnect.error &&
lastDisconnect.error.output &&
lastDisconnect.error.output.statusCode === 401
) {
FS.rmSync(whatsappLinkDirSocket, {recursive : true, force: true})
connectSocketClient()
} else {
console.log('Error unexpected', update)
} }
}
}
if(update.qr){
QRCode.toDataURL(update.qr, function(err, url){
var qrImageWithID = {};
qrImageWithID.id = WAnode.id;
qrImageWithID.image = url;
RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
});
QRCode.toString(update.qr, {type : 'terminal', small:true }, function(err, QRTerminal){
WAnode.log(`To Connect, Scan the QR Code through your Whatsapp Mobile App.`)
console.log("");
console.log(QRTerminal);
});
}
if (connection === 'open') {
var qrImageWithID = {};
qrImageWithID.id = WAnode.id;
qrImageWithID.image = null;
RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
}
})
return socketClient
};
client = connectSocketClient();
client.clientType = clientType;
WAnode.client = client
};
this.on('close', (removed, done)=>{ this.on('close', (removed, done)=>{
if(removed){ if(removed){
clearInterval(connectionSetupID); if(clientType === "waWebClient"){
WAClose(); clearInterval(WAnode.connectionSetupID);
WAnode.client.WAClose();
}
} }
else { else {
clearInterval(connectionSetupID); if(clientType === "waWebClient"){
WAClose(); clearInterval(WAnode.connectionSetupID);
WAnode.client.WAClose();
}
} }
done(); done();
}); });
this.WAConnect = WAConnect;
this.client = client;
this.WARestart = WARestart;
this.WAClose = WAClose;
this.whatsappConnectionStatus = whatsappConnectionStatus;
} }
RED.nodes.registerType("whatsappLink",RemoteClientNode); RED.nodes.registerType("whatsappLink",RemoteClientNode);
} }