Merge branch 'whats_session_out' into dialogflow_sessions_out

pull/20/head
adriano 2023-04-17 10:37:37 -03:00
commit f5fbd106bf
102 changed files with 12590 additions and 643 deletions

View File

@ -0,0 +1,3 @@
PORT=8019
PORT_START=8020
BASE_URL=http://localhost

View File

@ -0,0 +1,485 @@
const express = require('express');
const bodyparser = require('body-parser');
const dotenv = require('dotenv');
dotenv.config({ path: '.env' });
const copyFolder = require('./helpers/copyFolder')
const createDir = require('./helpers/createDir')
const createFile = require('./helpers/createFile')
const path = require('path');
const db_info = require('./db_conn')
const fs = require('fs');
let mysql_conn = require('./helpers/mysql_conn.js');
const { exec, execSync, spawn } = require("child_process");
const startPm2Process = require('./helpers/startPm2Process');
const removeDir = require('./helpers/remove_dir');
const setSessionName = require('./helpers/setSessionNumber')
const getNumberFromName = require('./helpers/getNumberSequence')
const pm2 = require('pm2');
const app = express();
app.use(bodyparser.json());
app.get('/', function (req, res) { return res.send('Express + TypeScript Server'); });
app.post('/api/session', async function (req, res) {
let { app_name, whatsappId, client_url, number } = req.body
if(app_name){
app_name = app_name.trim()
}
console.log('__dirname: ', path.join(__dirname, '..', app_name))
console.log('app_name: ', app_name, ' | whatsappId: ', whatsappId, ' | client_url: ',client_url)
const sessionsPath = path.join(__dirname, '..', 'sessions')
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true })
.filter((item) => item.isDirectory())
.map((item) => item.name);
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
let dirSessionsApp = path.join(sessionsPath, app_name)
if (dirExist.length == 0) {
let create = createDir(dirSessionsApp)
if (!create) {
res.status(500).json({ message: 'Cannot create the directory path!' })
return
}
}
let appPort = []
let existSubDir = false
for (let i = 0; i < directoriesInDIrectory.length; i++) {
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true })
.filter((item) => item.isDirectory())
.map((item) => item.name);
for (let x = 0; x < subDir.length; x++) {
console.log('subdir: ', subDir[x])
let whatsId = subDir[x].split('_')[0]
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
console.log('PATH: ', path.join(sessionsPath, directoriesInDIrectory[i], subDir[x]))
let oldNumber = subDir[x].split('_')[1]
// let sessionNum = subDir[x].split('_')[2]
// let sessionPort = subDir[x].split('_')[3]
// let newSessionAppName = `${whatsId}_${number}_${sessionNum}_${sessionPort}`
// let newPath = path.join(sessionsPath, directoriesInDIrectory[i], newSessionAppName)
// console.log(`number: ${number}\noldNumber: ${oldNumber}\nsessionNum: ${sessionNum}\nsessionPort: ${sessionPort}\nnewSessionAppName:${newSessionAppName}`)
if (oldNumber != number) {
deletePm2Process(subDir[x], currPath)
removeDir(currPath)
}
else {
res.send('ok')
return
}
// try {
// //
// fs.renameSync(currPath, newPath)
// console.log("Successfully renamed the directory.")
// const data = fs.readFileSync(path.join(`${newPath}`, '.env'), 'utf-8');
// // console.log('Data: ', data)
// const newValue = data.replace(`MOBILEUID=${oldNumber}`, `MOBILEUID=${number}`)
// fs.writeFileSync(path.join(`${newPath}`, '.env'), newValue, 'utf-8');
// if (oldNumber != number) {
// removeDir(path.join(newPath, '.wwebjs_auth'))
// }
// startPm2Process(newSessionAppName, 'app.js', newPath, sessionPort)
// } catch (err) {
// console.log(err)
// }
// res.send('ok')
// return
}
appPort.push(+subDir[x].split('_')[3])
console.log('---------> appPort: '+appPort)
existSubDir = true
}
}
appPort = existSubDir ? Math.max(...appPort) + 1 : process.env.PORT_START
console.log('new port: ', appPort)
let dirSessionAppName
let numberSession = 1
// const dirSessionsNumberAppDirectories = fs.readdirSync(dirSessionsApp, { withFileTypes: true })
// .filter((item) => item.isDirectory() && item.name.includes(`${number}`))
// .map((item) => item.name);
// console.log('dirSessionsNumberAppDirectories', dirSessionsNumberAppDirectories, ' | dirSessionsApp: ', dirSessionsApp)
console.log('client_url: ', client_url)
let db = db_info.filter((e) => e.client_url == client_url)
if (db && db.length > 0) {
db = db[0].db_conf
}
// if (dirSessionsNumberAppDirectories.length > 0) {
if (db && Object.keys(db).length > 0) {
const whatsapp_numbers = await new Promise((resolve, reject) => {
mysql_conn(db).query('SELECT name FROM Whatsapps WHERE name LIKE ?', [`%${number}%`], (err, result) => {
if (err) {
reject(err)
}
else {
resolve(result)
}
});
})
console.log('whatsapp_numbers: ', whatsapp_numbers)
let session_num = []
if (whatsapp_numbers && whatsapp_numbers.length > 0) {
console.log('whatsapp_numbers.length: ', whatsapp_numbers.length)
if (whatsapp_numbers.length == 5) {
res.status(400).json({ message: 'Cannot create more than 4 sessions from the same number' })
return
}
let regex = /-> [a-zA-Z]\d$/
let numbered_sessions = whatsapp_numbers.filter((e) => regex.test(e.name))
console.log('numbered_sessions: ', numbered_sessions)
session_num = numbered_sessions.map((e) => parseInt((e.name.split('->')[e.name.split('->').length - 1]).trim().match(/\d+/)[0]))
console.log('session_num', session_num)
}
let index = 1;
while (index <= 4) {
if (!session_num.includes(index)) {
console.log(index)
numberSession = index
break
}
index++
}
}
// numberSession = Math.max(...session_number) + 1
console.log('Number session: ', numberSession)
// }
dirSessionAppName = `${whatsappId}_${number}_${numberSession}_${appPort}`
destDir = path.join(dirSessionsApp, dirSessionAppName)
originDir = path.join(__dirname, '..', 'whats')
copyFolder(originDir, destDir)
if (db && Object.keys(db).length > 0) {
console.log('kkkkkkkkkkkkkkk')
let whatsName
const whatsapp = await new Promise((resolve, reject) => {
mysql_conn(db).query("SELECT name from Whatsapps where id = ?", [whatsappId], (err, result) => {
if (err) {
reject(err)
}
else {
resolve(result)
}
});
})
if (whatsapp[0]["name"].split('->').length > 0) {
whatsName = `${whatsapp[0]["name"].split('->')[0]} -> S${numberSession}`
}
else {
whatsName = `${whatsapp[0]["name"]} -> S${numberSession}`
}
console.log('whatsName: ', whatsName)
console.log(`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`)
await new Promise((resolve, reject) => {
mysql_conn(db).query("UPDATE Whatsapps SET url = ?, name = ? where id = ?", [`${process.env.BASE_URL}:${appPort}`, `${whatsName}`, whatsappId],
function (err, result) {
if (err) {
reject(err)
console.log("===> ERROR: " + err);
}
else {
resolve(result)
// console.log('RESULT: ', result)
}
// else
// console.log('myslq result: ', result);
});
})
let whatsappName = `${number} - s${numberSession}`
console.log('-------------- numberSession', numberSession)
if (whatsapp.length > 0) {
if (whatsapp[0]['name'].split(' ').length > 0) {
whatsappName = `${whatsapp[0]['name'].split(' ')[0]} - S${numberSession}`
}
}
console.log('whatsapp: ', whatsapp)
console.log("whatsapp[0]['name']: ", whatsapp[0]['name'])
const keys = Object.keys(db);
var stream = fs.createWriteStream(path.join(destDir, '.env'));
stream.once('open', function (fd) {
stream.write("# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n");
stream.write(`MOBILEUID=${number}\n`);
stream.write(`MOBILENAME=${whatsappName}\n`);
stream.write("\n");
stream.write("# PORT NUMBER FOR THIS API\n");
stream.write(`PORT=${appPort}\n`);
stream.write("\n");
stream.write("# URL FROM THE OMNIHIT BACKEND API\n");
stream.write(`CLIENT_URL=${client_url}\n`);
stream.write("\n");
stream.write("# OMNIHIT DATABASE\n");
keys.forEach((key, index) => {
stream.write(`${key}=${db[key]}\n`);
});
stream.write("\n");
stream.write(`# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE\n`);
stream.write(`WHATSAPP_ID=${whatsappId}`);
stream.end();
});
console.log('----------------destDir: ', destDir)
execSync(`npm install`, { cwd: destDir }, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
startPm2Process(dirSessionAppName, 'app.js', destDir, appPort)
}
res.send("OK");
});
app.post('/api/session/edit', async function (req, res) {
const { app_name, whatsappId, client_url, number } = req.body
})
app.post('/api/session/del', async function (req, res) {
let { whatsappId, app_name } = req.body
if(app_name){
app_name = app_name.trim()
}
const sessionsPath = path.join(__dirname, '..', 'sessions')
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true })
.filter((item) => item.isDirectory())
.map((item) => item.name);
console.log('directoriesInDIrectory: ', directoriesInDIrectory)
const dirExist = directoriesInDIrectory.filter((e) => e.trim() == app_name)
console.log('dirExist: ', dirExist)
if (dirExist.length == 0)
res.send('ok')
for (let i = 0; i < directoriesInDIrectory.length; i++) {
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true })
.filter((item) => item.isDirectory())
.map((item) => item.name);
for (let x = 0; x < subDir.length; x++) {
console.log('subdir: ', subDir[x])
let whatsId = subDir[x].split('_')[0]
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
deletePm2Process(subDir[x], currPath);
console.log('currPath: ', currPath)
removeDir(currPath)
return res.send('ok')
}
}
}
res.send('ok')
})
app.listen(process.env.PORT || 8003, function () {
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003);
});
process.on('uncaughtException', function (err) {
console.error(' ');
console.error('----- ' + (new Date).toUTCString() + ' ----------------------------------')
console.error('Erro uncaughtException: ', err.message)
console.error(err.stack)
console.error(' ');
return
});
function deletePm2Process(process_name, currPath) {
pm2.connect(function (err) {
if (err) {
console.error(err);
}
pm2.list(function (err, processes) {
if (err) {
console.error(err);
}
processes.forEach(function (process) {
console.log(".........process.name: ", process.name);
if (process.name === process_name) {
execSync(`pm2 delete ${process_name} && pm2 save --force`, { cwd: currPath }, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
}
});
pm2.disconnect();
});
});
}

View File

@ -0,0 +1,27 @@
const db = [
{
client_url: "http://localhost:8080",
db_conf: {
DB: "whaticket",
DB_HOST: "localhost",
DB_USER: "whaticket",
DB_PASS: "strongpassword",
DB_PORT: "3306"
}
},
{
client_url: "http://localhost:8081",
db_conf: {
DB: "whaticket",
DB_HOST: "localhost",
DB_USER: "whaticket",
DB_PASS: "strongpassword",
DB_PORT: "3306"
}
}
]
module.exports = db;

View File

@ -0,0 +1,17 @@
const fsPromises = require("fs/promises");
const fs = require('fs-extra')
// Delete a directory and its children
function copyFolder(sourcePath, destPath) {
fs.copySync(sourcePath, destPath, { overwrite: true }, (err) => {
if (err) {
console.error(err);
} else {
console.log("Copy dir success!");
}
});
}
module.exports = copyFolder;

View File

@ -0,0 +1,22 @@
const fs = require('fs');
function createDir(dir) {
// create new directory
try {
// check if directory already exists
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
console.log("Directory is created.");
} else {
console.log("Directory already exists.");
}
} catch (err) {
console.log(err);
return false
}
return true
}
module.exports = createDir;

View File

@ -0,0 +1,17 @@
const fs = require('fs');
function createFile(saveDir, rows, fileName) {
var stream = fs.createWriteStream(path.join(saveDir, fileName));
stream.once('open', function (fd) {
rows.forEach(element => {
stream.write(element);
});
stream.end();
});
}
module.exports = createFile

View File

@ -0,0 +1,46 @@
const pm2 = require('pm2');
function findAndDeletePm2Process(pm2_process_name) {
pm2.connect(function (err) {
if (err) {
console.error(err);
// process.exit(2);
}
pm2.list(function (err, processes) {
if (err) {
console.error(err);
// process.exit(2);
}
const processToDelete = processes.find(process => process.name === pm2_process_name);
if (!processToDelete) {
console.error('Process not found');
// process.exit(2);
}
else {
pm2.delete(processToDelete.pm_id, function (err) {
if (err) {
console.error(err);
// process.exit(2);
}
else{
console.log(`Process deleted: ${pm2_process_name}`)
}
pm2.disconnect();
});
}
});
});
}
module.exports = findAndDeletePm2Process

View File

@ -0,0 +1,39 @@
function getNumberFromName(name) {
name = name + ' '
let number = name.split('')
let newNumber = ''
let list = []
for (let i = 0; i < number.length; i++) {
if (!isNaN(Number(number[i])) && number[i].trim().length > 0) {
newNumber += number[i]
}
else {
if (!isNaN(Number(newNumber)) && newNumber.trim().length > 0) {
list.push(newNumber)
}
newNumber = ''
}
}
// longestString = list.filter(str => str.length === Math.max(...list.map(s => s.length)))[0];
// console.log('list: ', list)
let longestString = ""; // variable to store the longest string
for (let i = 0; i < list.length; i++) {
if (list[i].length > longestString.length) {
longestString = list[i];
}
}
return longestString
}
module.exports = getNumberFromName;

View File

@ -0,0 +1,109 @@
const dotenv = require('dotenv');
dotenv.config({ path: `${process.cwd()}/.env` });
const path = require('path')
function mysql_conn(config) {
// Ubicua Plataform - MYSQL Module
try {
var mysql_npm = require('mysql');
} catch (err) {
console.log("Cannot find `mysql` module. Is it installed ? Try `npm install mysql` or `npm install`.");
}
var db_config = {
host: config.DB_HOST,
user: config.DB_USER,
password: config.DB_PASS,
database: config.DB,
charset: 'utf8mb4_general_ci',
port: config.DB_PORT
};
//-
//- Create the connection variable
//-
var connection = mysql_npm.createPool(db_config);
//-
//- Establish a new connection
//-
connection.getConnection(function (err) {
if (err) {
// mysqlErrorHandling(connection, err);
console.log("\n\t *** Cannot establish a connection with the database. ***");
connection = reconnect(connection);
} else {
console.log("\n\t *** New connection established with the database. ***")
}
});
//-
//- Reconnection function
//-
function reconnect(connection) {
console.log("\n New connection tentative...");
//- Create a new one
connection = mysql_npm.createPool(db_config);
//- Try to reconnect
connection.getConnection(function (err) {
if (err) {
//- Try to connect every 2 seconds.
setTimeout(reconnect(connection), 2000);
} else {
console.log("\n\t *** New connection established with the database. ***")
return connection;
}
});
}
//-
//- Error listener
//-
connection.on('error', function (err) {
//-
//- The server close the connection.
//-
if (err.code === "PROTOCOL_CONNECTION_LOST") {
console.log("/!\\ Cannot establish a connection with the database. /!\\ (" + err.code + ")");
return reconnect(connection);
}
else if (err.code === "PROTOCOL_ENQUEUE_AFTER_QUIT") {
console.log("/!\\ Cannot establish a connection with the database. /!\\ (" + err.code + ")");
return reconnect(connection);
}
else if (err.code === "PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR") {
console.log("/!\\ Cannot establish a connection with the database. /!\\ (" + err.code + ")");
return reconnect(connection);
}
else if (err.code === "PROTOCOL_ENQUEUE_HANDSHAKE_TWICE") {
console.log("/!\\ Cannot establish a connection with the database. /!\\ (" + err.code + ")");
}
else {
console.log("/!\\ Cannot establish a connection with the database. /!\\ (" + err.code + ")");
return reconnect(connection);
}
});
return connection
}
//-
//- Export
//-
module.exports = mysql_conn;

View File

@ -0,0 +1,17 @@
import axios from "axios";
async function postData(url, body = {}) {
let response;
try {
response = await axios.post(url, body);
console.log(response.data); // handle successful response
} catch (error) {
console.error(error); // handle error
}
return response
}
module.exports = postData

View File

@ -0,0 +1,28 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
// Delete a directory and its children
const removeDir = async (dirPath) => {
if (fs.existsSync(dirPath)) {
try {
await fsPromises.rm(dirPath, { recursive: true, force: true });
console.log("Directory removed!");
return true
}
catch (err) {
console.log('An error occurred while removing the directory: ', err);
}
}
else {
console.log('Directory not found to remove: ', dirPath)
}
return false
}
module.exports = removeDir ;

View File

@ -0,0 +1,152 @@
import os from 'os';
import dir from 'path';
import fs from 'fs';
export const setJSON = (obj) => {
const sessionControlFile = dir.join(process.cwd(), `sessionsDir.json`);
try {
if (fs.existsSync(sessionControlFile)) {
const sessionsDir = fs.readFileSync(sessionControlFile, { encoding: 'utf8', flag: 'r' });
let lstRestore = JSON.parse(sessionsDir)
lstRestore.push(obj)
fs.writeFileSync(sessionControlFile, JSON.stringify(lstRestore), "utf8");
} else {
console.log('sessionsDir.json file not found! It will be created.');
if (Array.isArray(obj)) {
fs.writeFileSync(sessionControlFile, JSON.stringify(obj), "utf8");
}
else {
fs.writeFileSync(sessionControlFile, JSON.stringify([obj]), "utf8");
}
}
} catch (error) {
console.log('There was an error on try to read the sessionsDir.json file: ', error)
}
}
export const shifRestoreControll = () => {
const sessionControlFile = dir.join(os.tmpdir(), `sessionsDir.json`);
try {
if (fs.existsSync(sessionControlFile)) {
const sessionsDir = fs.readFileSync(sessionControlFile, { encoding: 'utf8', flag: 'r' });
let lstRestore: any = JSON.parse(sessionsDir)
let whatsapp: any = lstRestore.shift()
fs.writeFileSync(sessionControlFile, JSON.stringify(lstRestore), "utf8");
return whatsapp
}
} catch (error) {
console.log('There was an error on try to read the sessionsDir.json file: ', error)
}
return {}
}
export const delRestoreControllFile = () => {
const sessionControlFile = dir.join(os.tmpdir(), `sessionsDir.json`);
try {
if (fs.existsSync(sessionControlFile)) {
fs.unlinkSync(sessionControlFile)
} else {
console.log('sessionsDir.json file not found!');
}
} catch (error) {
console.log('There was an error on try delete the sessionsDir.json file: ', error)
}
}
export const getRestoreControll = () => {
const sessionControlFile = dir.join(os.tmpdir(), `sessionsDir.json`);
try {
if (fs.existsSync(sessionControlFile)) {
const sessionsDir = fs.readFileSync(sessionControlFile, { encoding: 'utf8', flag: 'r' });
let lstRestore: any = JSON.parse(sessionsDir)
return lstRestore
} else {
console.log('sessionsDir.json file not found!');
}
} catch (error) {
console.log('There was an error on try to read the sessionsDir.json file: ', error)
}
return []
}
export const _restore = async (whatsapp: Whatsapp, msg_file_title: string) => {
return
if (whatsapp.status != 'RESTORING' && whatsapp.status != 'qrcode') {
console.log('THE WHATSAAP ID: ', whatsapp.id, ' WILL BE RESTORED SOON!')
await whatsapp.update({ status: "RESTORING", });
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: "RESTORING", })
setTimeout(async () => await autoRestore(whatsapp.id, msg_file_title), 95000);
}
}

View File

@ -0,0 +1,105 @@
const fs = require('fs');
let mysql_conn = require('./mysql_conn.js');
async function sessionNumber(db_info, whatsappId, number, dirSessionsApp) {
let numberSession = 1
let whatsappName
const dirSessionsNumberAppDirectories = fs.readdirSync(dirSessionsApp, { withFileTypes: true })
.filter((item) => item.isDirectory() && item.name.includes(`${number}`))
.map((item) => item.name);
if (dirSessionsNumberAppDirectories.length > 0) {
let session_number = dirSessionsNumberAppDirectories.map((e) => +e.split('_')[2])
numberSession = Math.max(...session_number) + 1
console.log('Number session: ', numberSession)
if (numberSession > 4) {
res.status(400).json({ message: 'Cannot create more than 4 sessions from the same number' })
return
}
}
let db = db_info.filter((e) => e.client_url == client_url)
if (db && db.length > 0) {
db = db[0].db_conf
let whatsName
const whatsapp = await new Promise((resolve, reject) => {
mysql_conn(db).query("SELECT name from Whatsapps where id = ?", [whatsappId], (err, result) => {
if (err) {
reject(err)
}
else {
resolve(result)
}
});
})
if (whatsapp[0]["name"].split('->').length > 0) {
whatsName = `${whatsapp[0]["name"].split('->')[0]} -> S${numberSession}`
}
else {
whatsName = `${whatsapp[0]["name"]} -> S${numberSession}`
}
console.log('whatsName: ', whatsName)
console.log(`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`)
// await new Promise((resolve, reject) => {
// mysql_conn(db).query("UPDATE Whatsapps SET name = ? where id = ?", [ `${whatsName}`, whatsappId],
// function (err, result) {
// if (err) {
// reject(err)
// console.log("===> ERROR: " + err);
// }
// else {
// resolve(result)
// console.log('RESULT: ', result)
// }
// // else
// // console.log('myslq result: ', result);
// });
// })
whatsappName = `${number} - s${numberSession}`
console.log('-------------- numberSession', numberSession)
if (whatsapp.length > 0) {
if (whatsapp[0]['name'].split(' ').length > 0) {
whatsappName = `${whatsapp[0]['name'].split(' ')[0]} - S${numberSession}`
}
}
}
console.log('---------> whatsappName', whatsappName)
return whatsappName
}
module.exports = sessionNumber

View File

@ -0,0 +1,45 @@
const pm2 = require('pm2');
const { execSync } = require("child_process");
function startPm2Process(process_name, file, path, port) {
pm2.connect(function (err) {
if (err) {
console.error(err);
// process.exit(2);
}
pm2.start({
name: process_name,
script: file,
cwd: path,
env: {
PORT: port
}
// additional options here if needed
}, function (err, apps) {
if (err) {
console.error(err);
// process.exit(2);
}
else {
execSync(`pm2 save --force`, { cwd: path }, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
}
pm2.disconnect();
});
});
}
module.exports = startPm2Process

2194
TEST_SERVER1/api/package-lock.json generated 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
{
"name": "api-sessions-controller",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Adriano <adriano08andrade@hotmail.com>",
"license": "MIT",
"dependencies": {
"body-parser": "^1.20.1",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"fs-extra": "^11.1.0",
"mysql": "^2.18.1",
"nodemon": "^2.0.20",
"socket.io": "^4.5.4"
}
}

View File

@ -0,0 +1,20 @@
# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE
MOBILEUID=5517988310949
MOBILENAME=Numero de teste
# PORT NUMBER FOR THIS API
PORT=8020
# URL FROM THE OMNIHIT BACKEND API
CLIENT_URL=http://localhost:8080
# OMNIHIT DATABASE
DB=whaticket
DB_HOST=localhost
DB_USER=whaticket
DB_PASS=strongpassword
DB_PORT=3306
# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE
WHATSAPP_ID=46

31
TEST_SERVER1/whats/.gitignore vendored 100644
View File

@ -0,0 +1,31 @@
# dependencies
node_modules
/node_modules
/medias/*.*
/medias/in/*.*
/WWebJS/session-OmniHIT/Default/**
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
DevToolsActivePort*
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -0,0 +1,931 @@
'use strict';
const { initIO } = require("./helpers/socket")
const backup_session = require('./helpers/backup_session');
const restore = require('./helpers/restore');
const { Client, Location, List, Buttons, LocalAuth } = require('whatsapp-web.js/index');
const qrencode = require('qr-encode');
const axios = require('axios').default;
const bodyparser = require('body-parser');
const path = require('path');
const fs = require('fs');
const express = require('express');
// const dbcloud = require('./funcs/dbcloud.js');
const FormData = require('form-data');
// const { MessageMedia } = require('./node_modules/whatsapp-web.js/src/structures');
let whatsappWebGlobalPath = path.join(process.env.NODE_PATH, 'whatsapp-web.js', '/src/structures');
whatsappWebGlobalPath = whatsappWebGlobalPath.replace(':','')
console.log('whatsappWebGlobalPath: ', whatsappWebGlobalPath)
console.log('process.env.NODE_PATH: ', process.env.NODE_PATH)
const { MessageMedia } = require(whatsappWebGlobalPath);
const logger = require('logger')
const dotenv = require('dotenv');
dotenv.config({ path: '.env' });
const mime = require('mime');
const qrcode = require('qrcode-terminal');
const omnihit = require('./funcs/omnihit.js');
const { allowedNodeEnvironmentFlags } = require('process');
require("./funcs/tools.js")();
let scheduler_messages_outbound;
let scheduler_monitor;
let scheduler_monitor_cell;
let client;
// const PORT = 80;
let sendSeen = false
let unreadMessaesProcess
const { imageUpload } = require('./helpers/image-uploader')
var QRCODE = "0";
var mobileuid;
var destroy;
let asking_qrcode = false
const dbcc = require('./helpers/mysql_conn.js');
const removeDir = require('./helpers/remove_dir');
// (async()=>{
// backup_session(destroy)
// clearTimeout(destroy)
// })
// console.log('PASSOU............')
// return
// Sleep
const sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
//app.use(bodyparser.urlencoded({ extended: true }));
app.use(bodyparser.json());
const sessionName = process.env.MOBILEUID;
// console.log('DIRNAME: ', path.join(__dirname, '.wwebjs_auth', 'session-omnihit_sesssion'))
//TEST DEL
console.log('process.env.CLIENT_URL: ', process.env.CLIENT_URL)
console.log('1');
// Connect to server
var io = require('socket.io-client');
// const socket = initIO('http://localhost:8024')
const socketIo = io(process.env.CLIENT_URL, { reconnect: true, maxHttpBufferSize: 1e8 });
socketIo.on('connect', async function () {
console.log('Made socket connection', socketIo.id);
console.log('process.env.WHATSAPP_ID: ', process.env.WHATSAPP_ID)
socketIo.emit('joinWhatsSession', process.env.WHATSAPP_ID);
sendSeen = true
if (mobileuid) {
console.log('Socket conectado com o cliente: ', mobileuid)
setTimeout(async () => {
console.log('Entro no syncUnreadMessages ON CONNECTED SOCKET')
await syncUnreadMessages(client)
client.sendPresenceAvailable();
}, 5000)
}
});
socketIo.on('message_from_server', function () {
console.log('message_from_server data: ');
});
// socketIo.on('disconnect', function () {
// console.log('disconnect');
// });
// Send a message to the server 3 seconds after initial connection.
// setInterval(function () {
// socketIo.emit('message_from_client', 'Sent an event from the client!');
// }, 3000);
socketIo.on('connect_error', async function (err) {
console.log('connection errror', err);
sendSeen = false
if (mobileuid) {
client.sendPresenceUnavailable()
}
});
//
//NOVA OPÇÃO MD
client = new Client({
authStrategy: new LocalAuth({ clientId: 'omnihit_sesssion' }),
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
});
client.initialize();
client.on("qr", async qr => {
console.log("Session:", sessionName);
// Generate and scan this code with your phone
QRCODE = qr;
qrcode.generate(qr, { small: true })
console.log('QR RECEIVED', qr);
// omnihit.qrcode(process.env.MOBILEUID, process.env.MOBILENAME, qr);
// omnihit.monitor(process.env.MOBILEUID, process.env.MOBILENAME, "STARTUP");
asking_qrcode = true
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ? where id = ?", [qr, 'qrcode', 0, process.env.WHATSAPP_ID],
function (err, result) {
if (err)
console.log("ERROR: " + err);
// else
// console.log('myslq result: ', result);
});
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
try {
let response = await axios.post(url, { whatsappId: process.env.WHATSAPP_ID });
} catch (error) {
console.log('There was an error on POST THE DATA TO URL: ', url, '\n' + error);
}
});
client.on("authenticated", async session => {
console.log(`Session: ${sessionName} AUTHENTICATED`);
});
client.on("auth_failure", async msg => {
console.log(
`Session: ${sessionName} AUTHENTICATION FAILURE! Reason: ${msg}`
);
// omnihit.monitor(process.env.MOBILEUID, process.env.MOBILENAME, "AUTHFAILURE");
//reject(new Error("Error starting whatsapp session."));
});
client.on("ready", async () => {
console.log(`Session: ${sessionName} READY`);
// console.log('>>>>>>>>>>>>>> ready client.ts MOBILE NUMBER: ', client.info["wid"]["user"])
mobileuid = client.info["wid"]["user"];
console.log(new Date().toISOString() + " >>> Mobile UID ::: " + mobileuid);
// logger.info(`Session: ${sessionName} READY`);
const whatsapp = await new Promise((resolve, reject) => {
dbcc.query("SELECT * from Whatsapps where id = ?", [process.env.WHATSAPP_ID], (err, result) => {
if (err) {
reject(err)
}
else {
resolve(result)
}
});
})
if (whatsapp[0]['name'].includes(client.info["wid"]["user"])) {
console.log('-----------------> THIS IS THE RIGHT NUMBER')
}
else {
console.log('-----------------> THIS IS THE WRONG NUMBER')
let read_number = client.info["wid"]["user"]
let url = process.env.CLIENT_URL + '/whatsapp/connection/number'
try {
await client.logout()
let response = await axios.post(url, { number: read_number });
} catch (error) {
console.log('There was an error on POST THE DATA TO URL: ', url, '\n' + error);
}
return
}
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ?, number = ? where id = ?", ["", 'CONNECTED', 0, client.info["wid"]["user"], process.env.WHATSAPP_ID],
function (err, result) {
if (err)
console.log("ERROR: " + err);
// else
// console.log('myslq result: ', result);
});
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
try {
let response = await axios.post(url, { whatsappId: process.env.WHATSAPP_ID });
} catch (error) {
console.log('There was an error on POST THE DATA TO URL: ', url, '\n' + error);
}
console.log('SEND SEEN: ', sendSeen)
await syncUnreadMessages(client)
if (sendSeen) {
client.sendPresenceAvailable();
}
// if(asking_qrcode){
// // backup_session(destroy, 120000, true)
// }
backup_session(destroy, 120000, false)
asking_qrcode = false
console.log('PASSOU............')
});
async function read() {
let chats = await client.getState();
console.log(chats);
}
client.on("message_create", async msg => {
// if (msg.hasMedia && msg.fromMe)
// return
await handleMessage(msg);
});
client.on("media_uploaded", async msg => {
console.log('Entrou no midia upload')
let msgContact = null
let media = null
if (msg.fromMe) {
msgContact = await client.getContactById(msg.to);
}
else {
msgContact = await msg.getContact();
}
const chat = await msg.getChat();
msgContact.getProfilePicUrl = await msgContact.getProfilePicUrl()
let quotedMsg = await msg.getQuotedMessage();
if (msg.hasMedia) {
media = await msg.downloadMedia();
}
let data = {
id: process.env.WHATSAPP_ID,
msg: msg,
msgContact: msgContact,
chat: chat,
quotedMsg: quotedMsg ? quotedMsg.id.id : null,
media: media
}
socketIo.emit("media_uploaded", data);
});
client.on("message_ack", async (msg, ack) => {
let data = {
whatsappId: process.env.WHATSAPP_ID,
id: msg.id.id,
ack: ack
}
socketIo.emit("message_ack", data);
});
socketIo.on('send_message', async data => {
console.log('#')
console.log('--------------> send_message from number: ', mobileuid);
console.log('--------------> send_message to number: ', data.msg.number);
console.log('--------------> send_message body: ', data.msg.body);
console.log('--------------> send_message quotedMessageId: ', data.msg.quotedMessageId);
console.log('--------------> send_message linkPreview: ', data.msg.linkPreview);
console.log('#')
const sentMessage = await client.sendMessage(data.msg.number, data.msg.body, { quotedMessageId: data.msg.quotedMessageId, linkPreview: data.msg.linkPreview });
// console.log('=====================> sentMessage: ', sentMessage)
});
socketIo.on('send_media', async data => {
console.log('#')
console.log('--------------> send_message from number: ', mobileuid);
console.log('--------------> send_message to number: ', data.msg.number);
// console.log('--------------> send_message media: ', data.msg.media);
console.log('--------------> send_message sendAudioAsVoice: ', data.msg.sendAudioAsVoice);
console.log('--------------> data.msg.media.mimetype: ', data.msg.media.mimetype);
console.log('--------------> data.msg.media.filename: ', data.msg.media.filename);
console.log('#')
let media = new MessageMedia(data.msg.media.mimetype, data.msg.media.data, data.msg.media.file);
if (media && !media.filename)
media.filename = data.msg.media.filename
const sentMessage = await client.sendMessage(data.msg.number, media, { sendAudioAsVoice: data.msg.sendAudioAsVoice });
// const fullFilename = process.cwd() + process.env.MEDIA_DOWNLOAD_IN + data.msg.media.filename;
// console.log('fullFIlename: ', fullFilename)
// fs.writeFileSync(fullFilename, data.msg.media.data, { encoding: 'base64' });
});
client.on("change_state", async newState => {
let omnihit_url = process.env.CLIENT_URL + '/whatsapp/connection/monitor'
// logger.info(`Monitor session: ${sessionName}, ${newState}`);
console.log('>>>>>>>>>>>>>> change_state wbotMonitor.ts MOBILE NUMBER: ', client.info["wid"]["user"])
let data = {
action: 'change_state',
whatsappId: process.env.WHATSAPP_ID
};
await whatsappMonitor(newState, omnihit_url, data);
});
client.on("disconnected", async reason => {
let omnihit_url = process.env.CLIENT_URL + '/whatsapp/connection/monitor'
console.log('>>>>>>>>>>>>>> change_state wbotMonitor.ts MOBILE NUMBER: ', client.info["wid"]["user"])
let data = {
action: 'disconnected',
whatsappId: process.env.WHATSAPP_ID,
reason: reason
};
await removeDir(path.join(__dirname, '.wwebjs_auth', 'session-omnihit_sesssion'))
setTimeout(() => {
process.exit()
}, 3000)
await whatsappMonitor('OPENING', omnihit_url, data);
});
app.get('/', function (req, res) { return res.send('Express + TypeScript Server'); });
app.post('/start', function (req, res) {
client.initialize();
res.send("OK");
});
app.post('/qr', function (req, res) {
res.send(QRCODE);
});
app.post('/api/getWbotMessage', async (req, res) => {
const { number, messageId, limit } = req.body
console.log('number: ', number, ' | limit: ', limit)
const wbotChat = await client.getChatById(number);
const fetchWbotMessagesGradually = async () => {
const chatMessages = await wbotChat.fetchMessages({ limit });
const msgFound = chatMessages.find(msg => msg.id.id === messageId);
if (!msgFound && limit < 100) {
limit += 20;
return fetchWbotMessagesGradually();
}
return msgFound;
};
try {
const msgFound = await fetchWbotMessagesGradually();
if (!msgFound) {
res.status(404).json({ message: "Cannot found message within 100 last messages" });
return
}
res.status(200).json({ message: "ok", data: msgFound });
} catch (err) {
console.log('ERR_FETCH_WAPP_MSG: ', err)
res.status(404).json({ message: "ERR_FETCH_WAPP_MSG" });
}
})
app.post('/api/disconnect', async (req, res) => {
try {
console.log('Restaring the session.........')
await removeDir(path.join(__dirname, '.wwebjs_auth', 'session-omnihit_sesssion'))
await client.logout();
setTimeout(() => {
process.exit()
}, 3000)
} catch (error) {
console.log('There was an error on try disconnect the whatsapp: ', error)
}
res.status(200).json({ message: "ok" });
})
app.post('/api/DeleteWhatsAppMessage', async (req, res) => {
const { number, messageId, limit } = req.body
console.log('number: ', number, ' | messageId: ', messageId, ' | limit: ', limit)
try {
const messageToDelete = await getWbotMessage(messageId, number, limit)
await messageToDelete.delete(true);
res.status(200).json({ message: "ok", data: messageToDelete });
return
} catch (error) {
console.log('There was an error on try disconnect the whatsapp: ', error)
res.status(500).json({ message: "There was an error on trying delete the message" });
return
}
})
app.post('/api/GetProfilePicUrl', async (req, res) => {
const { number } = req.body
console.log('THE NUMBER: ', number)
const profilePicUrl = await client.getProfilePicUrl(`${number}@c.us`);
res.status(200).json({ message: "ok", data: profilePicUrl });
})
app.post('/api/restore', async (req, res) => {
await restore(client)
res.status(200).json({ message: "ok" });
})
app.get('/api/connection/status', async (req, res) => {
let stat
try {
stat = await client.getState();
} catch (err) {
let terr = err.message;
stat = (terr.search('Session closed') > -1 ? 'SESSIONCLOSED' : 'UNKNOWN')
}
res.status(200).json({ message: "ok", data: stat });
})
const syncUnreadMessages = async (wbot) => {
console.log('ENTROU NO UNREAD MESSAGES +++++++++++++=')
const chats = await wbot.getChats();
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
for (const chat of chats) {
if (chat.unreadCount > 0) {
const unreadMessages = await chat.fetchMessages({
limit: chat.unreadCount
});
for (const msg of unreadMessages) {
// console.log('--BACKEND MSG: ', msg)
if (!sendSeen) {
return
}
await handleMessage(msg, wbot);
}
console.log(':::::::::::::::::::::::::::::PASSOU')
await chat.sendSeen();
}
}
};
const getWbotMessage = async (messageId, number, limit,) => {
const wbotChat = await client.getChatById(number);
const fetchWbotMessagesGradually = async () => {
const chatMessages = await wbotChat.fetchMessages({ limit });
const msgFound = chatMessages.find(msg => msg.id.id === messageId);
if (!msgFound && limit < 100) {
limit += 20;
return fetchWbotMessagesGradually();
}
return msgFound;
};
try {
const msgFound = await fetchWbotMessagesGradually();
if (!msgFound) {
return null
}
return msgFound
} catch (err) {
console.log('ERR_FETCH_WAPP_MSG: ', err)
}
return null
}
async function whatsappMonitor(newState, omnihit_url, data) {
dbcc.query("UPDATE Whatsapps SET status = ? where id = ?", [newState, process.env.WHATSAPP_ID],
function (err, result) {
if (err)
console.log("ERROR: " + err);
// else
// console.log('myslq result: ', result);
});
try {
let response = await axios.post(omnihit_url, data);
} catch (error) {
console.log('There was an error on POST THE DATA TO URL: ', omnihit_url, '\n' + error);
}
}
async function handleMessage(msg) {
console.log('Entrou no message_create');
let msgContact = null;
let media = null;
if (msg.fromMe) {
msgContact = await client.getContactById(msg.to);
}
else {
console.log('################# RECEIVING MESSAGE FROM: ', msg.from, ' to ', msg.to)
msgContact = await msg.getContact();
}
const chat = await msg.getChat();
msgContact.getProfilePicUrl = await msgContact.getProfilePicUrl();
let quotedMsg = await msg.getQuotedMessage();
if (msg.hasMedia) {
media = await msg.downloadMedia();
}
let data = {
id: process.env.WHATSAPP_ID,
msg: msg,
msgContact: msgContact,
chat: chat,
quotedMsg: quotedMsg ? quotedMsg.id.id : null,
media: media
};
socketIo.emit("message_create", data);
}
async function getlabels() {
var ret = await client.getContactById('551721379544-1625752306@g.us');
//createGroup('The books', ['551100000000@c.us']);
console.log("-- Chats --------------------------------");
console.log(ret);
return ret;
}
function base64_encode(file) {
// read binary data
var bitmap = fs.readFileSync(file);
// convert binary data to base64 encoded string
return new Buffer(bitmap).toString('base64');
}
function getBase64(url) {
return axios
.get(url, {
responseType: 'arraybuffer'
})
.then(response => Buffer.from(response.data, 'binary').toString('base64'))
}
function downloadMedia(url) {
let base64 = axios.get(url, { response: "arraybuffer" }).toString("base64");
console.log("-- BASE64 -------------------------------");
console.log(base64);
return base64;
}
async function validate(mobile, cb) {
// let ret = await client.isRegisteredUser(mobile);
let ret = await client.isRegisteredUser(`${mobile}@c.us`);
// ///////////////////////////////////////////////////// 5571992888229 casaes
let _validNumber = null
console.log('******** mobile: ', mobile)
try {
_validNumber = (await client.getNumberId(`${mobile}@c.us`)).user;
} catch (err) {
console.log(`Error number: ${err}`)
}
console.log('_validNumber: ', _validNumber)
////////////////////////////////////////////////////////////////////
cb({ isValid: ret, number: _validNumber });
// cb(ret)
}
app.post('/api/validate', (req, res) => {
console.log('ENTROU')
let mobile = req.body['mobile'];
console.log(new Date() + " >>> Validating Registration Number ::: " + mobile + " on WhatsApp ...");
validate(mobile, function (e) {
res.send(e);
});
});
app.post('/api/chat', (req, res) => {
let mobile = req.body['mobile'];
let message = req.body['message'];
console.log(new Date() + " >>> Send Message ::: " + mobile + " ...");
client.sendMessage(mobile, message);
res.send('OK');
});
app.post('/group', function (req, res) {
//var ret = client.createGroup("Prueba", ["55@c.us"]);
var ret = getlabels()
res.send(ret);
});
app.post('/stop', function (req, res) {
client.destroy();
res.send("OK");
});
app.post('/api/status', function (req, res) {
res.send("OK");
});
async function monitor() {
let _nextime = 0;
try {
clearInterval(scheduler_monitor);
let stat;
if (mobileuid != undefined) {
try {
stat = await client.getState();
} catch (err) {
let terr = err.message;
stat = (terr.search('Session closed') > -1 ? 'SESSIONCLOSED' : 'UNKNOWN')
}
// omnihit.monitor(process.env.MOBILEUID, process.env.MOBILENAME, stat);
_nextime = 30000;
} else {
_nextime = 10000;
}
console.log(`WHATSAPP_ID: ${process.env.WHATSAPP_ID} | CLIENT MOBILEUID: ${mobileuid} | NAME: ${process.env.MOBILENAME} | ENV MOBILEUID: ${process.env.MOBILEUID} | STATUS: ${stat}`)
} catch (error) {
//new Date(new Date() + 'UTC')
// console.log(new Date().toISOString() + " >>> ", error);
console.log(new Date(new Date() + 'UTC') + " >>> ", error);
} finally {
scheduler_monitor = setInterval(monitor, _nextime);
}
}
async function monitorCell() {
try {
clearInterval(scheduler_monitor_cell);
// let _contact_mobile = "5511954803572@c.us";
let _message = new Date(new Date() + 'UTC');
if (client.info && client.info["wid"]["user"]) {
client.sendMessage(`${process.env.MONITOR_NUMBER}@c.us`, _message);
}
} catch (error) {
console.log(`Error on send monitor message to number ${process.env.MONITOR_NUMBER} from monitorCell function: ${error}`);
} finally {
scheduler_monitor_cell = setInterval(monitorCell, 1800000);
}
}
function comercialBuss(until_hour) {
const _hour = new Date().getHours()
console.log(' _hour: ', _hour)
// const _minute = new Date().getMinutes()
// const _second = new Date().getSeconds()
if (_hour >= until_hour) {
console.log('Trying send message into comercial buss!')
return
}
}
scheduler_monitor = setInterval(monitor, 10000);
app.listen(process.env.PORT || 8003, function () {
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003);
});
process.on('uncaughtException', function (err) {
console.error(' ');
console.error('----- ' + (new Date).toUTCString() + ' ----------------------------------')
console.error('Erro uncaughtException: ', err.message)
console.error(err.stack)
console.error(' ');
return
});

View File

@ -0,0 +1,141 @@
const dotenv = require('dotenv');
dotenv.config({ path: `${process.cwd()}/.env` });
const path = require('path')
const MongoClient = require( 'mongodb' ).MongoClient;
const url = process.env.DB_URL;
var _db;
module.exports = {
connectToServer: function( callback ) {
MongoClient.connect( url, { useNewUrlParser: true }, function( err, client ) {
_db = client.db(process.env.DB_NAME);
return callback( err );
} );
},
getDb: function() {
return _db;
}
};
// // PRODUCTION CONNECTION
// const MongoClient = require( 'mongodb' ).MongoClient;
// const url = "mongodb://admin:d1nf54012022prod*@172.31.187.8:27017";
// var _db;
// module.exports = {
// connectToServer: function( callback ) {
// MongoClient.connect( url, { useNewUrlParser: true }, function( err, client ) {
// _db = client.db('db_omnihit');
// return callback( err );
// } );
// },
// getDb: function() {
// return _db;
// }
// };
// LOCA CONNECTION
// const MongoClient = require( 'mongodb' ).MongoClient;
// const url = 'mongodb://localhost:27017';
// var _db;
// module.exports = {
// connectToServer: function( callback ) {
// MongoClient.connect( url, { useNewUrlParser: true }, function( err, client ) {
// _db = client.db('db_omnihit');
// return callback( err );
// } );
// },
// getDb: function() {
// return _db;
// }
// }
/*
const MongoClient = require( 'mongodb' ).MongoClient;
const url = "mongodb://admin:d1nf54012022*@172.31.187.2:27017";
var _db;
module.exports = {
connectToServer: function( callback ) {
MongoClient.connect( url, { useNewUrlParser: true }, function( err, client ) {
_db = client.db('db_omnihit_todoo');
return callback( err );
} );
},
getDb: function() {
return _db;
}
};
*/
// const MongoClient = require( 'mongodb' ).MongoClient;
// const url = "mongodb://admin:d1nf5401@192.168.15.13/admin?retryWrites=true&w=majority";
// var _db;
// module.exports = {
// connectToServer: function( callback ) {
// MongoClient.connect( url, { useNewUrlParser: true }, function( err, client ) {
// _db = client.db('db_omnihit');
// return callback( err );
// } );
// },
// getDb: function() {
// return _db;
// }
// };

View File

@ -0,0 +1,85 @@
const os = require('os');
const dbcloud = require('./dbcloud.js');
const dotenv = require('dotenv');
const axios = require('axios').default;
dotenv.config({path: '../.env'});
module.exports = {
// qrcode: async function(mobileuid, mobilename, qr ) {
// payload = {}
// payload['mobileuid'] = mobileuid;
// payload['mobilename'] = mobilename;
// payload['qrcode'] = qr;
// await axios.post(process.env.URL_QRCODE, payload, { timeout: 2000, headers: { 'content-type': 'application/json' } });
// console.log(new Date().toISOString() + " >>> SEND QR CODE ---------------------------------------");
// return 200;
// },
monitor: async function(mobileuid, mobilename, stat) {
let _totalmem = parseInt(os.totalmem());
let _freemem = parseInt(os.freemem());
let _memory = 100 - (_freemem / _totalmem * 100);
payload = {}
payload['mobileuid'] = mobileuid;
payload['mobilename'] = mobilename;
payload['memory'] = _memory;
let db = dbcloud.getDb();
let mco = await db.collection('tab_counts').find({ "_id": mobileuid }).limit(1).toArray();
if ( mco.length == 0 ) {
payload['_id'] = mobileuid;
payload['hour'] = 0;
payload['in'] = 0;
payload['out'] = 0;
payload['lastmessage'] = new Date(new Date() + 'UTC');
payload['in_today'] = 0;
payload['out_today'] = 0;
await db.collection('tab_counts').insertOne(payload);
}else{
payload['hour'] = mco[0]['hour'];
payload['in'] = mco[0]['in'];
payload['out'] = mco[0]['out'];
payload['lastmessage'] = mco[0]['lastmessage']
payload['in_today'] = mco[0]['in_today'];
payload['out_today'] = mco[0]['out_today'];
}
payload['dt'] = new Date(new Date() + 'UTC');
payload['status'] = stat;
console.log(new Date().toISOString() + " >>> SEND MONITOR ALARM ---------------------------------------");
console.log(new Date().toISOString() + " >>> payload: ",payload);
let monitor = await db.collection('tab_monitor').find({ "_id": mobileuid }).limit(1).toArray();
if ( monitor.length == 0 ) {
payload['_id'] = mobileuid
await db.collection('tab_monitor').insertOne(payload);
}
else{
await db.collection('tab_monitor').updateOne({ "_id": mobileuid }, { $set: payload }, true);
}
return 200;
}
}

View File

@ -0,0 +1,43 @@
module.exports = function() {
this.getTimestamp = function() {
var date = new Date();
var year = date.getFullYear();
var month = ("0"+(date.getMonth()+1)).substr(-2);
var day = ("0"+date.getDate()).substr(-2);
var hour = ("0"+date.getHours()).substr(-2);
var minutes = ("0"+date.getMinutes()).substr(-2);
var seconds = ("0"+date.getSeconds()).substr(-2);
return year+"-"+month+"-"+day+" "+hour+":"+minutes+":"+seconds;
};
this.log = function(desc, message) {
console.log(getTimestamp() + ' >> ' + desc + " :: ");
console.log(message);
};
this.getTime = function() {
var date = new Date();
var hour = ("0"+date.getHours()).substr(-2);
var minutes = ("0"+date.getMinutes()).substr(-2);
var seconds = ("0"+date.getSeconds()).substr(-2);
return hour+":"+minutes+":"+seconds;
};
this.forceGC = function() {
if (global.gc) {
console.log(getTimestamp() + " >> Starting Garbage Collector...");
global.gc();
} else {
console.warn("Garbage Collector não habilitado! Execute seu programa com node --expose-gc app.js.");
}
};
this.isJSON = function(str) {
try {
return (JSON.parse(str) && !!str);
} catch (e) {
return false;
}
}
}

View File

@ -0,0 +1,39 @@
const removeDir = require('./remove_dir');
const copyFolder = require('./copyFolder');
const path = require('path');
const fs = require('fs');
async function backup_session(destroy, save_session_after, save_first_read_only=false) {
console.log('process.cwd(): ', process.cwd())
const sessionBackupPath = path.join(process.cwd(), `session_backup`, `session-omnihit_sesssion`)
if (fs.existsSync(sessionBackupPath) && save_first_read_only) return
destroy = setTimeout(async () => {
const sessionPath = path.join(process.cwd(), '.wwebjs_auth', 'session-omnihit_sesssion')
if (fs.existsSync(path.join(process.cwd(), '.wwebjs_auth'))) {
await removeDir(sessionBackupPath)
// copy the good session for backup dir
copyFolder(sessionPath, sessionBackupPath)
}
else {
console.log('Directory not found to copy backup_session: ', sessionPath)
}
}, save_session_after);
return destroy
}
module.exports = backup_session;

View File

@ -0,0 +1,17 @@
const fsPromises = require("fs/promises");
const fs = require('fs-extra')
// Delete a directory and its children
function copyFolder(sourcePath, destPath) {
fs.copySync(sourcePath, destPath, { overwrite: true }, (err) => {
if (err) {
console.error(err);
} else {
console.log("Copy dir success!");
}
});
}
module.exports = copyFolder;

View File

@ -0,0 +1,36 @@
const multer = require('multer')
const path = require('path')
//Destination to store the images
const imageStorage = multer.diskStorage({
destination: function(req, file, cb){
// let folder = ""
// if(req.baseUrl.includes("users")){
// folder = "users"
// }else if(req.baseUrl.includes("pets")){
// folder = "pets"
// }
cb(null, path.join(process.cwd(),'medias', 'out'))
},
filename: function(req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname))
}
})
const imageUpload = multer({
storage: imageStorage,
// fileFilter(req, file, cb){
// if (!file.originalname.match(/\.(jpg|jpeg|png)$/)){
// return cb(new Error('Por favor, envie apenas jpg ou png!'))
// }
// cb(undefined, true)
// }
})
module.exports = { imageUpload }

View File

@ -0,0 +1,129 @@
const dotenv = require('dotenv');
dotenv.config({ path: `${process.cwd()}/.env` });
const path = require('path')
// Ubicua Plataform - MYSQL Module
try{
var mysql_npm = require('mysql');
}catch(err){
console.log("Cannot find `mysql` module. Is it installed ? Try `npm install mysql` or `npm install`.");
}
var db_config = {
host : process.env.DB_HOST,
user : process.env.DB_USER,
password : process.env.DB_PASS,
database : process.env.DB,
charset : 'utf8mb4_general_ci',
port : process.env.DB_PORT
};
//-
//- Connection configuration
//-
// var db_config = {
// host : 'localhost',
// user : 'whaticket',
// password : '9147teste',
// database : 'db_cdnwork',
// charset : 'utf8mb4_general_ci',
// port : '6603'
// };
// var db_config = {
// host : '172.31.187.7',
// user : 'todoo',
// password : '7901228899',
// database : 'db_cdnwork',
// charset : 'utf8mb4_general_ci'
// };
//-
//- Create the connection variable
//-
var connection = mysql_npm.createPool(db_config);
//-
//- Establish a new connection
//-
connection.getConnection(function(err){
if(err) {
// mysqlErrorHandling(connection, err);
console.log("\n\t *** Cannot establish a connection with the database. ***");
connection = reconnect(connection);
}else {
console.log("\n\t *** New connection established with the database. ***")
}
});
//-
//- Reconnection function
//-
function reconnect(connection){
console.log("\n New connection tentative...");
//- Create a new one
connection = mysql_npm.createPool(db_config);
//- Try to reconnect
connection.getConnection(function(err){
if(err) {
//- Try to connect every 2 seconds.
setTimeout(reconnect(connection), 2000);
}else {
console.log("\n\t *** New connection established with the database. ***")
return connection;
}
});
}
//-
//- Error listener
//-
connection.on('error', function(err) {
//-
//- The server close the connection.
//-
if(err.code === "PROTOCOL_CONNECTION_LOST"){
console.log("/!\\ Cannot establish a connection with the database. /!\\ ("+err.code+")");
return reconnect(connection);
}
else if(err.code === "PROTOCOL_ENQUEUE_AFTER_QUIT"){
console.log("/!\\ Cannot establish a connection with the database. /!\\ ("+err.code+")");
return reconnect(connection);
}
else if(err.code === "PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR"){
console.log("/!\\ Cannot establish a connection with the database. /!\\ ("+err.code+")");
return reconnect(connection);
}
else if(err.code === "PROTOCOL_ENQUEUE_HANDSHAKE_TWICE"){
console.log("/!\\ Cannot establish a connection with the database. /!\\ ("+err.code+")");
}
else{
console.log("/!\\ Cannot establish a connection with the database. /!\\ ("+err.code+")");
return reconnect(connection);
}
});
//-
//- Export
//-
module.exports = connection;

View File

@ -0,0 +1,28 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
// Delete a directory and its children
const removeDir = async (dirPath) => {
if (fs.existsSync(dirPath)) {
try {
await fsPromises.rm(dirPath, { recursive: true, force: true });
console.log("Directory removed!");
return true
}
catch (err) {
console.log('An error occurred while removing the directory: ', err);
}
}
else {
console.log('Directory not found to remove: ', dirPath)
}
return false
}
module.exports = removeDir ;

View File

@ -0,0 +1,39 @@
const removeDir = require('./remove_dir');
const copyFolder = require('./copyFolder');
const path = require('path');
const fs = require('fs');
async function restore(client) {
try {
await client.destroy()
} catch (error) {
console.error(`Error on try destroy client: ${error}`)
}
const sessionBackupPath = path.join(process.cwd(), `session_backup`, `session-omnihit_sesssion`)
const sessionPath = path.join(process.cwd(), '.wwebjs_auth', 'session-omnihit_sesssion')
if (fs.existsSync(path.join(process.cwd(), `session_backup`, `session-omnihit_sesssion`))) {
await removeDir(sessionPath)
// copy the good session for backup dir
copyFolder(sessionBackupPath, sessionPath)
}
else {
console.log('Directory not found to copy: ', sessionPath)
}
setTimeout(() => {
console.log('process.exit: kkkkkkkkkkkkkkkkkkkkk')
process.exit()
}, 5000)
}
module.exports = restore;

View File

@ -0,0 +1,67 @@
var io = require('socket.io-client');
var lst = []
const _clear_lst = () => {
if (lst.length <= 199) return
const chunk = Math.floor((lst.length / 2))
lst = lst.slice(chunk, chunk + lst.length);
}
const multisessionIdControll = (msgId) => {
_clear_lst()
let index = lst.findIndex((x) => x.id == msgId)
console.log('INDEX: ', index)
if (index == -1) {
lst.push({ id: msgId })
}
else {
console.log('IGNORED ID: ', msgId)
return
}
// console.log('LIST OF ID MESSAGE lst: ', lst)
console.log('PASSOU.................................ID: ', msgId)
}
const initIO = (url) => {
const socket = io(url, { reconnect: true });
socket.on('connect', async () => {
console.log('Made socket connection2');
});
socket.on('messageId', messageId => {
console.log('-------> messageId: ', messageId);
multisessionIdControll(messageId)
console.log('socket lst: ', lst)
});
return socket;
};
module.exports = { initIO, lst }

5393
TEST_SERVER1/whats/package-lock.json generated 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
{
"name": "omnihit",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon ./app.js"
},
"author": "Edson da Silva",
"license": "ISC",
"dependencies": {
"axios": "^0.21.4",
"body-parser": "^1.19.0",
"dotenv": "^16.0.0",
"express": "^4.17.1",
"form-data": "^4.0.0",
"logger": "^0.0.1",
"mime": "^2.4.5",
"mongodb": "^4.1.1",
"multer": "^1.4.4",
"mysql": "^2.18.1",
"node-os-utils": "^1.3.5",
"qr-encode": "^0.3.0",
"qrcode-terminal": "^0.12.0",
"socket.io": "^4.5.4",
"socket.io-client": "^4.5.4",
"fs-extra": "^11.1.0"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}

View File

@ -6,7 +6,7 @@
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"start": "nodemon dist/server.js",
"start": "nodemon --expose-gc dist/server.js",
"dev:server": "ts-node-dev --respawn --transpile-only --ignore node_modules src/server.ts",
"pretest": "NODE_ENV=test sequelize db:migrate && NODE_ENV=test sequelize db:seed:all",
"test": "NODE_ENV=test jest",
@ -20,6 +20,7 @@
"@types/pino": "^6.3.4",
"actions-on-google": "^3.0.0",
"axios": "^0.27.2",
"axios": "^1.2.3",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
@ -45,6 +46,7 @@
"sequelize-cli": "^5.5.1",
"sequelize-typescript": "^1.1.0",
"socket.io": "^3.0.5",
"socket.io-client": "^4.5.4",
"uuid": "^8.3.2",
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js",
"yup": "^0.32.8"

View File

@ -14,6 +14,8 @@ export default {
filename(req, file, cb) {
const fileName = new Date().getTime() + path.extname(file.originalname);
console.log('THE FILE NAME FROM MULTER: ',fileName)
return cb(null, fileName);
}
})

View File

@ -62,12 +62,12 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
searchParam = searchParam.replace(/\s+/g, ' ').trim().toLowerCase();
console.log('QUERY CONTACTS FROM CACHE SEARCH PARAM: ', searchParam)
const data = await searchContactCache(searchParam, offset, 20)
if (data) {
console.log('QUERY CONTACTS FROM CACHE SEARCH PARAM: ', searchParam)
console.log('QUERY CONTACTS FROM CACHE QUERY LENGTH: ', data.length)
return res.json({ contacts: data, count: data.length, hasMore: data.length > 0 ? true : false });
@ -80,6 +80,8 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
}
console.log('QUERY CONTACTS FROM DATABASE SEARCH PARAM: ', searchParam)
const { contacts, count, hasMore } = await ListContactsService({ searchParam, pageNumber });
return res.json({ contacts, count, hasMore });
@ -113,11 +115,24 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
throw new AppError(err.message);
}
await CheckIsValidContact(newContact.number);
const validNumber: any = await CheckContactNumber(newContact.number)
const validNumber = await CheckIsValidContact(newContact.number);
// const validNumber: any = await CheckContactNumber(newContact.number)
if(!validNumber){
throw new AppError("ERR_WAPP_CHECK_CONTACT");
}
const profilePicUrl = await GetProfilePicUrl(validNumber);
console.log('xxxxxxxxxxx profilePicUrl: ',profilePicUrl)
// console.log(`newContact.name: ${newContact.name}\n
// newContact.number: ${newContact.number}\n
// newContact.email: ${newContact.email}\n
// newContact.extraInfo: ${newContact.extraInfo}`)
let name = newContact.name
let number = validNumber
let email = newContact.email
@ -129,8 +144,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
number,
email,
useDialogflow,
profilePicUrl: profilePicUrl,
extraInfo,
profilePicUrl
});
const io = getIO();

View File

@ -30,7 +30,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
ticketId
});
SetTicketMessagesAsRead(ticket);
// SetTicketMessagesAsRead(ticket);
return res.json({ count, messages, ticket, hasMore });
};
@ -43,7 +43,9 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
const ticket = await ShowTicketService(ticketId);
SetTicketMessagesAsRead(ticket);
console.log('TICKET ID: ', ticketId)
// SetTicketMessagesAsRead(ticket);
if (medias) {
await Promise.all(

View File

@ -41,7 +41,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
try {
await QuickAnswerSchema.validate(newQuickAnswer);
} catch (err) {
} catch (err:any) {
throw new AppError(err.message);
}
@ -79,7 +79,7 @@ export const update = async (
try {
await schema.validate(quickAnswerData);
} catch (err) {
} catch (err: any) {
throw new AppError(err.message);
}

View File

@ -93,6 +93,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
const { contactId, status, userId }: TicketData = req.body;
// test del
let ticket = await Ticket.findOne({ where: { contactId, status: 'queueChoice' } });
if (ticket) {

View File

@ -0,0 +1,81 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
import { logger } from "../utils/logger";
import * as Sentry from "@sentry/node";
import Whatsapp from "../models/Whatsapp";
// type IndexQuery = {
// centro_custo: string;
// };
export const wbotMonitorRemote = async (req: Request, res: Response): Promise<Response> => {
const { action, whatsappId, reason } = req.body
console.log('-----------> ACTION: ', req.body['action'])
// let whatsapp = await ShowWhatsAppService(whatsappId)
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
if (whatsapp) {
if (action === 'disconnected') {
logger.info(`Disconnected session: ${whatsapp.name}, reason: ${reason}`);
}
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
}
return res.status(200).json({ "message": "Ok" });
};
export const wbotMonitorQrcodeRemote = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.body
console.log('-----------> QRCODE MONITOR whatsappId: ', req.body['whatsappId'])
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
// let whatsapp = await ShowWhatsAppService(whatsappId)
if (whatsapp) {
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
}
return res.status(200).json({ "message": "Ok" });
};
export const wbotMonitorQrcodeNumberRead = async (req: Request, res: Response): Promise<Response> => {
const { number } = req.body
console.log('-----------> number read: ', number)
const io = getIO();
io.emit("whatsappSession", {
action: "error",
msg: `Numero lido: ${number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`
});
return res.status(200).json({ "message": "Ok" });
};

View File

@ -13,12 +13,20 @@ import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppSer
import AppError from "../errors/AppError";
import getNumberFromName from "../helpers/GetNumberSequence";
import phoneNumberStart from "../helpers/PhoneNumberStatusCode"
import path from 'path';
import validatePhoneName from "../helpers/ValidatePhoneName";
import postData from "../helpers/AxiosPost";
import Whatsapp from "../models/Whatsapp";
interface WhatsappData {
name: string;
queueIds: number[];
url: string;
urlApi: string;
greetingMessage?: string;
farewellMessage?: string;
status?: string;
@ -38,15 +46,39 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
isDefault,
greetingMessage,
farewellMessage,
queueIds
queueIds,
url,
urlApi
}: WhatsappData = req.body;
// console.log( name,
// status,
// isDefault,
// greetingMessage,
// farewellMessage,
// queueIds,
// url,
// urlApi)
// console.log('getNumberFromName: ', getNumberFromName(name))
// return res.status(200);
if (req.user.profile !== "master") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
let validate = validatePhoneName(name)
if (validate) {
return res.status(200).json({ message: validate });
}
const { whatsapp, oldDefaultWhatsapp } = await CreateWhatsAppService({
name,
url,
urlApi,
status,
isDefault,
greetingMessage,
@ -54,7 +86,16 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
queueIds
});
StartWhatsAppSession(whatsapp);
console.log('whatsapp.id: ', whatsapp.id)
postData( `${whatsapp.urlApi}/api/session`, {
"app_name": process.env.APP_NAME,
"whatsappId": whatsapp.id,
"number": getNumberFromName(name),
"client_url": `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
})
// StartWhatsAppSession(whatsapp);
const io = getIO();
io.emit("whatsapp", {
@ -87,11 +128,28 @@ export const update = async (
const { whatsappId } = req.params;
const whatsappData = req.body;
let validate = validatePhoneName(whatsappData.name)
console.log('validate', validate)
if (validate) {
return res.status(200).json({ message: validate });
}
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
whatsappData,
whatsappId
});
postData( `${whatsapp.urlApi}/api/session`, {
"app_name": process.env.APP_NAME,
"whatsappId": whatsapp.id,
"number": getNumberFromName(whatsapp.name),
"client_url": `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
})
const io = getIO();
io.emit("whatsapp", {
action: "update",
@ -119,11 +177,18 @@ export const remove = async (
const { whatsappId } = req.params;
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
postData( `${whatsapp.urlApi}/api/session/del`, {
"app_name": process.env.APP_NAME,
"whatsappId": whatsappId
})
await DeleteWhatsAppService(whatsappId);
removeDir(path.join(process.cwd(), '.wwebjs_auth', `session-bd_${whatsappId}`))
removeDir(path.join(process.cwd(), '.wwebjs_auth','sessions', `session-bd_${whatsappId}`))
removeDir(path.join(process.cwd(), '.wwebjs_auth', 'sessions', `session-bd_${whatsappId}`))
removeWbot(+whatsappId);

View File

@ -14,6 +14,9 @@ import { stat } from "fs";
import { setRestoreControll, getRestoreControll, shifRestoreControll } from "../helpers/RestoreControll";
import autoRestore from "../helpers/AutoRestore";
import axios from "axios";
import Whatsapp from "../models/Whatsapp";
import endPointQuery from "../helpers/EndPointQuery";
// let lstRestore: any = []
@ -67,7 +70,28 @@ const restart = async (req: Request, res: Response): Promise<Response> => {
}
await autoRestore(whatsappId, 'human')
let whatsapp: any = await Whatsapp.findByPk(whatsappId)
if (whatsapp) {
await whatsapp.update({ status: 'OPENING' });
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
whatsapp = JSON.parse(JSON.stringify(whatsapp))
console.log('whatsapp url: ', whatsapp.url)
await endPointQuery(`${whatsapp.url}/api/restore`, {})
}
autoRestore(whatsappId)
return res.status(200).json({ message: "Starting session." });
};
@ -75,22 +99,29 @@ const restart = async (req: Request, res: Response): Promise<Response> => {
const remove = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params;
const whatsapp = await ShowWhatsAppService(whatsappId);
const wbot = getWbot(whatsapp.id);
// const whatsapp = await ShowWhatsAppService(whatsappId);
await wbot.logout();
// const wbot = getWbot(whatsapp.id);
// await wbot.logout();
try {
const wbot_url = await getWbot(whatsappId);
let response = await axios.post(`${wbot_url}/api/disconnect`);
// TEST DEL
// removeWbot(+whatsapp.id)
} catch (error) {
// await removeDir(path.join(process.cwd(), '.wwebjs_auth', 'sessions', `session-bd_${whatsappId}`))
console.log('There was an error on try disconnect the whatsapp id: ', whatsappId)
}
// console.log('REMOVEU!!!!!!!!!!!!!!!!!!!!!')
//
return res.status(200).json({ message: "Session disconnected." });

View File

@ -0,0 +1,13 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Whatsapps", "url", {
type: DataTypes.TEXT
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Whatsapps", "url");
}
};

View File

@ -0,0 +1,13 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Whatsapps", "urlApi", {
type: DataTypes.TEXT
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Whatsapps", "urlApi");
}
};

View File

@ -14,7 +14,7 @@ import { number } from "yargs";
const autoRestore = async (whatsappId: string | number, started_action_by: string = '') => {
const whatsapp = await ShowWhatsAppService(whatsappId);
/*const whatsapp = await ShowWhatsAppService(whatsappId);
// console.log('>>>>>>>>>>> Whatsapp.id: ', whatsappId)
@ -37,9 +37,10 @@ const autoRestore = async (whatsappId: string | number, started_action_by: strin
number = ''
}
fs.writeFileSync(`${sourcePath}/${timestamp}_restore_${number}_triggered_by_${started_action_by}_id_${whatsappId}.txt`, `Whatsapp id: ${whatsapp.id} \nDate: ${dateToday.fullDate} ${dateToday.fullTime}`, (error: any) => { console.log(error) });
if (started_action_by.trim().length > 0)
fs.writeFileSync(`${sourcePath}/${timestamp}_restore_${number}_triggered_by_${started_action_by}_id_${whatsappId}.txt`, `Whatsapp id: ${whatsapp.id} \nDate: ${dateToday.fullDate} ${dateToday.fullTime}`, (error: any) => { console.log(error) });
}
}*/
setRestoreControll({ 'id': +whatsappId, 'disabled': true })

View File

@ -0,0 +1,18 @@
import axios from "axios";
import { object } from "yup";
async function postData(url: string, body: object = {}) {
let response;
try {
response = await axios.post(url, body);
console.log(response.data); // handle successful response
} catch (error) {
console.error(error); // handle error
}
return response
}
export default postData

View File

@ -13,7 +13,7 @@ const deleteContactsByIdCache = async (id: string | number) => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const contact_cache: any = await redis.hgetall(`contact:${id}`)
@ -35,7 +35,7 @@ const deleteContactsByIdCache = async (id: string | number) => {
console.log(`There was an error on deleteContactsByIdCache: ${error}`)
}
await redis.quit()
// await redis.quit()
}
const updateContactCache = async (hash: any, json_object: any) => {
@ -44,7 +44,7 @@ const updateContactCache = async (hash: any, json_object: any) => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -56,7 +56,7 @@ const updateContactCache = async (hash: any, json_object: any) => {
await pipeline.exec(() => { console.log("Key/value inserted/updated") });
await redis.quit()
// await redis.quit()
}
@ -66,7 +66,7 @@ const updateContactCacheById = async (id: string | number, update_fields: object
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const contact_cache: any = await redis.hgetall(`contact:${id}`)
@ -86,7 +86,7 @@ const updateContactCacheById = async (id: string | number, update_fields: object
console.log(`There was an error on updateContactCacheById: ${error}`)
}
await redis.quit()
// await redis.quit()
}
const createOrUpdateContactCache = async (hash: any, contact: any) => {
@ -95,7 +95,7 @@ const createOrUpdateContactCache = async (hash: any, contact: any) => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
if (contact.name) {
contact.escaped_name = escapeCharCache(contact.name)
@ -103,7 +103,7 @@ const createOrUpdateContactCache = async (hash: any, contact: any) => {
await redis.hmset(hash, contact);
await redis.quit()
// await redis.quit()
}
@ -114,12 +114,12 @@ async function searchContactCache(search: string, offset: number, limit: number)
if(!redis) return
if (redis.status !== 'connect') return null
// if (redis.status !== 'connect') return null
search = escapeCharCache(search)
const response: any = await redis.call('FT.SEARCH', 'idx_contact', `(@escaped_name:*${search}*)|(@number:*${search}*)`, 'LIMIT', offset, limit, 'SORTBY', 'escaped_name', 'ASC')
await redis.quit()
// await redis.quit()
if (response.length === 1) {
@ -172,7 +172,7 @@ const insertContactsCache = async (contacts: any) => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -185,7 +185,7 @@ const insertContactsCache = async (contacts: any) => {
await pipeline.exec(() => { console.log(`${contacts.length} CONTACTS INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
}
const loadContactsCache = async () => {
@ -196,7 +196,7 @@ const loadContactsCache = async () => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
let contacts = await ListContactsServiceCache()
@ -214,7 +214,7 @@ const loadContactsCache = async () => {
await pipeline.exec(() => { console.log(`${contacts.length} CONTACTS INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
}
const createContactIndexCache = async (hashIndex: string) => {
@ -223,7 +223,7 @@ const createContactIndexCache = async (hashIndex: string) => {
if(!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
try {
@ -242,7 +242,7 @@ const createContactIndexCache = async (hashIndex: string) => {
console.log('There was an error on createContactIndexCache: ', error)
}
await redis.quit()
// await redis.quit()
}
export {

View File

@ -0,0 +1,39 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
import axios from 'axios';
import * as https from "https";
const endPointQuery = async (url: string, data: any) => {
let response: any = null
try {
response = await axios.post(url, data);
console.log(`TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}`);
} catch (err: any) {
if (err.response) {
// The client was given an error response (5xx, 4xx)
// console.log('err.response: ', err.response)
console.log('err.response: ', err.response)
// return { data: err.response.data, status: err.response.status }
} else if (err.request) {
// The client never received a response, and the request was never left
console.log('err.request: ', err.request)
} else {
// Anything else
console.error(`Erro ao consultar endpoint ${url}: ${err}`);
}
}
return response
}
export default endPointQuery;

View File

@ -0,0 +1,40 @@
function getNumberFromName(name: string) {
name = name + ' '
let number: any[] = name.split('')
let newNumber: any = ''
let list = []
for (let i = 0; i < number.length; i++) {
if (!isNaN(Number(number[i])) && number[i].trim().length > 0) {
newNumber += number[i]
}
else {
if (!isNaN(Number(newNumber)) && newNumber.trim().length > 0) {
list.push(newNumber)
}
newNumber = ''
}
}
// longestString = list.filter(str => str.length === Math.max(...list.map(s => s.length)))[0];
// console.log('list: ', list)
let longestString = ""; // variable to store the longest string
for (let i = 0; i < list.length; i++) {
if (list[i].length > longestString.length) {
longestString = list[i];
}
}
return longestString
}
export default getNumberFromName;

View File

@ -4,7 +4,9 @@ import GetDefaultWhatsApp from "./GetDefaultWhatsApp";
import Ticket from "../models/Ticket";
const GetTicketWbot = async (ticket: Ticket): Promise<Session> => {
if (!ticket.whatsappId) {
const defaultWhatsapp = await GetDefaultWhatsApp();
await ticket.$set("whatsapp", defaultWhatsapp);

View File

@ -2,20 +2,35 @@ import { Message as WbotMessage } from "whatsapp-web.js";
import Ticket from "../models/Ticket";
import GetTicketWbot from "./GetTicketWbot";
import AppError from "../errors/AppError";
import endPointQuery from "./EndPointQuery";
import { getWbot } from "../libs/wbot";
export const GetWbotMessage = async (
ticket: Ticket,
messageId: string
): Promise<WbotMessage> => {
const wbot = await GetTicketWbot(ticket);
): Promise<WbotMessage | any> => {
const wbotChat = await wbot.getChatById(
`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`
);
let limit = 20;
const wbot_url = await getWbot(ticket.whatsappId);
const msgFound = await endPointQuery(`${wbot_url}/api/getWbotMessage`, {
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
messageId: messageId,
limit: limit
})
// console.log('----------> msgFound: ', msgFound)
// const wbot = await GetTicketWbot(ticket);
/* const wbotChat = await wbot.getChatById(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`);
const fetchWbotMessagesGradually = async (): Promise<void | WbotMessage> => {
const chatMessages = await wbotChat.fetchMessages({ limit });
const msgFound = chatMessages.find(msg => msg.id.id === messageId);
@ -26,16 +41,16 @@ export const GetWbotMessage = async (
}
return msgFound;
};
};*/
try {
const msgFound = await fetchWbotMessagesGradually();
// const msgFound = await fetchWbotMessagesGradually();
if (!msgFound) {
throw new Error("Cannot found message within 100 last messages");
}
return msgFound;
return msgFound.data.data;
} catch (err) {
throw new AppError("ERR_FETCH_WAPP_MSG");
}

View File

@ -0,0 +1,69 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
const checkInternetConnected = require('check-internet-connected');
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
import { Client } from "whatsapp-web.js";
import { splitDateTime } from "../helpers/SplitDateTime";
import { format } from "date-fns";
import ptBR from 'date-fns/locale/pt-BR';
import dir from 'path';
import { getIO } from "../libs/socket";
import { number } from "yup";
const internetConnection = async (whatasappId?: string | number) => {
checkInternetConnected().then((result: any) => {
console.log('Internet successfully connected to a server: ', result);//successfully connected to a server
}).catch((ex: any) => {
console.log('Intenet connection cannot connect to a server or error occurred: ', ex); // cannot connect to a server or error occurred.
});
const config = {
timeout: 5000, //timeout connecting to each server, each try
retries: 5,//number of retries to do before failing
domain: 'https://apple.com',//the domain to check DNS record of
}
let internet_status:any = null
try {
internet_status = await checkInternetConnected(config);
} catch (error) {
console.log('Erron when trying get internet connection info: ', error)
}
console.log('INTERNET STATUS: ', internet_status)
if (whatasappId && !internet_status) {
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
let timestamp = Math.floor(Date.now() / 1000)
const sourcePath = dir.join(process.cwd(), '.wwebjs_auth', 'sessions', 'log');
fs.writeFileSync(`${sourcePath}/${timestamp}_internet_connection_lost.txt`, `Date: ${dateToday.fullDate} ${dateToday.fullTime}`, (error: any) => { console.log(error) });
let whats = await ShowWhatsAppService(whatasappId)
await whats.update({ status: "OPENING" });
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whats
});
}
return internet_status
}
export default internetConnection;

View File

@ -13,7 +13,7 @@ const deleteContactsByIdCache = async (id: string | number) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const contact_cache: any = await redis.hgetall(`contact:${id}`)
@ -31,7 +31,7 @@ const deleteContactsByIdCache = async (id: string | number) => {
console.log(`There was an error on deleteContactsByIdCache: ${error}`)
}
await redis.quit()
// await redis.quit()
}
const updateContactCache = async (hash: any, json_object: any) => {
@ -40,7 +40,7 @@ const updateContactCache = async (hash: any, json_object: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -52,7 +52,7 @@ const updateContactCache = async (hash: any, json_object: any) => {
await pipeline.exec(() => { console.log("Key/value inserted/updated") });
await redis.quit()
// await redis.quit()
}
@ -62,7 +62,7 @@ const updateContactCacheById = async (id: string | number, update_fields: object
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const contact_cache: any = await redis.hgetall(`contact:${id}`)
@ -84,7 +84,7 @@ const updateContactCacheById = async (id: string | number, update_fields: object
console.log(`There was an error on updateContactCacheById: ${error}`)
}
await redis.quit()
// await redis.quit()
}
const createOrUpdateContactCache = async (hash: any, contact: any) => {
@ -93,7 +93,7 @@ const createOrUpdateContactCache = async (hash: any, contact: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
if (contact.name) {
contact.escaped_name = escapeCharCache(contact.name)
@ -101,7 +101,7 @@ const createOrUpdateContactCache = async (hash: any, contact: any) => {
await redis.hmset(hash, contact);
await redis.quit()
// await redis.quit()
}
@ -112,12 +112,12 @@ async function searchContactCache(search: string, offset: number, limit: number)
if (!redis) return
if (redis.status !== 'connect') return null
// if (redis.status !== 'connect') return null
search = escapeCharCache(search)
const response: any = await redis.call('FT.SEARCH', 'idx_contact_message', `(@escaped_name:*${search}*)|(@number:*${search}*)`, 'LIMIT', offset, limit, 'SORTBY', 'escaped_name', 'ASC')
await redis.quit()
// await redis.quit()
if (response.length === 1) {
@ -168,7 +168,7 @@ const getLastId = async (hash: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const contact_cache: any = await redis.hgetall(hash)
@ -182,13 +182,13 @@ const insertMessageContactCache = async (hash: any, contact_message: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
await redis.hmset(hash, contact_message);
console.log('CREATED/UPDATED CONTACT MESSAGE')
await redis.quit()
// await redis.quit()
}
@ -200,7 +200,7 @@ const loadContactsCache = async () => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
let contacts = await ListContactsServiceCache()
@ -218,7 +218,7 @@ const loadContactsCache = async () => {
await pipeline.exec(() => { console.log(`${contacts.length} CONTACTS INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
}
const createContactMessageIndexCache = async (hashIndex: string) => {
@ -227,7 +227,7 @@ const createContactMessageIndexCache = async (hashIndex: string) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
try {
@ -246,7 +246,7 @@ const createContactMessageIndexCache = async (hashIndex: string) => {
console.log('There was an error on contact_message: ', error)
}
await redis.quit()
// await redis.quit()
}
export {

View File

@ -0,0 +1,19 @@
import getNumberFromName from "./GetNumberSequence"
import codephoneNumber from './countryPhoneCodes';
function phoneNumberStart(name:string){
let phone_number:string = getNumberFromName(name)
let start: boolean = false
for (let i = 0; i < codephoneNumber.length; i++) {
if(phone_number.startsWith(codephoneNumber[i].code)){
start = true
break
}
}
return start
}
export default phoneNumberStart

View File

@ -5,6 +5,7 @@ import Whatsapp from "../models/Whatsapp";
import { StartWhatsAppSession } from "../services/WbotServices/StartWhatsAppSession";
import { copyFolder } from "./CopyFolder";
import { removeDir } from "./DeleteDirectory";
// import internetConnection from "./InternetConnection";
const fsPromises = require("fs/promises");
const fs = require('fs')
@ -12,6 +13,8 @@ const fs = require('fs')
// Restart session
export const restartWhatsSession = async (whatsapp: Whatsapp, backupSession: boolean = false) => {
return
console.log('RESTARTING THE whatsapp.id: ', whatsapp.id)
const sourcePath = path.join(__dirname, `../../.wwebjs_auth/sessions/`, `session-bd_${whatsapp.id}`)

View File

@ -3,7 +3,7 @@ import os from 'os';
import dir from 'path';
import fs from 'fs';
import ShowWhatsAppService from '../services/WhatsappService/ShowWhatsAppService';
import { insertOrUpeateWhatsCache } from './WhatsCache';
// import { insertOrUpeateWhatsCache } from './WhatsCache';
import autoRestore from './AutoRestore';
import Whatsapp from '../models/Whatsapp';
import { getIO } from '../libs/socket';
@ -142,6 +142,8 @@ export const getRestoreControll = () => {
export const _restore = async (whatsapp: Whatsapp, msg_file_title: string) => {
return
if (whatsapp.status != 'RESTORING' && whatsapp.status != 'qrcode') {
console.log('THE WHATSAAP ID: ', whatsapp.id, ' WILL BE RESTORED SOON!')
@ -155,7 +157,7 @@ export const _restore = async (whatsapp: Whatsapp, msg_file_title: string) => {
session: whatsapp
});
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: "RESTORING", })
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: "RESTORING", })
setTimeout(async () => await autoRestore(whatsapp.id, msg_file_title), 95000);

View File

@ -0,0 +1,86 @@
import Whatsapp from "../models/Whatsapp"
import autoRestore from "./AutoRestore"
import { getRestoreControll } from "./RestoreControll"
let lstAutoRestore: any = []
// Delete a directory and its children
export const restoreMonit = (whatsappId: string | number) => {
return
try {
let lstRestore: any = getRestoreControll()
console.log('ENTROU NO AUTO RESTORE..................................')
if (Object.keys(lstRestore.filter((e: any) => +e.id == +whatsappId)).length) {
console.log('Restore executed by human whatasappId: ', whatsappId)
}
else {
lstAutoRestore.push({ 'whatsappId': +whatsappId })
setTimeout(async () => {
lstRestore = getRestoreControll()
let count = lstAutoRestore.length
for (let i = 0; i < count; i++) {
let autoR = lstAutoRestore.shift()
console.log('----------------> autoR: ', autoR)
if (autoR && autoR.whatsappId) {
if (Object.keys(lstRestore.filter((e: any) => +e.id == +autoR.whatsappId)).length) {
console.log(' EXECUTING RESTORING autoR: ', autoR)
continue
}
const _whatsapp = await Whatsapp.findOne({ where: { id: autoR.whatsappId } });
console.log('----------------> autoR exec after 180 seconds: ', autoR)
let whatsappStatus = ["CONFLICT",
"DEPRECATED_VERSION",
"OPENING",
"PAIRING",
"PROXYBLOCK",
"SMB_TOS_BLOCK",
"TIMEOUT",
"TOS_BLOCK",
"UNLAUNCHED",
"UNPAIRED",
"UNPAIRED_IDLE"]
if (_whatsapp?.status) {
if (whatsappStatus.includes(_whatsapp.status)) {
await autoRestore(autoR.whatsappId, 'auto_monit')
}
}
}
}
}, 180000);
}
} catch (error) {
console.log('There was an error on try execute AUTO-RESTORE: ', error)
}
}

View File

@ -20,7 +20,7 @@ const deleteScheduleByTicketIdCache = async (ticketId: string | number) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const schedule_cache: any = await redis.hgetall(`schedule:${ticketId}`)
@ -38,7 +38,7 @@ const deleteScheduleByTicketIdCache = async (ticketId: string | number) => {
console.log(`There was an error on deleteScheduleByTicketIdCache: ${error}`)
}
await redis.quit()
// await redis.quit()
}
@ -51,7 +51,7 @@ const updateScheduleCacheByTicketId = async (scheduleNotify: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -63,7 +63,7 @@ const updateScheduleCacheByTicketId = async (scheduleNotify: any) => {
await pipeline.exec(() => { console.log("schedule Key/value inserted/updated") });
await redis.quit()
// await redis.quit()
}
@ -76,7 +76,7 @@ const createSchedulingNotifyCache = async (scheduleNotify: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
let date_time: any = format(new Date(scheduleNotify.schedulingTime), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }).split(' ')
@ -96,7 +96,7 @@ const createSchedulingNotifyCache = async (scheduleNotify: any) => {
console.log(`${scheduleNotify.length} SCHEDULE NOTIFY INSERTED IN CACHE!`)
await redis.quit()
// await redis.quit()
}
@ -107,12 +107,12 @@ async function searchScheduleCache(date: string, hour: number | string, minute:
if (!redis) return
if (redis.status !== 'connect') return null
// if (redis.status !== 'connect') return null
date = escapeCharCache(date).trim()
const response: any = await redis.call('FT.SEARCH', 'idx_schedule', `(@date_escaped:${date}) (@hour:${hour}) (@minute:${minute})`)
await redis.quit()
const response: any = await redis.call('FT.SEARCH', 'idx_schedule', `(@date_escaped:${date}) (@hour:${hour}) (@minute:${minute})`)
// await redis.quit()
if (response.length === 1) {
@ -145,7 +145,7 @@ const loadSchedulesCache = async () => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
let schedules: any = await SchedulingNotify.findAll({ raw: true, attributes: ["id", "statusChatEndId", "ticketId", "schedulingTime", "message"] });
@ -173,7 +173,7 @@ const loadSchedulesCache = async () => {
await pipeline.exec(() => { console.log(`${schedules.length} SCHEDULES NOTIFY INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
// let test = await searchScheduleCache('2022-12-16', '18', '30')
@ -188,7 +188,7 @@ const createScheduleIndexCache = async (hashIndex: string) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
try {
@ -207,7 +207,7 @@ const createScheduleIndexCache = async (hashIndex: string) => {
console.log('There was an error on createScheduleIndexCache: ', error)
}
await redis.quit()
// await redis.quit()
}
export {

View File

@ -55,7 +55,7 @@ const monitor = async () => {
await ticket.update({status: 'open'})
}
SetTicketMessagesAsRead(ticket);
// SetTicketMessagesAsRead(ticket);
await SendWhatsAppMessage({
body: schedulingNotifies[i].message, ticket
@ -102,47 +102,47 @@ const monitor = async () => {
// WHATS SESSION SIZE MONITORING
const whatsapps = await ListWhatsAppsService();
// const whatsapps = await ListWhatsAppsService();
whatsapps.forEach(async whats => {
// whatsapps.forEach(async whats => {
const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`)
// const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`)
if (fs.existsSync(sourcePath)) {
// if (fs.existsSync(sourcePath)) {
try {
// try {
const fastFolderSizeAsync = promisify(fastFolderSize)
// const fastFolderSizeAsync = promisify(fastFolderSize)
let size = await fastFolderSizeAsync(sourcePath)
// let size = await fastFolderSizeAsync(sourcePath)
size = convertBytes(size)
// size = convertBytes(size)
// SESSION MONITORING
const io = getIO();
io.emit("whatsappSessionMonit", {
action: "update",
whatsappSessionSize: {
id: whats.id,
sessionSize: size
}
});
}
catch (err) {
console.log('An error occurred while get info from the directory: ', err);
}
// // SESSION MONITORING
// const io = getIO();
// io.emit("whatsappSessionMonit", {
// action: "update",
// whatsappSessionSize: {
// id: whats.id,
// sessionSize: size
// }
// });
// }
// catch (err) {
// console.log('An error occurred while get info from the directory: ', err);
// }
}
else {
// }
// else {
console.log('Directory not found to get size info: ', sourcePath)
// // console.log('Directory not found to get size info: ', sourcePath)
}
// }
});
// });

View File

@ -0,0 +1,62 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
import axios from 'axios';
import * as https from "https";
const sendMessageAPI = async (url: string, body: string) => {
let response: any = null
try {
const httpsAgent = new https.Agent({ rejectUnauthorized: false, });
response = await axios.post(url, {
'x-api-token': 'e23dcfdfeb6be5b91b1bf5c55ee50cc4405f2802',
'x-api-app': 'x-api-app',
}, {
httpsAgent,
headers: { 'Content-Type': 'multipart/form-data' },
});
console.log(`TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}`);
// if (method == 'get') {
// // const url = 'https://sos.espacolaser.com.br/api/whatsapp/ticket/R32656'
// response = await axios.get(url, {
// httpsAgent,
// headers: {
// 'x-access-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOnsiaWQiOjEsInJvbGUiOiJjbGllbnQiLCJob3N0Ijoic29zLmVzcGFjb2xhc2VyLmNvbS5iciIsInRlbmFudCI6ImVzcGFjb2xhc2VyIiwibmFtZSI6IlNFTlNSLklUIiwiY29tcGFueSI6eyJpZCI6NDR9fSwiZGF0ZSI6MTY2MTI2MjY0MywiaWF0IjoxNjYxMjYyNjQzLCJleHAiOjE3NDc2NjI2NDN9.zf91OmRs4_C7B8OlVpLLrQMiRBYc7edP4qAdH_hqxpk',
// 'Origin': 'espacolaser'
// }
// });
// console.log(`TEST URL CLIENT GET ROUTE: ${url} | STATUS CODE: ${response.status}`);
// }
// else if (method == 'post') {
// // const url = 'http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php'
// response = await axios.post(url, {
// 'auth': '0424bd59b807674191e7d77572075f33',
// 'jsonrpc': '2.0',
// 'method': 'chamado.ematendimento',
// 'params[ccusto]': param,
// id: '101'
// }, {
// httpsAgent,
// headers: { 'Content-Type': 'multipart/form-data' },
// });
// console.log(`TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}`);
// }
} catch (error) {
console.error(`Erro ao consultar endpoint ${url}: ${error}`);
}
return response
}
export default sendMessageAPI;

View File

@ -0,0 +1,21 @@
import { MessageMedia } from "whatsapp-web.js";
import { getIO } from "../libs/socket";
import Ticket from "../models/Ticket";
function sendWhatsAppMediaSocket(ticket: Ticket, newMedia: MessageMedia) {
const io = getIO();
io.to(`session_${ticket.whatsappId.toString()}`).emit("send_media", {
action: "create",
msg: {
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
media: newMedia,
sendAudioAsVoice: true
}
});
}
export default sendWhatsAppMediaSocket;

View File

@ -0,0 +1,33 @@
import { getIO } from "../libs/socket";
import Ticket from "../models/Ticket";
function sendWhatsAppMessageSocket(ticket: Ticket, body: string, quotedMsgSerializedId?: string | undefined) {
const io = getIO();
io.to(`session_${ticket.whatsappId.toString()}`).emit("send_message", {
action: "create",
msg: {
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
body: body,
quotedMessageId: quotedMsgSerializedId,
linkPreview: false
}
});
// io.emit("send_message", {
// action: "create",
// msg: {
// number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
// body: body,
// quotedMessageId: quotedMsgSerializedId,
// linkPreview: false
// }
// });
}
export default sendWhatsAppMessageSocket;

View File

@ -2,9 +2,7 @@ import Message from "../models/Message";
import Ticket from "../models/Ticket";
const SerializeWbotMsgId = (ticket: Ticket, message: Message): string => {
const serializedMsgId = `${message.fromMe}_${ticket.contact.number}@${
ticket.isGroup ? "g" : "c"
}.us_${message.id}`;
const serializedMsgId = `${message.fromMe}_${ticket.contact.number}@${ticket.isGroup ? "g" : "c" }.us_${message.id}`;
return serializedMsgId;
};

View File

@ -7,55 +7,63 @@ import ListTicketServiceCache from "../services/TicketServices/ListTicketService
import { escapeCharCache } from './ContactsCache'
let redis: any = null
if (process.env.CACHE) {
redis = new Redis();
}
const redisConn = async () => {
if(!process.env.CACHE){
if (!process.env.CACHE) {
return null
}
try {
// try {
const redis = new Redis();
// const redis = new Redis();
const conn = () => new Promise((resolve, reject) => {
// const conn = () => new Promise((resolve, reject) => {
redis.on('error', async (err) => {
// redis.on('error', async (err) => {
if (err.code === 'ECONNREFUSED') {
console.error(`Redis connection error: ${err}.`)
await redis.quit()
}
else {
console.error(`Redis encountered an error: ${err.message}.`)
}
// if (err.code === 'ECONNREFUSED') {
// console.error(`Redis connection error: ${err}.`)
// // await redis.quit()
// }
// else {
// console.error(`Redis encountered an error: ${err.message}.`)
// }
reject(err)
// reject(err)
})
// })
redis.on('connect', () => {
// redis.on('connect', () => {
// console.log('CacheStore - Connection status: connected');
resolve(redis);
// // console.log('CacheStore - Connection status: connected');
// resolve(redis);
})
// })
redis.on('end', () => {
// console.log('CacheStore - Connection status: disconnected');
});
// redis.on('end', () => {
// // console.log('CacheStore - Connection status: disconnected');
// });
redis.on('reconnecting', () => {
// console.log('CacheStore - Connection status: reconnecting');
});
});
// redis.on('reconnecting', () => {
// // console.log('CacheStore - Connection status: reconnecting');
// });
// });
return await conn();
// return await conn();
} catch (e) {
console.error(`There whas an error on redis connection: ${e}`);
return Promise.resolve([]);
}
// } catch (e) {
// console.error(`There whas an error on redis connection: ${e}`);
// return Promise.resolve([]);
// }
return redis
}
@ -64,14 +72,16 @@ const flushCache = async () => {
const redis: any = await redisConn();
if(!redis) return false
if (!redis) return false
if (redis.status === 'connect') {
// if (redis.status === 'connect') {
console.log('TICKETS CACHE REMOVED')
await redis.call('FLUSHALL')
await redis.quit()
}
// console.log('TICKETS CACHE REMOVED')
// await redis.call('FLUSHALL')
// }
await redis.call('FLUSHALL')
}
@ -79,14 +89,12 @@ const cacheSize = async () => {
const redis: any = await redisConn();
if(!redis) return null
if (!redis) return null
if (redis.status !== 'connect') {
return -1
}
// if (redis.status !== 'connect') return -1
const size = await redis.call('dbsize')
await redis.quit()
// await redis.quit()
return size
}
@ -95,9 +103,9 @@ const loadTicketsCache = async () => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
await createTicketIndexCache('idx_ticket')
@ -123,7 +131,7 @@ const loadTicketsCache = async () => {
await pipeline.exec(() => { console.log(`${tickets.length} TICKETS INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
}
@ -131,9 +139,9 @@ const createTicketIndexCache = async (hashIndex: string) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
try {
@ -152,16 +160,16 @@ const createTicketIndexCache = async (hashIndex: string) => {
console.log('There was an error on createTicketIndexCache: ', error)
}
await redis.quit()
// await redis.quit()
}
const updateTicketCache = async (hash: any, json_object: any) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
let entries = Object.entries(json_object)
@ -172,7 +180,7 @@ const updateTicketCache = async (hash: any, json_object: any) => {
await pipeline.exec(() => { console.log("updateTicketCache Key/value inserted/updated") });
await redis.quit()
// await redis.quit()
}
@ -180,9 +188,9 @@ const updateTicketCacheByTicketId = async (ticketId: string | number, update_fie
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const ticket_cache = await redis.hgetall(`ticket:${ticketId}`)
@ -204,7 +212,7 @@ const updateTicketCacheByTicketId = async (ticketId: string | number, update_fie
console.log(`There was an error on updateTicketCacheByTicketId: ${error}`)
}
await redis.quit()
// await redis.quit()
}
@ -214,9 +222,9 @@ const createOrUpdateTicketCache = async (hash: any, ticket: any) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
ticket.escaped_name = escapeCharCache(ticket['contact.name'])
@ -227,7 +235,7 @@ const createOrUpdateTicketCache = async (hash: any, ticket: any) => {
console.log('CREATED/UPDATED TICKET CACHE')
await redis.quit()
// await redis.quit()
}
@ -235,9 +243,9 @@ const deleteTicketsByIdCache = async (ticketId: string | number) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const ticket_cache = await redis.hgetall(`ticket:${ticketId}`)
@ -255,7 +263,7 @@ const deleteTicketsByIdCache = async (ticketId: string | number) => {
console.log(`There was an error on deleteTicketsByIdCache: ${error}`)
}
await redis.quit()
// await redis.quit()
}
@ -263,9 +271,9 @@ const deleteTicketsFieldsCache = async (tickets: any, del_fields: any) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -286,7 +294,7 @@ const deleteTicketsFieldsCache = async (tickets: any, del_fields: any) => {
}
await redis.quit()
// await redis.quit()
}
@ -295,9 +303,9 @@ const updateTicketsByContactsCache = async (oldNumber: string, newName: string,
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -323,7 +331,7 @@ const updateTicketsByContactsCache = async (oldNumber: string, newName: string,
}
await redis.quit()
// await redis.quit()
}
@ -332,9 +340,9 @@ const deleteTicketsByContactsCache = async (number: string) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -356,7 +364,7 @@ const deleteTicketsByContactsCache = async (number: string) => {
}
await redis.quit()
// await redis.quit()
}
@ -364,22 +372,22 @@ const deleteTicketCache = async (hash: any) => {
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
await redis.del(hash)
await redis.quit()
// await redis.quit()
}
async function searchTicketCache(search: string, offset?: number, limit?: number) {
const redis:any = await redisConn();
const redis: any = await redisConn();
if(!redis) return
if (!redis) return
if(redis.status!=='connect') return null
// if(redis.status!=='connect') return null
search = escapeCharCache(search)
@ -391,7 +399,7 @@ async function searchTicketCache(search: string, offset?: number, limit?: number
else {
response = await redis.call('FT.SEARCH', 'idx_ticket', `(@escaped_name:*${search}*)|(@contact_number:*${search}*)`)
}
await redis.quit()
// await redis.quit()
// console.log('response: ', response)

View File

@ -0,0 +1,19 @@
import getNumberFromName from "./GetNumberSequence";
import phoneNumberStart from "./PhoneNumberStatusCode";
function validatePhoneName(name: string) {
if (getNumberFromName(name).length > 0 && getNumberFromName(name).length <= 6) {
return 'invalid_phone_number';
}
else if (getNumberFromName(name).length == 0) {
return 'no_phone_number';
}
else if (!phoneNumberStart(name)) {
return 'wrong_number_start'
}
}
export default validatePhoneName

View File

@ -14,7 +14,7 @@ const deleteWhatsappCache = async (hash: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const whatsapp_cache: any = await redis.hgetall(hash)
@ -32,7 +32,7 @@ const deleteWhatsappCache = async (hash: any) => {
console.log(`There was an error on deleteWhatsappCache: ${error}`)
}
await redis.quit()
// await redis.quit()
}
const updateWhatsappCache = async (hash: any, json_object: any) => {
@ -41,7 +41,7 @@ const updateWhatsappCache = async (hash: any, json_object: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
@ -53,7 +53,7 @@ const updateWhatsappCache = async (hash: any, json_object: any) => {
await pipeline.exec(() => { console.log("whatsapp Key/value inserted/updated") });
await redis.quit()
// await redis.quit()
}
@ -63,7 +63,7 @@ const updateWhatsappCacheById = async (hash: any, update_fields: object | any) =
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
const whatsapp_cache: any = await redis.hgetall(hash)
@ -83,7 +83,7 @@ const updateWhatsappCacheById = async (hash: any, update_fields: object | any) =
console.log(`There was an error on updateWhatsappCacheById: ${error}`)
}
await redis.quit()
// await redis.quit()
}
// const createOrUpdateContactCache = async (hash: any, contact: any) => {
@ -92,7 +92,7 @@ const updateWhatsappCacheById = async (hash: any, update_fields: object | any) =
// if(!redis) return
// if (redis.status !== 'connect') return
// // if (redis.status !== 'connect') return
// if (contact.name) {
// contact.escaped_name = escapeCharCache(contact.name)
@ -111,13 +111,13 @@ async function searchWhatsappCache(id: string, status: string) {
if (!redis) return
if (redis.status !== 'connect') return null
// if (redis.status !== 'connect') return null
const number_cache: any = await redis.hgetall(`whatsapp:${id}`)
if (Object.entries(number_cache).length == 0) {
await await redis.quit()
// await redis.quit()
return []
}
@ -128,7 +128,7 @@ async function searchWhatsappCache(id: string, status: string) {
const response: any = await redis.call('FT.SEARCH', 'idx_whatsapp', `(@status:*${status}*) (@number:*${number_cache.number}*)`, 'SORTBY', 'status', 'ASC')
await redis.quit()
// await redis.quit()
if (response.length === 1) {
@ -161,7 +161,7 @@ const insertOrUpeateWhatsCache = async (hash: any, whatsapp: any) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
if (Array.isArray(whatsapp)) {
@ -183,7 +183,7 @@ const insertOrUpeateWhatsCache = async (hash: any, whatsapp: any) => {
}
await redis.quit()
// await redis.quit()
}
@ -197,7 +197,7 @@ const loadWhatsappCache = async () => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
let whatsapps: any = await Whatsapp.findAll({ raw: true })
@ -215,7 +215,7 @@ const loadWhatsappCache = async () => {
await pipeline.exec(() => { console.log(`${whatsapps.length} WHATSAPPS INSERTED IN CACHE!`) });
await redis.quit()
// await redis.quit()
}
const createWhatsappIndexCache = async (hashIndex: string) => {
@ -224,7 +224,7 @@ const createWhatsappIndexCache = async (hashIndex: string) => {
if (!redis) return
if (redis.status !== 'connect') return
// if (redis.status !== 'connect') return
try {
@ -243,13 +243,13 @@ const createWhatsappIndexCache = async (hashIndex: string) => {
console.log('There was an error on createWhatsappIndexCache: ', error)
}
await redis.quit()
// await redis.quit()
}
export {
loadWhatsappCache,
searchWhatsappCache,
updateWhatsappCacheById,
insertOrUpeateWhatsCache,
deleteWhatsappCache
// loadWhatsappCache,
// searchWhatsappCache,
// updateWhatsappCacheById,
// insertOrUpeateWhatsCache,
// deleteWhatsappCache
}

View File

@ -2,15 +2,15 @@
class WhatsQueueIndex {
static staticIndex:Number = 0;
static staticIndex: number = 0;
static setIndex(index:Number){
static setIndex(index: number) {
this.staticIndex = index
}
static getIndex(){
static getIndex() {
return this.staticIndex
}
}
}
export default WhatsQueueIndex;
export default WhatsQueueIndex;

View File

@ -0,0 +1,74 @@
import os from 'os';
import dir from 'path';
import fs from 'fs';
export const setWhatsappId = (whatsappId: string, split?: any) => {
console.log('os.tmpdir(): ', os.tmpdir())
const whatsappIdFile = dir.join(os.tmpdir(), `whatsappIdInfo.txt`);
try {
if (split) {
fs.unlink(whatsappIdFile, (err) => {
if (err) {
throw err;
}
console.log(`Delete File ${whatsappIdFile} successfully.`);
});
}
fs.appendFile(whatsappIdFile, `${whatsappId},`, err => {
if (err) {
console.error(err);
}
// done!
});
} catch (error: any) {
console.log('There was an error on try to read/delete the whatsappIdInfo.json file: ', error)
}
}
export const getWhatsappIds = () => {
const whatsappIdFile = dir.join(os.tmpdir(), `whatsappIdInfo.txt`);
try {
if (fs.existsSync(whatsappIdFile)) {
let whatsappInfo: any = fs.readFileSync(whatsappIdFile, { encoding: 'utf8', flag: 'r' });
if (whatsappInfo && whatsappInfo.endsWith(',')) {
whatsappInfo = whatsappInfo.substring(0, whatsappInfo.length - 1);
}
whatsappInfo = whatsappInfo.split(',')
// console.log('xxxxxxxxxx whatsappInfo: ',whatsappInfo)
return whatsappInfo
} else {
console.log('restoreInfo.json file not found!');
}
} catch (error) {
console.log('There was an error on try to read the restoreInfo.json file: ', error)
}
return []
}

View File

@ -51,8 +51,6 @@ const emitterOnline = (user: any, status: string, showOnlineTime: boolean = true
}
}
console.log('ENTROU NO EMMITER ONLINE: ', user.id)
// console.log('-------------> onlineTime: ', onlineTime)
const io = getIO();

View File

@ -0,0 +1,242 @@
const country_code = [{"country":"Afghanistan","code":"93","iso":"AF"},
{"country":"Albania","code":"355","iso":"AL"},
{"country":"Algeria","code":"213","iso":"DZ"},
{"country":"American Samoa","code":"1-684","iso":"AS"},
{"country":"Andorra","code":"376","iso":"AD"},
{"country":"Angola","code":"244","iso":"AO"},
{"country":"Anguilla","code":"1-264","iso":"AI"},
{"country":"Antarctica","code":"672","iso":"AQ"},
{"country":"Antigua and Barbuda","code":"1-268","iso":"AG"},
{"country":"Argentina","code":"54","iso":"AR"},
{"country":"Armenia","code":"374","iso":"AM"},
{"country":"Aruba","code":"297","iso":"AW"},
{"country":"Australia","code":"61","iso":"AU"},
{"country":"Austria","code":"43","iso":"AT"},
{"country":"Azerbaijan","code":"994","iso":"AZ"},
{"country":"Bahamas","code":"1-242","iso":"BS"},
{"country":"Bahrain","code":"973","iso":"BH"},
{"country":"Bangladesh","code":"880","iso":"BD"},
{"country":"Barbados","code":"1-246","iso":"BB"},
{"country":"Belarus","code":"375","iso":"BY"},
{"country":"Belgium","code":"32","iso":"BE"},
{"country":"Belize","code":"501","iso":"BZ"},
{"country":"Benin","code":"229","iso":"BJ"},
{"country":"Bermuda","code":"1-441","iso":"BM"},
{"country":"Bhutan","code":"975","iso":"BT"},
{"country":"Bolivia","code":"591","iso":"BO"},
{"country":"Bosnia and Herzegovina","code":"387","iso":"BA"},
{"country":"Botswana","code":"267","iso":"BW"},
{"country":"Brazil","code":"55","iso":"BR"},
{"country":"British Indian Ocean Territory","code":"246","iso":"IO"},
{"country":"British Virgin Islands","code":"1-284","iso":"VG"},
{"country":"Brunei","code":"673","iso":"BN"},
{"country":"Bulgaria","code":"359","iso":"BG"},
{"country":"Burkina Faso","code":"226","iso":"BF"},
{"country":"Burundi","code":"257","iso":"BI"},
{"country":"Cambodia","code":"855","iso":"KH"},
{"country":"Cameroon","code":"237","iso":"CM"},
{"country":"Canada","code":"1","iso":"CA"},
{"country":"Cape Verde","code":"238","iso":"CV"},
{"country":"Cayman Islands","code":"1-345","iso":"KY"},
{"country":"Central African Republic","code":"236","iso":"CF"},
{"country":"Chad","code":"235","iso":"TD"},
{"country":"Chile","code":"56","iso":"CL"},
{"country":"China","code":"86","iso":"CN"},
{"country":"Christmas Island","code":"61","iso":"CX"},
{"country":"Cocos Islands","code":"61","iso":"CC"},
{"country":"Colombia","code":"57","iso":"CO"},
{"country":"Comoros","code":"269","iso":"KM"},
{"country":"Cook Islands","code":"682","iso":"CK"},
{"country":"Costa Rica","code":"506","iso":"CR"},
{"country":"Croatia","code":"385","iso":"HR"},
{"country":"Cuba","code":"53","iso":"CU"},
{"country":"Curacao","code":"599","iso":"CW"},
{"country":"Cyprus","code":"357","iso":"CY"},
{"country":"Czech Republic","code":"420","iso":"CZ"},
{"country":"Democratic Republic of the Congo","code":"243","iso":"CD"},
{"country":"Denmark","code":"45","iso":"DK"},
{"country":"Djibouti","code":"253","iso":"DJ"},
{"country":"Dominica","code":"1-767","iso":"DM"},
{"country":"Dominican Republic","code":"1-809, 1-829, 1-849","iso":"DO"},
{"country":"East Timor","code":"670","iso":"TL"},
{"country":"Ecuador","code":"593","iso":"EC"},
{"country":"Egypt","code":"20","iso":"EG"},
{"country":"El Salvador","code":"503","iso":"SV"},
{"country":"Equatorial Guinea","code":"240","iso":"GQ"},
{"country":"Eritrea","code":"291","iso":"ER"},
{"country":"Estonia","code":"372","iso":"EE"},
{"country":"Ethiopia","code":"251","iso":"ET"},
{"country":"Falkland Islands","code":"500","iso":"FK"},
{"country":"Faroe Islands","code":"298","iso":"FO"},
{"country":"Fiji","code":"679","iso":"FJ"},
{"country":"Finland","code":"358","iso":"FI"},
{"country":"France","code":"33","iso":"FR"},
{"country":"French Polynesia","code":"689","iso":"PF"},
{"country":"Gabon","code":"241","iso":"GA"},
{"country":"Gambia","code":"220","iso":"GM"},
{"country":"Georgia","code":"995","iso":"GE"},
{"country":"Germany","code":"49","iso":"DE"},
{"country":"Ghana","code":"233","iso":"GH"},
{"country":"Gibraltar","code":"350","iso":"GI"},
{"country":"Greece","code":"30","iso":"GR"},
{"country":"Greenland","code":"299","iso":"GL"},
{"country":"Grenada","code":"1-473","iso":"GD"},
{"country":"Guam","code":"1-671","iso":"GU"},
{"country":"Guatemala","code":"502","iso":"GT"},
{"country":"Guernsey","code":"44-1481","iso":"GG"},
{"country":"Guinea","code":"224","iso":"GN"},
{"country":"Guinea-Bissau","code":"245","iso":"GW"},
{"country":"Guyana","code":"592","iso":"GY"},
{"country":"Haiti","code":"509","iso":"HT"},
{"country":"Honduras","code":"504","iso":"HN"},
{"country":"Hong Kong","code":"852","iso":"HK"},
{"country":"Hungary","code":"36","iso":"HU"},
{"country":"Iceland","code":"354","iso":"IS"},
{"country":"India","code":"91","iso":"IN"},
{"country":"Indonesia","code":"62","iso":"ID"},
{"country":"Iran","code":"98","iso":"IR"},
{"country":"Iraq","code":"964","iso":"IQ"},
{"country":"Ireland","code":"353","iso":"IE"},
{"country":"Isle of Man","code":"44-1624","iso":"IM"},
{"country":"Israel","code":"972","iso":"IL"},
{"country":"Italy","code":"39","iso":"IT"},
{"country":"Ivory Coast","code":"225","iso":"CI"},
{"country":"Jamaica","code":"1-876","iso":"JM"},
{"country":"Japan","code":"81","iso":"JP"},
{"country":"Jersey","code":"44-1534","iso":"JE"},
{"country":"Jordan","code":"962","iso":"JO"},
{"country":"Kazakhstan","code":"7","iso":"KZ"},
{"country":"Kenya","code":"254","iso":"KE"},
{"country":"Kiribati","code":"686","iso":"KI"},
{"country":"Kosovo","code":"383","iso":"XK"},
{"country":"Kuwait","code":"965","iso":"KW"},
{"country":"Kyrgyzstan","code":"996","iso":"KG"},
{"country":"Laos","code":"856","iso":"LA"},
{"country":"Latvia","code":"371","iso":"LV"},
{"country":"Lebanon","code":"961","iso":"LB"},
{"country":"Lesotho","code":"266","iso":"LS"},
{"country":"Liberia","code":"231","iso":"LR"},
{"country":"Libya","code":"218","iso":"LY"},
{"country":"Liechtenstein","code":"423","iso":"LI"},
{"country":"Lithuania","code":"370","iso":"LT"},
{"country":"Luxembourg","code":"352","iso":"LU"},
{"country":"Macao","code":"853","iso":"MO"},
{"country":"Macedonia","code":"389","iso":"MK"},
{"country":"Madagascar","code":"261","iso":"MG"},
{"country":"Malawi","code":"265","iso":"MW"},
{"country":"Malaysia","code":"60","iso":"MY"},
{"country":"Maldives","code":"960","iso":"MV"},
{"country":"Mali","code":"223","iso":"ML"},
{"country":"Malta","code":"356","iso":"MT"},
{"country":"Marshall Islands","code":"692","iso":"MH"},
{"country":"Mauritania","code":"222","iso":"MR"},
{"country":"Mauritius","code":"230","iso":"MU"},
{"country":"Mayotte","code":"262","iso":"YT"},
{"country":"Mexico","code":"52","iso":"MX"},
{"country":"Micronesia","code":"691","iso":"FM"},
{"country":"Moldova","code":"373","iso":"MD"},
{"country":"Monaco","code":"377","iso":"MC"},
{"country":"Mongolia","code":"976","iso":"MN"},
{"country":"Montenegro","code":"382","iso":"ME"},
{"country":"Montserrat","code":"1-664","iso":"MS"},
{"country":"Morocco","code":"212","iso":"MA"},
{"country":"Mozambique","code":"258","iso":"MZ"},
{"country":"Myanmar","code":"95","iso":"MM"},
{"country":"Namibia","code":"264","iso":"NA"},
{"country":"Nauru","code":"674","iso":"NR"},
{"country":"Nepal","code":"977","iso":"NP"},
{"country":"Netherlands","code":"31","iso":"NL"},
{"country":"Netherlands Antilles","code":"599","iso":"AN"},
{"country":"New Caledonia","code":"687","iso":"NC"},
{"country":"New Zealand","code":"64","iso":"NZ"},
{"country":"Nicaragua","code":"505","iso":"NI"},
{"country":"Niger","code":"227","iso":"NE"},
{"country":"Nigeria","code":"234","iso":"NG"},
{"country":"Niue","code":"683","iso":"NU"},
{"country":"North Korea","code":"850","iso":"KP"},
{"country":"Northern Mariana Islands","code":"1-670","iso":"MP"},
{"country":"Norway","code":"47","iso":"NO"},
{"country":"Oman","code":"968","iso":"OM"},
{"country":"Pakistan","code":"92","iso":"PK"},
{"country":"Palau","code":"680","iso":"PW"},
{"country":"Palestine","code":"970","iso":"PS"},
{"country":"Panama","code":"507","iso":"PA"},
{"country":"Papua New Guinea","code":"675","iso":"PG"},
{"country":"Paraguay","code":"595","iso":"PY"},
{"country":"Peru","code":"51","iso":"PE"},
{"country":"Philippines","code":"63","iso":"PH"},
{"country":"Pitcairn","code":"64","iso":"PN"},
{"country":"Poland","code":"48","iso":"PL"},
{"country":"Portugal","code":"351","iso":"PT"},
{"country":"Puerto Rico","code":"1-787, 1-939","iso":"PR"},
{"country":"Qatar","code":"974","iso":"QA"},
{"country":"Republic of the Congo","code":"242","iso":"CG"},
{"country":"Reunion","code":"262","iso":"RE"},
{"country":"Romania","code":"40","iso":"RO"},
{"country":"Russia","code":"7","iso":"RU"},
{"country":"Rwanda","code":"250","iso":"RW"},
{"country":"Saint Barthelemy","code":"590","iso":"BL"},
{"country":"Saint Helena","code":"290","iso":"SH"},
{"country":"Saint Kitts and Nevis","code":"1-869","iso":"KN"},
{"country":"Saint Lucia","code":"1-758","iso":"LC"},
{"country":"Saint Martin","code":"590","iso":"MF"},
{"country":"Saint Pierre and Miquelon","code":"508","iso":"PM"},
{"country":"Saint Vincent and the Grenadines","code":"1-784","iso":"VC"},
{"country":"Samoa","code":"685","iso":"WS"},
{"country":"San Marino","code":"378","iso":"SM"},
{"country":"Sao Tome and Principe","code":"239","iso":"ST"},
{"country":"Saudi Arabia","code":"966","iso":"SA"},
{"country":"Senegal","code":"221","iso":"SN"},
{"country":"Serbia","code":"381","iso":"RS"},
{"country":"Seychelles","code":"248","iso":"SC"},
{"country":"Sierra Leone","code":"232","iso":"SL"},
{"country":"Singapore","code":"65","iso":"SG"},
{"country":"Sint Maarten","code":"1-721","iso":"SX"},
{"country":"Slovakia","code":"421","iso":"SK"},
{"country":"Slovenia","code":"386","iso":"SI"},
{"country":"Solomon Islands","code":"677","iso":"SB"},
{"country":"Somalia","code":"252","iso":"SO"},
{"country":"South Africa","code":"27","iso":"ZA"},
{"country":"South Korea","code":"82","iso":"KR"},
{"country":"South Sudan","code":"211","iso":"SS"},
{"country":"Spain","code":"34","iso":"ES"},
{"country":"Sri Lanka","code":"94","iso":"LK"},
{"country":"Sudan","code":"249","iso":"SD"},
{"country":"Suriname","code":"597","iso":"SR"},
{"country":"Svalbard and Jan Mayen","code":"47","iso":"SJ"},
{"country":"Swaziland","code":"268","iso":"SZ"},
{"country":"Sweden","code":"46","iso":"SE"},
{"country":"Switzerland","code":"41","iso":"CH"},
{"country":"Syria","code":"963","iso":"SY"},
{"country":"Taiwan","code":"886","iso":"TW"},
{"country":"Tajikistan","code":"992","iso":"TJ"},
{"country":"Tanzania","code":"255","iso":"TZ"},
{"country":"Thailand","code":"66","iso":"TH"},
{"country":"Togo","code":"228","iso":"TG"},
{"country":"Tokelau","code":"690","iso":"TK"},
{"country":"Tonga","code":"676","iso":"TO"},
{"country":"Trinidad and Tobago","code":"1-868","iso":"TT"},
{"country":"Tunisia","code":"216","iso":"TN"},
{"country":"Turkey","code":"90","iso":"TR"},
{"country":"Turkmenistan","code":"993","iso":"TM"},
{"country":"Turks and Caicos Islands","code":"1-649","iso":"TC"},
{"country":"Tuvalu","code":"688","iso":"TV"},
{"country":"U.S. Virgin Islands","code":"1-340","iso":"VI"},
{"country":"Uganda","code":"256","iso":"UG"},
{"country":"Ukraine","code":"380","iso":"UA"},
{"country":"United Arab Emirates","code":"971","iso":"AE"},
{"country":"United Kingdom","code":"44","iso":"GB"},
{"country":"United States","code":"1","iso":"US"},
{"country":"Uruguay","code":"598","iso":"UY"},
{"country":"Uzbekistan","code":"998","iso":"UZ"},
{"country":"Vanuatu","code":"678","iso":"VU"},
{"country":"Vatican","code":"379","iso":"VA"},
{"country":"Venezuela","code":"58","iso":"VE"},
{"country":"Vietnam","code":"84","iso":"VN"},
{"country":"Wallis and Futuna","code":"681","iso":"WF"},
{"country":"Western Sahara","code":"212","iso":"EH"},
{"country":"Yemen","code":"967","iso":"YE"},
{"country":"Zambia","code":"260","iso":"ZM"},
{"country":"Zimbabwe","code":"263","iso":"ZW"}]
export default country_code;

View File

@ -15,6 +15,9 @@ import { splitDateTime } from "../helpers/SplitDateTime";
import format from 'date-fns/format';
import ptBR from 'date-fns/locale/pt-BR';
import ListUserOnlineOffline from "../services/UserServices/ListUsersOnlineOfflineService";
import { handleMessage, handleMsgAck } from "../services/WbotServices/wbotMessageListener";
import { join } from "path";
import Whatsapp from "../models/Whatsapp";
let count: number = 0
let listOnline: any[] = []
@ -29,8 +32,6 @@ let lstOnline: any[] = []
let lstOnlineAux: any[] = []
let lstTry: any[] = []
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
@ -38,7 +39,8 @@ export const initIO = (httpServer: Server): SocketIO => {
io = new SocketIO(httpServer, {
cors: {
origin: process.env.FRONTEND_URL
}
},
maxHttpBufferSize: 1e8
});
@ -46,6 +48,49 @@ export const initIO = (httpServer: Server): SocketIO => {
logger.info("Client Connected");
socket.on("joinWhatsSession", (whatsappId: string) => {
logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`);
socket.join(`session_${whatsappId}`);
});
socket.on("message_from_client", () => {
socket.emit('message_from_server', 'Sent an event from the server!');
})
socket.on("message_create", async (data: any) => {
handleMessage(data.msg, data);
});
socket.on("media_uploaded", async (data: any) => {
handleMessage(data.msg, data);
});
socket.on("message_ack", async (data: any) => {
handleMsgAck(data.id, data.ack)
});
socket.on("online", (userId: any) => {
// console.log('userId: ', userId)
@ -189,8 +234,54 @@ export const initIO = (httpServer: Server): SocketIO => {
socket.join(status);
});
socket.on("disconnect", () => {
logger.info("Client disconnected");
socket.on("disconnect", (data: any) => {
logger.info(`Client disconnected socket: ${data}`);
});
socket.on("disconnecting", async () => {
console.log('socket.rooms: ', socket.rooms); // the Set contains at least the socket ID
let rooms = socket.rooms
console.log('rooms: ', rooms, ' | rooms.size: ', rooms.size)
if(rooms && rooms.size==1) return
if(rooms && rooms.size==2 && !([...rooms][1].startsWith('session_'))) return
let whatsappIds: any = await Whatsapp.findAll({ attributes: ['id'], raw: true })
if (whatsappIds && whatsappIds.length > 0) {
whatsappIds = whatsappIds.map((e: any) => `${e.id}`)
console.log('whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ',whatsappIds)
if (rooms && rooms.size == 2 &&
[...rooms][1].startsWith('session_') &&
whatsappIds.includes([...rooms][1].replace('session_', ''))) {
console.log([...rooms][1])
let whatsappId = [...rooms][1].replace('session_', '')
const whatsapp = await Whatsapp.findByPk(whatsappId, {})
if (whatsapp) {
await whatsapp.update({ status: 'OPENING' });
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
}
}
}
});
});
return io;
@ -204,6 +295,11 @@ export const getIO = (): SocketIO => {
};
function writeFileAsync(arg0: any, data: any, arg2: string) {
throw new Error("Function not implemented.");
}
// exports.listOnlineUsers = listUserId
// exports.listUserId

View File

@ -20,11 +20,12 @@ const sessions: Session[] = [];
let backupSession: any[] = []
import { insertOrUpeateWhatsCache } from "../helpers/WhatsCache";
// import { insertOrUpeateWhatsCache } from "../helpers/WhatsCache";
import { json } from "sequelize/types";
import { restartWhatsSession } from "../helpers/RestartWhatsSession";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
let miliseconds = [1000, 2000, 3000]
const syncUnreadMessages = async (wbot: Session) => {
const chats = await wbot.getChats();
@ -32,7 +33,9 @@ const syncUnreadMessages = async (wbot: Session) => {
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
for (const chat of chats) {
if (chat.unreadCount > 0) {
const unreadMessages = await chat.fetchMessages({
limit: chat.unreadCount
});
@ -46,6 +49,7 @@ const syncUnreadMessages = async (wbot: Session) => {
await chat.sendSeen();
}
}
};
@ -70,9 +74,24 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
// });
// usando instancia do chrome
// const wbot: Session = new Client({
// session: sessionCfg, authStrategy: new LocalAuth({ clientId: 'bd_' + whatsapp.id }),
// // puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || undefined },
// puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
// });
const args: String = process.env.CHROME_ARGS || "";
const wbot: Session = new Client({
session: sessionCfg, authStrategy: new LocalAuth({ clientId: 'bd_' + whatsapp.id }),
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
session: sessionCfg,
authStrategy: new LocalAuth({ clientId: 'bd_' + whatsapp.id }),
puppeteer: {
executablePath: process.env.CHROME_BIN || undefined,
// @ts-ignore
browserWSEndpoint: process.env.CHROME_WS || undefined,
args: args.split(' ')
}
});
@ -90,7 +109,7 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
logger.info("Session:", sessionName);
qrCode.generate(qr, { small: true });
await whatsapp.update({ qrcode: qr, status: "qrcode", retries: 0 });
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { qrcode: qr, status: "qrcode", retries: 0 })
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { qrcode: qr, status: "qrcode", retries: 0 })
const sessionIndex = sessions.findIndex(s => s.id === whatsapp.id);
if (sessionIndex === -1) {
@ -116,7 +135,7 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
if (whatsapp.retries > 1) {
await whatsapp.update({ session: "", retries: 0 });
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { session: "", retries: 0 })
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { session: "", retries: 0 })
}
const retry = whatsapp.retries;
@ -124,10 +143,10 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
status: "DISCONNECTED",
retries: retry + 1
});
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
status: "DISCONNECTED",
retries: retry + 1
})
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
// status: "DISCONNECTED",
// retries: retry + 1
// })
io.emit("whatsappSession", {
action: "update",
@ -140,10 +159,10 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
wbot.on("ready", async () => {
logger.info(`Session: ${sessionName} READY`);
if(whatsapp.name.includes(wbot.info["wid"]["user"])){
if (whatsapp.name.includes(wbot.info["wid"]["user"])) {
console.log('-----------------> THIS IS THE RIGHT NUMBER')
}
else{
else {
console.log('-----------------> THIS IS THE WRONG NUMBER')
let read_number = wbot.info["wid"]["user"]
@ -151,11 +170,9 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
io.emit("whatsappSession", {
action: "error",
msg: `Numero lido: ${read_number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`
msg: `Numero lido: ${read_number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`
});
// restartWhatsSession(whatsapp)
return
}
@ -166,7 +183,7 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
retries: 0,
number: wbot.info["wid"]["user"]
});
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`,whatsapp)
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, whatsapp)
io.emit("whatsappSession", {
action: "update",
@ -222,12 +239,10 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
}, 90000);
console.log(' PASSOU NO TIMEOUT whatsapp.id: ',whatsapp.id)
console.log(' PASSOU NO TIMEOUT whatsapp.id: ', whatsapp.id)
}
});
} catch (err) {
logger.error(`${err}`);
@ -235,16 +250,54 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
});
};
export const getWbot = (whatsappId: number): Session => {
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
export const getWbot = async (whatsappId: number | string): Promise<any> => {
// console.log('----------> sessionIndex: ', sessionIndex, ' | whatasappId: ', whatsappId)
// console.log('----------> sessions: ',sessions.map(s => s.id))
console.log('getWbot whatsappId: ', whatsappId)
let whatsapp = await Whatsapp.findByPk(whatsappId, {
attributes: ["url"]
})
if (whatsapp && whatsapp.status != 'CONNECTED') {
let listWhatsapp: any = null
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
if (!listWhatsapp) {
listWhatsapp = await ListWhatsAppsNumber(whatsappId, 'CONNECTED')
}
if (listWhatsapp.whatsapps && listWhatsapp.whatsapps.length > 0) {
console.log('----------> getWbot has changed the whatsappId: ', listWhatsapp.whatsapps[0].id)
whatsapp = await Whatsapp.findByPk(listWhatsapp.whatsapps[0].id, {
attributes: ["url"]
})
}
if (sessionIndex === -1) {
throw new AppError("ERR_WAPP_NOT_INITIALIZED");
}
return sessions[sessionIndex];
if (whatsapp && (whatsapp.url && whatsapp.url.length > 0)) {
return whatsapp.url
}
return null
// const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
// if (sessionIndex === -1) {
// throw new AppError("ERR_WAPP_NOT_INITIALIZED");
// }
// return sessions[sessionIndex];
};
export const removeWbot = (whatsappId: number): void => {

View File

@ -56,6 +56,12 @@ class Whatsapp extends Model<Whatsapp> {
@Column
number: string;
@Column
url: string;
@Column
urlApi: string;
@Default(false)
@AllowNull
@Column

View File

@ -15,6 +15,7 @@ import schedulingNotifiyRoutes from "./SchedulingNotifyRoutes";
import statusChatEndRoutes from "./statusChatEndRoutes";
import dialogflowRoutes from "./dialogflowRoutes";
import hitRoutes from "./hitRoutes";
import wbotMonitorRoutes from "./wbotMonitorRoutes";
const routes = Router();
@ -35,5 +36,6 @@ routes.use(reportRoutes);
routes.use(statusChatEndRoutes);
routes.use(dialogflowRoutes);
routes.use(hitRoutes);
routes.use(wbotMonitorRoutes);
export default routes;

View File

@ -0,0 +1,12 @@
import { Router } from "express";
import isAuth from "../middleware/isAuth";
import * as WbotMonitorController from "../controllers/WbotMonitorController";
const userRoutes = Router();
userRoutes.post("/whatsapp/connection/monitor", WbotMonitorController.wbotMonitorRemote);
userRoutes.post("/whatsapp/connection/qrcode", WbotMonitorController.wbotMonitorQrcodeRemote);
userRoutes.post("/whatsapp/connection/number", WbotMonitorController.wbotMonitorQrcodeNumberRead);
export default userRoutes;

View File

@ -1,48 +1,132 @@
import gracefulShutdown from "http-graceful-shutdown";
import app from "./app";
import { initIO } from "./libs/socket";
import { initIO, getIO } from "./libs/socket";
import { logger } from "./utils/logger";
import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhatsAppsSessions";
import "./helpers/SchedulingNotifySendMessage"
import "./helpers/WhoIsOnlineMonitor"
import { loadTicketsCache, flushCache, cacheSize } from './helpers/TicketCache'
import { loadContactsCache } from './helpers/ContactsCache'
import User from "./models/User";
import Whatsapp from "./models/Whatsapp";
import endPointQuery from "./helpers/EndPointQuery";
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
import { loadContactsCache } from "./helpers/ContactsCache";
import "./helpers/CloseBotTickets";
import { loadWhatsappCache } from './helpers/WhatsCache'
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
import { delRestoreControllFile } from "./helpers/RestoreControll";
import { createSessionDir } from "./helpers/CreateSessionDir";
import { loadSchedulesCache, } from "./helpers/SchedulingNotifyCache";
import "./helpers/SchedulingNotifySendMessage"
import axios from "axios";
import os from 'os';
const server = app.listen(process.env.PORT, () => {
logger.info(`Server started on port: ${process.env.PORT}`);
});
// if (global.gc) {
// console.log(">> Starting Garbage Collector...");
// global.gc();
// } else {
// console.warn('No GC hook! Start your program as `node --expose-gc file.js`.');
// }
initIO(server);
StartAllWhatsAppsSessions();
// StartAllWhatsAppsSessions();
gracefulShutdown(server);
(async()=>{
const cacheLength = await cacheSize()
console.log('os.tmpdir(): ', os.tmpdir())
console.log('cacheSize: ', cacheLength)
let whatsapps: any = await Whatsapp.findAll({ attributes: ['id', 'url'] })
if (cacheLength == 0) {
console.log('Loading from cache...')
await flushCache()
await loadContactsCache()
await loadTicketsCache()
// console.log('whatsapps: ', whatsapps)
if (whatsapps && whatsapps.length > 0) {
for (let i = 0; i < whatsapps.length; i++) {
try {
console.log(`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`)
const response = await axios.get(`${whatsapps[i].dataValues.url}/api/connection/status`, {});
console.log(`-------> Response: ${response.data.data}`)
if (!response) {
throw new Error('Response null');
}
if (response.data.data && response.data.data == 'CONNECTED') {
await whatsapps[i].update({ status: 'CONNECTED' });
}
} catch (error: any) {
await whatsapps[i].update({ status: 'OPENING' });
console.log(`There was an error on try acess the api sessions ${whatsapps[i].dataValues.url}`)
}
await new Promise(f => setTimeout(f, 100));
}
}
await loadWhatsappCache()
await loadSchedulesCache()
if (process.env.CACHE) {
const cacheLength = await cacheSize()
console.log('cacheSize: ', cacheLength)
if (cacheLength == 0) {
console.log('Loading from cache...')
await flushCache()
await loadContactsCache()
await loadTicketsCache()
}
await loadSchedulesCache()
// await loadWhatsappCache()
}
delRestoreControllFile()
})()
createSessionDir()
delRestoreControllFile()
setTimeout(async () => {
const io = getIO();
console.log('Triggered socket!')
let users = await User.findAll({ raw: true, attributes: ["id"], })
if (users && users.length > 0) {
for (let i = 0; i < users.length; i++) {
io.emit("reload_page", {
action: "update",
userId: users[i].id
});
console.log('USER ID: ', users[i].id)
await new Promise(f => setTimeout(f, 100));
}
}
}, 5000)

View File

@ -2,6 +2,7 @@ import AppError from "../../errors/AppError";
import Contact from "../../models/Contact";
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
import GetProfilePicUrl from "../WbotServices/GetProfilePicUrl";
interface ExtraInfo {
@ -23,8 +24,10 @@ const CreateContactService = async ({
number,
email = "",
useDialogflow,
profilePicUrl='',
extraInfo = []
}: Request): Promise<Contact> => {
const numberExists = await Contact.findOne({
where: { number }
});
@ -39,6 +42,7 @@ const CreateContactService = async ({
number,
email,
useDialogflow,
profilePicUrl,
extraInfo
},
{
@ -47,8 +51,9 @@ const CreateContactService = async ({
);
// TEST DEL
await createOrUpdateContactCache(`contact:${contact.id}`, {id: contact.id, name, number, profilePicUrl:'', isGroup:'false', extraInfo, email })
await createOrUpdateContactCache(`contact:${contact.id}`, {id: contact.id, name, number, profilePicUrl, isGroup:'false', extraInfo, email })
//
return contact;

View File

@ -29,6 +29,8 @@ const UpdateContactService = async ({
}: Request): Promise<Contact> => {
const { email, name, number, extraInfo } = contactData;
// console.log('email, name, number, extraInfo: ', email, name, number, extraInfo)
const contact = await Contact.findOne({
where: { id: contactId },
attributes: ["id", "name", "number", "email", "profilePicUrl"],
@ -59,6 +61,22 @@ const UpdateContactService = async ({
const oldNumber = contact.number
//Solução para o erro tcp_wrap.cc
// console.log('----------> oldNumber: ', oldNumber)
if (number) {
const numberExists = await Contact.findOne({
where: { number }
});
if (numberExists) {
throw new AppError("ERR_DUPLICATED_CONTACT");
}
}
//
await contact.update({
name,
number,

View File

@ -18,6 +18,9 @@ interface Request {
}
const CreateMessageService = async ({ messageData }: Request): Promise<Message> => {
// console.log('UPSERT MESSAGE messageData: ', messageData)
await Message.upsert(messageData);
const message = await Message.findByPk(messageData.id, {
@ -54,6 +57,8 @@ const CreateMessageService = async ({ messageData }: Request): Promise<Message>
})
//
console.log('message.ticketId.toString(): ', message.ticketId.toString())
console.log('message.ticket.status: ',message.ticket.status)
const io = getIO();
io.to(message.ticketId.toString())

View File

@ -16,6 +16,7 @@ const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss
import ListTicketServiceCache from "./ListTicketServiceCache"
import { searchTicketCache, loadTicketsCache } from '../../helpers/TicketCache'
import { getWbot } from "../../libs/wbot";
interface Request {
@ -53,6 +54,11 @@ const ListTicketsService = async ({
console.log('PAGE NUMBER TICKET: ', pageNumber)
//TEST DEL
// const url = await getWbot(46)
// console.log('---------> URL: ', url)
//
if (pageNumber.trim().length == 0) {
pageNumber = '1'
}
@ -196,7 +202,6 @@ const ListTicketsService = async ({
console.log('ENTROU NO LIST TICKET SERVICE')
const { count, rows: tickets } = await Ticket.findAndCountAll({
where: whereCondition,

View File

@ -27,6 +27,8 @@ const ShowTicketService = async (id: string | number): Promise<Ticket> => {
]
});
console.log('>>>>>>>>>>>>>>>>>>>>>>>> ShowTicketService: ',ticket?.whatsappId)
if (!ticket) {
throw new AppError("ERR_NO_TICKET_FOUND", 404);
}

View File

@ -36,7 +36,7 @@ const UpdateTicketService = async ({
const { status, userId, queueId, statusChatEnd } = ticketData;
const ticket = await ShowTicketService(ticketId);
await SetTicketMessagesAsRead(ticket);
// await SetTicketMessagesAsRead(ticket);
const oldStatus = ticket.status;
const oldUserId = ticket.user?.id;

View File

@ -31,7 +31,7 @@ const CreateUserService = async ({
const schema = Yup.object().shape({
name: Yup.string().required().min(2),
email: Yup.string().required().test(
email: Yup.string().required().trim().test(
"Check-email",
"An user with this email already exists.",
async value => {
@ -60,7 +60,7 @@ const CreateUserService = async ({
try {
await schema.validate({ email, password, name });
} catch (err) {
} catch (err:any) {
throw new AppError(err.message);
}

View File

@ -2,6 +2,7 @@ import * as Yup from "yup";
import AppError from "../../errors/AppError";
import ShowUserService from "./ShowUserService";
import User from "../../models/User";
import deleteFileFromTMP from "../../helpers/deleteFileFromTMP";
@ -33,23 +34,40 @@ const UpdateUserService = async ({
const schema = Yup.object().shape({
name: Yup.string().min(2),
email: Yup.string().min(2),
// email: Yup.string().email(),
// email: Yup.string().min(2),
profile: Yup.string(),
password: Yup.string()
password: Yup.string(),
email: Yup.string().trim().required().test(
"Check-email",
"An user with this email already exists.",
async value => {
if (!value) return false;
const emailExists = await User.findOne({ where: { email: value }, raw: true, attributes: ['email', 'id'] });
if (emailExists && user.id != emailExists?.id) {
console.error('The email already exists in another user profile!')
return !emailExists;
}
return true
}
),
});
const { email, password, profile, name, queueIds = [] } = userData;
try {
await schema.validate({ email, password, profile, name });
} catch (err) {
} catch (err: any) {
throw new AppError(err.message);
}
await user.update({
email,
password,

View File

@ -1,23 +1,36 @@
import AppError from "../../errors/AppError";
import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot";
const CheckIsValidContact = async (number: string): Promise<void> => {
const CheckIsValidContact = async (number: string): Promise<any> => {
const defaultWhatsapp = await GetDefaultWhatsApp();
const wbot = getWbot(defaultWhatsapp.id);
const wbot_url = await getWbot(defaultWhatsapp.id);
const isValidNumber = await endPointQuery(`${wbot_url}/api/validate`, { mobile: `${number}`, })
// console.log('isValidNumber.data.number: ', isValidNumber.data.number)
try {
const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
if (!isValidNumber) {
// const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`);
if (!isValidNumber || isValidNumber && !isValidNumber.data.isValid) {
throw new AppError("invalidNumber");
}
} catch (err:any) {
} catch (err: any) {
if (err.message === "invalidNumber") {
throw new AppError("ERR_WAPP_INVALID_CONTACT");
}
throw new AppError("ERR_WAPP_CHECK_CONTACT");
}
if (isValidNumber && isValidNumber.data.isValid)
return isValidNumber.data.number
};
export default CheckIsValidContact;

View File

@ -2,12 +2,12 @@ import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot";
const CheckContactNumber = async (number: string): Promise<void> => {
const defaultWhatsapp = await GetDefaultWhatsApp();
// const defaultWhatsapp = await GetDefaultWhatsApp();
const wbot = getWbot(defaultWhatsapp.id);
// const wbot = getWbot(defaultWhatsapp.id);
const validNumber : any = await wbot.getNumberId(`${number}@c.us`);
return validNumber.user
// const validNumber : any = await wbot.getNumberId(`${number}@c.us`);
// return validNumber.user
};
export default CheckContactNumber;

View File

@ -1,9 +1,11 @@
import AppError from "../../errors/AppError";
import endPointQuery from "../../helpers/EndPointQuery";
import GetWbotMessage from "../../helpers/GetWbotMessage";
import { getWbot } from "../../libs/wbot";
import Message from "../../models/Message";
import Ticket from "../../models/Ticket";
const DeleteWhatsAppMessage = async (messageId: string): Promise<Message> => {
const DeleteWhatsAppMessage = async (messageId: string): Promise<Message | any> => {
const message = await Message.findByPk(messageId, {
include: [
{
@ -20,15 +22,35 @@ const DeleteWhatsAppMessage = async (messageId: string): Promise<Message> => {
const { ticket } = message;
const messageToDelete = await GetWbotMessage(ticket, messageId);
let limit = 20;
try {
await messageToDelete.delete(true);
} catch (err) {
const wbot_url = await getWbot(ticket.whatsappId);
const messageToDelete = await endPointQuery(`${wbot_url}/api/DeleteWhatsAppMessage`, {
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
messageId: messageId,
limit: limit
})
// console.log('messageToDelete.data.data: ',messageToDelete.data.data)
// const { ticket } = message;
// const messageToDelete = await GetWbotMessage(ticket, messageId);
// try {
// await messageToDelete.delete(true);
// } catch (err) {
// throw new AppError("ERR_DELETE_WAPP_MSG");
// }
if (messageToDelete && messageToDelete.data.data) {
await message.update({ isDeleted: true });
}
else{
throw new AppError("ERR_DELETE_WAPP_MSG");
}
await message.update({ isDeleted: true });
return message;
};

View File

@ -1,14 +1,27 @@
import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot";
const GetProfilePicUrl = async (number: string): Promise<string> => {
const GetProfilePicUrl = async (number: string): Promise<any> => {
const defaultWhatsapp = await GetDefaultWhatsApp();
const wbot = getWbot(defaultWhatsapp.id);
const wbot_url = await getWbot(defaultWhatsapp.id);
const profilePicUrl = await wbot.getProfilePicUrl(`${number}@c.us`);
// const profilePicUrl = await wbot.getProfilePicUrl(`${number}@c.us`);
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, })
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data)
if (profilePicUrl && profilePicUrl.data.data) {
console.log('GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG')
return profilePicUrl.data.data;
}
return null
return profilePicUrl;
};
export default GetProfilePicUrl;

View File

@ -6,47 +6,47 @@ import { logger } from "../../utils/logger";
import { createOrUpdateContactCache } from '../../helpers/ContactsCache'
const ImportContactsService = async (): Promise<void> => {
const defaultWhatsapp = await GetDefaultWhatsApp();
// const defaultWhatsapp = await GetDefaultWhatsApp();
const wbot = getWbot(defaultWhatsapp.id);
// const wbot = getWbot(defaultWhatsapp.id);
let phoneContacts;
// let phoneContacts;
try {
phoneContacts = await wbot.getContacts();
} catch (err) {
logger.error(`Could not get whatsapp contacts from phone. Err: ${err}`);
}
// try {
// phoneContacts = await wbot.getContacts();
// } catch (err) {
// logger.error(`Could not get whatsapp contacts from phone. Err: ${err}`);
// }
if (phoneContacts) {
await Promise.all(
phoneContacts.map(async ({ number, name }) => {
if (!number) {
return null;
}
if (!name) {
name = number;
}
// if (phoneContacts) {
// await Promise.all(
// phoneContacts.map(async ({ number, name }) => {
// if (!number) {
// return null;
// }
// if (!name) {
// name = number;
// }
const numberExists = await Contact.findOne({
where: { number }
});
// const numberExists = await Contact.findOne({
// where: { number }
// });
if (numberExists) return null;
// if (numberExists) return null;
let contact = await Contact.create({ number, name });
// let contact = await Contact.create({ number, name });
// await contact.reload()
// // await contact.reload()
// TEST DEL
await createOrUpdateContactCache(`contact:${contact.id}`, {id:contact.id, name, number, profilePicUrl: contact.profilePicUrl, isGroup: contact.isGroup, extraInfo: '', email:'' })
//
// // TEST DEL
// await createOrUpdateContactCache(`contact:${contact.id}`, {id:contact.id, name, number, profilePicUrl: contact.profilePicUrl, isGroup: contact.isGroup, extraInfo: '', email:'' })
// //
// return Contact.create({ number, name });
return contact
})
);
}
// // return Contact.create({ number, name });
// return contact
// })
// );
// }
};
export default ImportContactsService;

View File

@ -6,6 +6,9 @@ import Ticket from "../../models/Ticket";
import { updateTicketCacheByTicketId } from '../../helpers/TicketCache'
import { date } from "faker";
import { getIO } from "../../libs/socket";
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
import sendWhatsAppMediaSocket from "../../helpers/SendWhatsappMessageMediaSocket";
interface Request {
media: Express.Multer.File;
@ -15,13 +18,15 @@ interface Request {
const SendWhatsAppMedia = async ({
media,
ticket
}: Request): Promise<WbotMessage> => {
}: Request): Promise<WbotMessage | any> => {
try {
const wbot = await GetTicketWbot(ticket);
// const wbot = await GetTicketWbot(ticket);
const newMedia = MessageMedia.fromFilePath(media.path);
const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, newMedia, { sendAudioAsVoice: true });
//const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, newMedia, { sendAudioAsVoice: true });
sendWhatsAppMediaSocket(ticket, newMedia);
await ticket.update({ lastMessage: media.filename });
@ -29,12 +34,17 @@ const SendWhatsAppMedia = async ({
await updateTicketCacheByTicketId(ticket.id, { lastMessage: media.filename, updatedAt: new Date(ticket.updatedAt).toISOString() })
//
console.log('media.path: ', media.path)
fs.unlinkSync(media.path);
return sentMessage;
// return sentMessage;
} catch (err) {
throw new AppError("ERR_SENDING_WAPP_MSG");
}
};
export default SendWhatsAppMedia;

View File

@ -20,10 +20,12 @@ import { json } from "sequelize/types";
import sendMessageMultiSession from "../../helpers/TrySendMessageMultiSession";
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
import { insertOrUpeateWhatsCache, searchWhatsappCache } from "../../helpers/WhatsCache";
// import { insertOrUpeateWhatsCache, searchWhatsappCache } from "../../helpers/WhatsCache";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import autoRestore from "../../helpers/AutoRestore";
import { _restore } from "../../helpers/RestoreControll";
import { getIO } from "../../libs/socket";
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
@ -37,48 +39,102 @@ const SendWhatsAppMessage = async ({
body,
ticket,
quotedMsg
}: Request): Promise<WbotMessage> => {
}: Request): Promise<WbotMessage | any> => {
let timestamp = Math.floor(Date.now() / 1000)
var timetaken = `########################################${timestamp}| TicketId: ${ticket.id} => Time taken to send the message`;
console.time(timetaken)
let quotedMsgSerializedId: string | undefined;
if (quotedMsg) {
await GetWbotMessage(ticket, quotedMsg.id);
quotedMsgSerializedId = SerializeWbotMsgId(ticket, quotedMsg);
}
console.log('quotedMsgSerializedId: ', quotedMsgSerializedId)
let whatsapps: any
let listWhatsapp = null
listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
console.log('ticket.whatsappIdticket.whatsappIdticket.whatsappIdticket: ', ticket.whatsappId)
if (!listWhatsapp) {
listWhatsapp = await ListWhatsAppsNumber(ticket.whatsappId, 'CONNECTED')
}
if (listWhatsapp.whatsapp && listWhatsapp.whatsapp.status != 'CONNECTED' && listWhatsapp.whatsapps.length > 0) {
if (listWhatsapp.length > 1) {
console.log('kkkkkkkkkkkkkkkkkkkkkkkkkkkk: ', listWhatsapp.whatsapps[0].id)
console.log('entrou --------------------->')
await ticket.update({ whatsappId: + listWhatsapp.whatsapps[0].id });
const _whatsapp = listWhatsapp[Math.floor(Math.random() * listWhatsapp.length)];
let _ticket = await Ticket.findByPk(listWhatsapp.whatsapps[0].id)
}
if (listWhatsapp.whatsapps.length > 1) {
const _whatsapp = listWhatsapp.whatsapps[Math.floor(Math.random() * listWhatsapp.whatsapps.length)];
await ticket.update({ whatsappId: +_whatsapp.id });
// await ticket.reload();
}
// console.log('listWhatsapp.whatsapps.length: ', listWhatsapp.whatsapps.length)
// console.log('listWhatsapp.whatsapp.status: ', listWhatsapp.whatsapp.status)
if (listWhatsapp.whatsapps.length == 0 && listWhatsapp.whatsapp.status != 'CONNECTED') {
console.log('listWhatsapp.whatsapps == 0')
whatsapps = await wbotByUserQueue(ticket.userId)
console.log('============> The whatsapps: ', whatsapps)
if (whatsapps.length > 0) {
if (whatsapps.length > 1) {
await ticket.update({ whatsappId: whatsapps[+WhatsIndex(whatsapps)].id });
}
else {
await ticket.update({ whatsappId: whatsapps[0].id });
}
}
}
console.log('1 --------> ticket.whatsappId: ', ticket.whatsappId)
if (listWhatsapp.length == 0) {
// const wbot = await GetTicketWbot(ticket);
whatsapps = await wbotByUserQueue(ticket.userId)
/*const whatsapp = await Whatsapp.findByPk(ticket.whatsappId);
if (whatsapp && whatsapp.status != 'CONNECTED') {
let whatsapps = await wbotByUserQueue(ticket.userId)
if (whatsapps.length > 0) {
@ -98,40 +154,41 @@ const SendWhatsAppMessage = async ({
}
const wbot = await GetTicketWbot(ticket);
*/
console.log('2 --------> send from whatsapp ticket.whatsappId: ', ticket.whatsappId)
try {
const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, body, { quotedMessageId: quotedMsgSerializedId, linkPreview: false });
sendWhatsAppMessageSocket(ticket, body, quotedMsgSerializedId);
await ticket.update({ lastMessage: body });
await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
// const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, body, { quotedMessageId: quotedMsgSerializedId, linkPreview: false });
// await ticket.update({ lastMessage: body });
// await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
// return sentMessage;
console.timeEnd(timetaken)
return sentMessage;
} catch (err) {
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
await _restore(whatsapp, 'auto_send_message')
const sentMessage = await sendMessageMultiSession(ticket, body, quotedMsgSerializedId)
if (sentMessage.length > 0) {
await ticket.update({ lastMessage: body });
await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
return sentMessage;
}
// const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
throw new AppError("ERR_SENDING_WAPP_MSG");
}
};
export default SendWhatsAppMessage;

View File

@ -1,11 +1,114 @@
import path from "path";
import autoRestore from "../../helpers/AutoRestore";
import { removeDir } from "../../helpers/DeleteDirectory";
import { delRestoreControllFile, getRestoreControll } from "../../helpers/RestoreControll";
// import { insertOrUpeateWhatsCache, loadWhatsappCache, searchWhatsappCache } from "../../helpers/WhatsCache";
import { getIO } from "../../libs/socket";
import Whatsapp from "../../models/Whatsapp";
import ListWhatsAppsService from "../WhatsappService/ListWhatsAppsService";
import { StartWhatsAppSession } from "./StartWhatsAppSession";
const fs = require('fs')
import "../../helpers/SchedulingNotifySendMessage"
import "../../helpers/WhoIsOnlineMonitor"
import { cacheSize, flushCache, loadTicketsCache } from "../../helpers/TicketCache";
import { loadContactsCache } from "../../helpers/ContactsCache";
import { loadSchedulesCache } from "../../helpers/SchedulingNotifyCache";
import { createSessionDir } from "../../helpers/CreateSessionDir";
import openSocket from "socket.io-client";
let counter = 0
export const StartAllWhatsAppsSessions = async (): Promise<void> => {
const whatsapps = await ListWhatsAppsService();
if (whatsapps.length > 0) {
whatsapps.forEach(whatsapp => {
StartWhatsAppSession(whatsapp);
});
const cacheLength = await cacheSize()
console.log('cacheSize: ', cacheLength)
if (cacheLength == 0) {
console.log('Loading from cache...')
await flushCache()
await loadContactsCache()
await loadTicketsCache()
}
await loadSchedulesCache()
// await loadWhatsappCache()
createSessionDir()
delRestoreControllFile()
const whatsapps = await ListWhatsAppsService();
if (whatsapps.length > 0) {
whatsapps.forEach(async whatsapp => {
// StartWhatsAppSession(whatsapp);
const sourcePath = path.join(process.cwd(), `.wwebjs_auth/`, `session-bd_${whatsapp.id}`)
if (fs.existsSync(sourcePath)) {
await removeDir(sourcePath)
console.log('Directory deleted on start process: ', sourcePath)
}
else {
console.log('Directory not found to delete on start process: ', sourcePath)
}
await whatsapp.update({ status: "RESTORING" });
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
// status: "RESTORING",
// })
const io = getIO();
io.emit("whatsappSession", {
action: "update",
session: whatsapp
});
console.log('1 counter: ', counter)
setTimeout(async () => {
let whats: any = await Whatsapp.findOne({ where: { id: whatsapp.id } });
if (whats && whats.status !== 'CONNECTED') {
let lstRestore = getRestoreControll()
console.log('---------> lstRestore: ', lstRestore)
if (Object.keys(lstRestore.filter((e: any) => +e.id == +whatsapp.id)).length) {
console.log(` EXECUTING RESTORING ON whatsappId: ${whatsapp.id}`)
} else {
await autoRestore(whatsapp.id,)
}
}
}, counter)
counter += 57000
});
}
};

View File

@ -4,7 +4,7 @@ import { wbotMessageListener } from "./wbotMessageListener";
import { getIO } from "../../libs/socket";
import wbotMonitor from "./wbotMonitor";
import { logger } from "../../utils/logger";
import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
// import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
import { getRestoreControll, setRestoreControll, shifRestoreControll } from "../../helpers/RestoreControll";
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
@ -18,92 +18,15 @@ import { splitDateTime } from "../../helpers/SplitDateTime";
import { format } from "date-fns";
import ptBR from 'date-fns/locale/pt-BR';
let lstAutoRestore: any = []
import path from "path";
const fs = require('fs')
export const StartWhatsAppSession = async (whatsapp: Whatsapp, backupSession: boolean = false): Promise<void> => {
return
await whatsapp.update({ status: "OPENING" });
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
status: "OPENING",
})
try {
let lstRestore: any = getRestoreControll()
if (Object.keys(lstRestore.filter((e: any) => +e.id == +whatsapp.id)).length) {
console.log('Restore executed by human whatasappId: ', whatsapp.id)
}
else {
lstAutoRestore.push({ 'whatsappId': +whatsapp.id })
setTimeout(async () => {
lstRestore = getRestoreControll()
let count = lstAutoRestore.length
for (let i = 0; i < count; i++) {
let autoR = lstAutoRestore.shift()
console.log('----------------> autoR: ', autoR)
if (autoR && autoR.whatsappId) {
if (Object.keys(lstRestore.filter((e: any) => +e.id == +autoR.whatsappId)).length) {
console.log(' EXECUTING RESTORING autoR: ', autoR)
continue
}
const _whatsapp = await Whatsapp.findOne({ where: { id: autoR.whatsappId } });
console.log('----------------> autoR exec after 120 seconds: ', autoR)
let whatsappStatus = ["CONFLICT",
"DEPRECATED_VERSION",
"OPENING",
"PAIRING",
"PROXYBLOCK",
"SMB_TOS_BLOCK",
"TIMEOUT",
"TOS_BLOCK",
"UNLAUNCHED",
"UNPAIRED",
"UNPAIRED_IDLE"]
if (_whatsapp?.status) {
if (whatsappStatus.includes(_whatsapp.status)) {
await autoRestore(autoR.whatsappId, 'auto_monit')
}
}
}
}
}, 120000);
}
} catch (error) {
console.log('There was an error on try execute AUTO-RESTORE: ', error)
}
const io = getIO();
io.emit("whatsappSession", {
action: "update",

View File

@ -67,11 +67,12 @@ import ShowContactCustomFieldService from "../ContactServices/ShowContactCustomF
import { insertMessageContactCache, getLastId } from '../../helpers/LastMessageIdByContactCache'
import autoRestore from "../../helpers/AutoRestore";
import { _restore } from "../../helpers/RestoreControll";
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
import { getWhatsappIds, setWhatsappId } from "../../helpers/WhatsappIdMultiSessionControl";
let lst: any[] = []
let clear_lst: any
var lst: any[] = getWhatsappIds()
interface Session extends Client {
@ -80,8 +81,9 @@ interface Session extends Client {
const writeFileAsync = promisify(writeFile);
const verifyContact = async (msgContact: WbotContact): Promise<Contact> => {
const profilePicUrl = await msgContact.getProfilePicUrl();
const verifyContact = async (msgContact: any): Promise<Contact> => {
// const profilePicUrl = await msgContact.getProfilePicUrl();
const profilePicUrl = msgContact.getProfilePicUrl;
const contactData = {
name: msgContact.name || msgContact.pushname || msgContact.id.user,
@ -96,11 +98,14 @@ const verifyContact = async (msgContact: WbotContact): Promise<Contact> => {
};
const verifyQuotedMessage = async (
msg: WbotMessage
msg: any,
_quotedMsg?: any
): Promise<Message | null> => {
if (!msg.hasQuotedMsg) return null;
const wbotQuotedMsg = await msg.getQuotedMessage();
// const wbotQuotedMsg = await msg.getQuotedMessage();
const wbotQuotedMsg = _quotedMsg;
const quotedMsg = await Message.findOne({
where: { id: wbotQuotedMsg.id.id }
@ -112,19 +117,27 @@ const verifyQuotedMessage = async (
};
const verifyMediaMessage = async (
msg: WbotMessage,
msg: any,
ticket: Ticket,
contact: Contact
): Promise<Message> => {
const quotedMsg = await verifyQuotedMessage(msg);
contact: Contact,
media: any,
quotedMsg?: any,
): Promise<Message | any> => {
// const quotedMsg = await verifyQuotedMessage(msg);
const media = await msg.downloadMedia();
// const media = await msg.downloadMedia();
if (!media) {
throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
}
console.log('MEDIA.FILENAME: ', media.fileName, ' | msg.fromMe: ', msg.fromMe)
if (!media.filename) {
console.log('No file name -----------------------------------------')
const ext = media.mimetype.split("/")[1].split(";")[0];
media.filename = `${new Date().getTime()}.${ext}`;
}
@ -136,11 +149,15 @@ const verifyMediaMessage = async (
// "base64"
// );
console.log('FROM wbotMessageListener.ts media.filename: ', media.filename)
await writeFileAsync(
join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
media.data,
"base64"
);
} catch (err) {
Sentry.captureException(err);
logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
@ -155,7 +172,8 @@ const verifyMediaMessage = async (
read: msg.fromMe,
mediaUrl: media.filename,
mediaType: media.mimetype.split("/")[0],
quotedMsgId: quotedMsg?.id
quotedMsgId: quotedMsg
// quotedMsgId: quotedMsg?.id
};
await ticket.update({ lastMessage: msg.body || media.filename });
@ -167,11 +185,16 @@ const verifyMediaMessage = async (
const verifyMessage = async (
msg: WbotMessage,
ticket: Ticket,
contact: Contact
contact: Contact,
quotedMsg?: any,
) => {
const quotedMsg = await verifyQuotedMessage(msg);
// const quotedMsg = await verifyQuotedMessage(msg);
// const quotedMsg = await verifyQuotedMessage(msg);
const messageData = {
id: msg.id.id,
ticketId: ticket.id,
@ -180,16 +203,13 @@ const verifyMessage = async (
fromMe: msg.fromMe,
mediaType: msg.type,
read: msg.fromMe,
quotedMsgId: quotedMsg?.id
quotedMsgId: quotedMsg
// quotedMsgId: quotedMsg?.id
};
await ticket.update({ lastMessage: msg.body });
// TEST DEL
// await updateTicketCacheByTicketId(ticket.id, { lastMessage: msg.body, updatedAt: new Date(ticket.updatedAt).toISOString() })
//
await CreateMessageService({ messageData });
};
@ -664,9 +684,11 @@ const verifyQueue = async (
body = `\u200e${choosenQueue.greetingMessage}`;
}
const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
// await verifyMessage(sentMessage, ticket, contact);
sendWhatsAppMessageSocket(ticket, body)
await verifyMessage(sentMessage, ticket, contact);
}
else {
@ -690,8 +712,13 @@ const verifyQueue = async (
const debouncedSentMessage = debounce(
async () => {
const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
verifyMessage(sentMessage, ticket, contact);
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
// verifyMessage(sentMessage, ticket, contact);
sendWhatsAppMessageSocket(ticket, body)
},
3000,
ticket.id
@ -834,60 +861,57 @@ const botSendMessage = (ticket: Ticket, contact: Contact, wbot: Session, msg: st
const _clear_lst = () => {
if (lst.length <= 200) return
console.log('THE lst.length: ', lst.length)
if (lst.length <= 199) return
const chunk: any = Math.floor((lst.length / 2))
lst = lst.slice(chunk, chunk + lst.length);
let whatsappIdsSplited = lst.map((e)=>`${e.id}`).toString()
setWhatsappId(whatsappIdsSplited, true)
}
const handleMessage = async (
msg: any,
wbot: any
): Promise<void> => {
const clearMultiSessionWhatsappMessageId = () => {
try {
clearInterval(clear_lst);
if (!msg.fromMe) {
_clear_lst()
} catch (error) {
console.log('error on clear lst whatsapp id message: ', error)
}
finally {
clear_lst = setInterval(_clear_lst, 10000);
let index = lst.findIndex((x: any) => x.id == msg.id.id)
console.log('INDEX: ', index)
if (index == -1) {
// console.log('-----------------> LST: ', lst)
lst.push({ id: msg.id.id })
setWhatsappId(msg.id.id)
}
else {
console.log('IGNORED ID: ', msg.id.id)
return
}
// console.log('LIST OF ID MESSAGE lst: ', lst)
console.log('PASSOU.................................FROM: ', msg.from.split("@")[0], ' | ID: ', msg.id.id)
}
}
clear_lst = setInterval(clearMultiSessionWhatsappMessageId, 10000);
const handleMessage = async (
msg: WbotMessage,
wbot: Session
): Promise<void> => {
// TEST DEL MULTI SESSION
let index = lst.findIndex((x: any) => x.id == msg.id.id)
console.log('INDEX: ', index)
if (index == -1) {
lst.push({ id: msg.id.id })
}
else {
console.log('IGNORED ID: ', msg.id.id)
return
}
// console.log('LIST OF ID MESSAGE lst: ', lst)
console.log('PASSOU.................................FROM: ', msg.from.split("@")[0], ' | ID: ', msg.id.id)
if (!isValidMsg(msg)) {
@ -895,25 +919,38 @@ const handleMessage = async (
}
try {
let msgContact: WbotContact;
let groupContact: Contact | undefined;
let msgContact: any = wbot.msgContact
// let groupContact: Contact | undefined;
if (msg.fromMe) {
// console.log('FROM ME: ', msg.fromMe, ' | /\u200e/.test(msg.body[0]: ', (/\u200e/.test(msg.body[0])))
// messages sent automatically by wbot have a special character in front of it
// if so, this message was already been stored in database;
if (/\u200e/.test(msg.body[0])) return;
// if (/\u200e/.test(msg.body[0])) return;
// console.log('PASSOU 1')
// media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
// in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard") return;
msgContact = await wbot.getContactById(msg.to);
// console.log('PASSOU 2')
// msgContact = await wbot.getContactById(msg.to);
// console.log('1 --------------> msgContat: ', JSON.parse(JSON.stringify(msgContact)))
// console.log(' # msg.type: ', msg.type )
} else {
msgContact = await msg.getContact();
// msgContact = await msg.getContact();
// console.log('2 --------------> msgContat: ', JSON.parse(JSON.stringify(msgContact)))
//
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
Parcial msg and msgContact info:
msgContact.name: ${msgContact.name}
@ -928,26 +965,35 @@ const handleMessage = async (
}
const chat = await msg.getChat();
// const chat = await msg.getChat();
const chat = wbot.chat
// console.log('----------> chat: ', JSON.parse(JSON.stringify(chat)))
// if (chat.isGroup) {
// let msgGroupContact;
// if (msg.fromMe) {
// msgGroupContact = await wbot.getContactById(msg.to);
// } else {
// msgGroupContact = await wbot.getContactById(msg.from);
// }
// groupContact = await verifyContact(msgGroupContact);
// }
if (chat.isGroup) {
let msgGroupContact;
if (msg.fromMe) {
msgGroupContact = await wbot.getContactById(msg.to);
} else {
msgGroupContact = await wbot.getContactById(msg.from);
}
groupContact = await verifyContact(msgGroupContact);
}
const whatsapp = await ShowWhatsAppService(wbot.id!);
// const whatsapp = await ShowWhatsAppService(46);
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
const contact = await verifyContact(msgContact);
// console.log('----------> contact: ', JSON.parse(JSON.stringify(contact)))
if (unreadMessages === 0 && whatsapp.farewellMessage && whatsapp.farewellMessage === msg.body) return;
@ -956,7 +1002,7 @@ const handleMessage = async (
contact,
wbot.id!,
unreadMessages,
groupContact
// groupContact
);
//
@ -965,20 +1011,22 @@ const handleMessage = async (
// Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen
if (wbot.id != ticket.whatsappId) {
// console.log('PARA RESPONDER PELO MEMOS WHATSAPP wbot.id: ', wbot.id, ' | wbot.status: ', wbot.status)
// console.log('WHATSAPP STATUS ticket.whatsappId: ', ticket.whatsappId)
await ticket.update({ whatsappId: wbot.id });
}
//
if (msg.hasMedia) {
await verifyMediaMessage(msg, ticket, contact);
await verifyMediaMessage(msg, ticket, contact, wbot.media, wbot.quotedMsg);
} else {
await verifyMessage(msg, ticket, contact);
// console.log('>>>>>>> msg.fromMe: ',msg.fromMe )
await verifyMessage(msg, ticket, contact, wbot.quotedMsg);
}
//setTimeout(()=>verifyQueue(wbot, msg, ticket, contact), 3000);
if (
!ticket.queue &&
@ -1055,7 +1103,7 @@ const handleMessage = async (
// if (msg.body.trim() == 'broken') {
// throw new Error('Throw makes it go boom!')
// }
//
} catch (err) {
Sentry.captureException(err);
@ -1093,13 +1141,13 @@ const handleMessage = async (
}
};
const handleMsgAck = async (msg: WbotMessage, ack: MessageAck) => {
const handleMsgAck = async (msg_id: any, ack: any) => {
await new Promise(r => setTimeout(r, 500));
const io = getIO();
try {
const messageToUpdate = await Message.findByPk(msg.id.id, {
const messageToUpdate = await Message.findByPk(msg_id, {
include: [
"contact",
{
@ -1114,6 +1162,8 @@ const handleMsgAck = async (msg: WbotMessage, ack: MessageAck) => {
}
await messageToUpdate.update({ ack });
// console.log('ACK messageToUpdate: ', JSON.parse(JSON.stringify(messageToUpdate)))
io.to(messageToUpdate.ticketId.toString()).emit("appMessage", {
action: "update",
message: messageToUpdate
@ -1126,6 +1176,7 @@ const handleMsgAck = async (msg: WbotMessage, ack: MessageAck) => {
};
const wbotMessageListener = (wbot: Session): void => {
wbot.on("message_create", async msg => {
handleMessage(msg, wbot);
});
@ -1139,4 +1190,4 @@ const wbotMessageListener = (wbot: Session): void => {
});
};
export { wbotMessageListener, handleMessage };
export { wbotMessageListener, handleMessage, handleMsgAck, lst };

View File

@ -1,12 +1,35 @@
import * as Sentry from "@sentry/node";
import { Client } from "whatsapp-web.js";
import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
// import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
import { getIO } from "../../libs/socket";
import Whatsapp from "../../models/Whatsapp";
import { logger } from "../../utils/logger";
import { StartWhatsAppSession } from "./StartWhatsAppSession";
import { getRestoreControll, setRestoreControll, shifRestoreControll } from "../../helpers/RestoreControll";
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
import dir from 'path';
import autoRestore from "../../helpers/AutoRestore";
import { creationTime } from "../../helpers/CreationTime";
import { splitDateTime } from "../../helpers/SplitDateTime";
import { format } from "date-fns";
import ptBR from 'date-fns/locale/pt-BR';
import path from "path";
import { restoreMonit } from "../../helpers/RestoreMonit";
const fs = require('fs')
let lstAutoRestore: any = []
interface Session extends Client {
id?: number;
}
@ -22,12 +45,12 @@ const wbotMonitor = async (
wbot.on("change_state", async newState => {
logger.info(`Monitor session: ${sessionName}, ${newState}`);
// console.log('>>>>>>>>>>>>>> change_state wbotMonitor.ts MOBILE NUMBER: ', wbot.info["wid"]["user"])
console.log('>>>>>>>>>>>>>> change_state wbotMonitor.ts MOBILE NUMBER: ', wbot.info["wid"]["user"])
try {
await whatsapp.update({ status: newState });
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: newState })
} catch (err) {
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: newState })
} catch (err: any) {
Sentry.captureException(err);
logger.error(err);
}
@ -36,6 +59,9 @@ const wbotMonitor = async (
action: "update",
session: whatsapp
});
restoreMonit(whatsapp.id)
});
wbot.on("change_battery", async batteryInfo => {
@ -46,7 +72,7 @@ const wbotMonitor = async (
try {
await whatsapp.update({ battery, plugged });
} catch (err) {
} catch (err: any) {
Sentry.captureException(err);
logger.error(err);
}
@ -62,8 +88,8 @@ const wbotMonitor = async (
try {
await whatsapp.update({ status: "OPENING", session: "" });
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: "OPENING", session: "" })
} catch (err) {
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, { status: "OPENING", session: "" })
} catch (err: any) {
Sentry.captureException(err);
logger.error(err);
}
@ -75,7 +101,7 @@ const wbotMonitor = async (
setTimeout(() => StartWhatsAppSession(whatsapp), 2000);
});
} catch (err) {
} catch (err: any) {
Sentry.captureException(err);
logger.error(err);
}

View File

@ -6,6 +6,8 @@ import AssociateWhatsappQueue from "./AssociateWhatsappQueue";
interface Request {
name: string;
url: string;
urlApi: string;
queueIds?: number[];
greetingMessage?: string;
farewellMessage?: string;
@ -20,11 +22,13 @@ interface Response {
const CreateWhatsAppService = async ({
name,
url,
urlApi,
status = "OPENING",
queueIds = [],
greetingMessage,
farewellMessage,
isDefault = false
isDefault = false,
}: Request): Promise<Response> => {
const schema = Yup.object().shape({
name: Yup.string()
@ -41,12 +45,13 @@ const CreateWhatsAppService = async ({
return !nameExists;
}
),
isDefault: Yup.boolean().required()
isDefault: Yup.boolean().required(),
urlApi: Yup.string().required()
});
try {
await schema.validate({ name, status, isDefault });
} catch (err) {
await schema.validate({ name, status, isDefault, urlApi });
} catch (err: any) {
throw new AppError(err.message);
}
@ -74,6 +79,8 @@ const CreateWhatsAppService = async ({
{
name,
status,
url,
urlApi,
greetingMessage,
farewellMessage,
isDefault

View File

@ -1,26 +1,28 @@
import Whatsapp from "../../models/Whatsapp";
const ListWhatsAppsNumber = async (whatsappId: string | number, status: string): Promise<Whatsapp[]> => {
const ListWhatsAppsNumber = async (whatsappId: string | number, status: string): Promise<Whatsapp[] | any> => {
const whatsapp = await Whatsapp.findOne({
raw: true,
where: { id: whatsappId }
})
// const whatsapp = await Whatsapp.findOne({
// raw: true,
// where: { id: whatsappId }
// })
const whatsapp = await Whatsapp.findByPk(whatsappId, { raw: true })
if (whatsapp) {
const whatsapps = await Whatsapp.findAll({
raw: true,
where: { number: whatsapp.number, status: status },
attributes: ['id', 'number', 'status', 'isDefault']
attributes: ['id', 'number', 'status', 'isDefault', 'url']
});
return whatsapps;
return { whatsapps, whatsapp };
}
return []
return { whatsapps: [], whatsapp: null }
};

View File

@ -14,6 +14,8 @@ const ShowWhatsAppService = async (id: string | number): Promise<Whatsapp> => {
order: [["queues", "id", "ASC"]]
});
// console.log('kkkkkkkkkkkkkkkkkkkk: ', whatsapp)
if (!whatsapp) {
throw new AppError("ERR_NO_WAPP_FOUND", 404);
}

View File

@ -5,7 +5,7 @@ import AppError from "../../errors/AppError";
import Whatsapp from "../../models/Whatsapp";
import ShowWhatsAppService from "./ShowWhatsAppService";
import AssociateWhatsappQueue from "./AssociateWhatsappQueue";
import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
// import { insertOrUpeateWhatsCache } from "../../helpers/WhatsCache";
import { getWbot } from "../../libs/wbot";
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
@ -13,6 +13,8 @@ import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
interface WhatsappData {
name?: string;
url?: string;
urlApi?: string;
status?: string;
session?: string;
isDefault?: boolean;
@ -45,6 +47,8 @@ const UpdateWhatsAppService = async ({
name,
status,
isDefault,
url,
urlApi,
session,
greetingMessage,
farewellMessage,
@ -55,7 +59,7 @@ const UpdateWhatsAppService = async ({
try {
await schema.validate({ name, status, isDefault });
} catch (err) {
} catch (err: any) {
throw new AppError(err.message);
}
@ -88,19 +92,21 @@ const UpdateWhatsAppService = async ({
name,
status,
session,
url,
urlApi,
greetingMessage,
farewellMessage,
isDefault
});
await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
name,
status,
session,
greetingMessage,
farewellMessage,
isDefault
})
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
// name,
// status,
// session,
// greetingMessage,
// farewellMessage,
// isDefault
// })
await AssociateWhatsappQueue(whatsapp, queueIds);

View File

@ -319,6 +319,8 @@ const MessageInput = ({ ticketStatus }) => {
quotedMsg: replyingMessage,
};
try {
// console.log('message: ', message)
await api.post(`/messages/${ticketId}`, message);
} catch (err) {
toastError(err);

View File

@ -364,6 +364,9 @@ const MessagesList = ({ ticketId, isGroup }) => {
socket.on("appMessage", (data) => {
if (data.action === "create") {
console.log('ADD_MESSAGE: ', data.message)
dispatch({ type: "ADD_MESSAGE", payload: data.message });
scrollToBottom();
@ -371,6 +374,8 @@ const MessagesList = ({ ticketId, isGroup }) => {
if (data.action === "update") {
console.log('joinChatBox update: ',data.action)
dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
}
});

Some files were not shown because too many files have changed in this diff Show More