mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-19 04:09:26 +00:00
migrated wbot initialization to typescript
This commit is contained in:
5
backend/src/@types/WAWebJS.d.ts
vendored
Normal file
5
backend/src/@types/WAWebJS.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare namespace WAWebJS {
|
||||
export interface ClientInfo {
|
||||
meuId: number;
|
||||
}
|
||||
}
|
||||
6
backend/src/@types/express.d.ts
vendored
6
backend/src/@types/express.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
declare namespace Express {
|
||||
export interface Request {
|
||||
user: { id: string; profile: string };
|
||||
}
|
||||
export interface Request {
|
||||
user: { id: string; profile: string };
|
||||
}
|
||||
}
|
||||
|
||||
1
backend/src/@types/qrcode-terminal.d.ts
vendored
Normal file
1
backend/src/@types/qrcode-terminal.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module "qrcode-terminal";
|
||||
@@ -1,110 +0,0 @@
|
||||
const qrCode = require("qrcode-terminal");
|
||||
const { Client } = require("whatsapp-web.js");
|
||||
const Whatsapp = require("../models/Whatsapp");
|
||||
const { getIO } = require("../libs/socket");
|
||||
|
||||
let sessions = [];
|
||||
|
||||
module.exports = {
|
||||
initWbot: async whatsapp => {
|
||||
try {
|
||||
const io = getIO();
|
||||
const sessionName = whatsapp.name;
|
||||
let sessionCfg;
|
||||
|
||||
if (whatsapp && whatsapp.session) {
|
||||
sessionCfg = JSON.parse(whatsapp.session);
|
||||
}
|
||||
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsapp.id);
|
||||
if (sessionIndex !== -1) {
|
||||
sessions[sessionIndex].destroy();
|
||||
sessions.splice(sessionIndex, 1);
|
||||
}
|
||||
|
||||
const wbot = new Client({
|
||||
session: sessionCfg,
|
||||
restartOnAuthFail: true
|
||||
});
|
||||
wbot.initialize();
|
||||
|
||||
wbot.on("qr", async qr => {
|
||||
console.log("Session:", sessionName);
|
||||
|
||||
qrCode.generate(qr, { small: true });
|
||||
|
||||
await whatsapp.update({ qrcode: qr, status: "qrcode" });
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
});
|
||||
|
||||
wbot.on("authenticated", async session => {
|
||||
console.log("Session:", sessionName, "AUTHENTICATED");
|
||||
|
||||
await whatsapp.update({
|
||||
session: JSON.stringify(session),
|
||||
status: "authenticated"
|
||||
});
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
});
|
||||
|
||||
wbot.on("auth_failure", async msg => {
|
||||
console.error("Session:", sessionName, "AUTHENTICATION FAILURE", msg);
|
||||
|
||||
await whatsapp.update({ session: "" });
|
||||
});
|
||||
|
||||
wbot.on("ready", async () => {
|
||||
console.log("Session:", sessionName, "READY");
|
||||
|
||||
await whatsapp.update({
|
||||
status: "CONNECTED",
|
||||
qrcode: ""
|
||||
});
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
|
||||
wbot.sendPresenceAvailable();
|
||||
});
|
||||
|
||||
wbot.id = whatsapp.id;
|
||||
sessions.push(wbot);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getWbot: whatsappId => {
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
|
||||
|
||||
if (sessionIndex === -1) {
|
||||
console.log("This Wbot session is not initialized");
|
||||
return null;
|
||||
}
|
||||
return sessions[sessionIndex];
|
||||
},
|
||||
|
||||
removeWbot: whatsappId => {
|
||||
try {
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
|
||||
if (sessionIndex !== -1) {
|
||||
sessions[sessionIndex].destroy();
|
||||
sessions.splice(sessionIndex, 1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
107
backend/src/libs/wbot.ts
Normal file
107
backend/src/libs/wbot.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import qrCode from "qrcode-terminal";
|
||||
import { Client } from "whatsapp-web.js";
|
||||
import { getIO } from "./socket";
|
||||
import Whatsapp from "../models/Whatsapp";
|
||||
|
||||
const sessions: Client[] = [];
|
||||
|
||||
export const initWbot = async (whatsapp: Whatsapp): Promise<void> => {
|
||||
console.log("starting");
|
||||
try {
|
||||
const io = getIO();
|
||||
const sessionName = whatsapp.name;
|
||||
let sessionCfg;
|
||||
|
||||
if (whatsapp && whatsapp.session) {
|
||||
sessionCfg = JSON.parse(whatsapp.session);
|
||||
}
|
||||
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsapp.id);
|
||||
if (sessionIndex !== -1) {
|
||||
sessions[sessionIndex].destroy();
|
||||
sessions.splice(sessionIndex, 1);
|
||||
}
|
||||
|
||||
const wbot = new Client({
|
||||
session: sessionCfg,
|
||||
restartOnAuthFail: true
|
||||
});
|
||||
wbot.initialize();
|
||||
|
||||
wbot.on("qr", async qr => {
|
||||
console.log("Session:", sessionName);
|
||||
|
||||
qrCode.generate(qr, { small: true });
|
||||
|
||||
await whatsapp.update({ qrcode: qr, status: "qrcode" });
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
});
|
||||
|
||||
wbot.on("authenticated", async session => {
|
||||
console.log("Session:", sessionName, "AUTHENTICATED");
|
||||
|
||||
await whatsapp.update({
|
||||
session: JSON.stringify(session),
|
||||
status: "authenticated"
|
||||
});
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
});
|
||||
|
||||
wbot.on("auth_failure", async msg => {
|
||||
console.error("Session:", sessionName, "AUTHENTICATION FAILURE", msg);
|
||||
|
||||
await whatsapp.update({ session: "" });
|
||||
});
|
||||
|
||||
wbot.on("ready", async () => {
|
||||
console.log("Session:", sessionName, "READY");
|
||||
|
||||
await whatsapp.update({
|
||||
status: "CONNECTED",
|
||||
qrcode: ""
|
||||
});
|
||||
|
||||
io.emit("whatsappSession", {
|
||||
action: "update",
|
||||
session: whatsapp
|
||||
});
|
||||
|
||||
wbot.sendPresenceAvailable();
|
||||
});
|
||||
|
||||
wbot.id = whatsapp.id;
|
||||
sessions.push(wbot);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
export const getWbot = (whatsappId: number): Client | null => {
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
|
||||
|
||||
if (sessionIndex === -1) {
|
||||
console.log("This Wbot session is not initialized");
|
||||
return null;
|
||||
}
|
||||
return sessions[sessionIndex];
|
||||
};
|
||||
|
||||
export const removeWbot = (whatsappId: number): void => {
|
||||
try {
|
||||
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);
|
||||
if (sessionIndex !== -1) {
|
||||
sessions[sessionIndex].destroy();
|
||||
sessions.splice(sessionIndex, 1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
@@ -11,13 +11,13 @@ import AppError from "./errors/AppError";
|
||||
import routes from "./routes";
|
||||
import { initIO } from "./libs/socket";
|
||||
import "./database";
|
||||
import { initWbot } from "./libs/wbot";
|
||||
|
||||
// import path from "path";
|
||||
|
||||
// const { initWbot } = require("./libs/wbot");
|
||||
// const wbotMessageListener = require("./services/wbotMessageListener");
|
||||
// const wbotMonitor = require("./services/wbotMonitor");
|
||||
// const Whatsapp = require("./models/Whatsapp");
|
||||
import Whatsapp from "./models/Whatsapp";
|
||||
|
||||
Sentry.init({ dsn: process.env.SENTRY_DSN });
|
||||
|
||||
@@ -62,21 +62,21 @@ io.on("connection", socket => {
|
||||
});
|
||||
});
|
||||
|
||||
// const startWhatsAppSessions = async () => {
|
||||
// const whatsapps = await Whatsapp.findAll();
|
||||
|
||||
// if (whatsapps.length > 0) {
|
||||
// whatsapps.forEach(whatsapp => {
|
||||
// initWbot(whatsapp)
|
||||
// .then(() => {
|
||||
// wbotMessageListener(whatsapp);
|
||||
// wbotMonitor(whatsapp);
|
||||
// })
|
||||
// .catch(err => console.log(err));
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
// startWhatsAppSessions();
|
||||
const startWhatsAppSessions = async () => {
|
||||
const whatsapps = await Whatsapp.findAll();
|
||||
if (whatsapps.length > 0) {
|
||||
whatsapps.forEach(whatsapp => {
|
||||
initWbot(whatsapp)
|
||||
.then(() => {
|
||||
console.log("initialized!!");
|
||||
// wbotMessageListener(whatsapp);
|
||||
// wbotMonitor(whatsapp);
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
});
|
||||
}
|
||||
};
|
||||
startWhatsAppSessions();
|
||||
|
||||
// app.use(Sentry.Handlers.errorHandler());
|
||||
|
||||
|
||||
206
backend/src/services/WbotServices/wbotMessageListener.js
Normal file
206
backend/src/services/WbotServices/wbotMessageListener.js
Normal file
@@ -0,0 +1,206 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { Op } = require("sequelize");
|
||||
const { subHours } = require("date-fns");
|
||||
const Sentry = require("@sentry/node");
|
||||
|
||||
const Contact = require("../models/Contact");
|
||||
const Ticket = require("../models/Ticket");
|
||||
const Message = require("../models/Message");
|
||||
const Whatsapp = require("../models/Whatsapp");
|
||||
|
||||
const { getIO } = require("../libs/socket");
|
||||
const { getWbot, initWbot } = require("../libs/wbot");
|
||||
|
||||
const verifyContact = async (msgContact, profilePicUrl) => {
|
||||
let contact = await Contact.findOne({
|
||||
where: { number: msgContact.number }
|
||||
});
|
||||
|
||||
if (contact) {
|
||||
await contact.update({ profilePicUrl: profilePicUrl });
|
||||
} else {
|
||||
contact = await Contact.create({
|
||||
name: msgContact.pushname || msgContact.number.toString(),
|
||||
number: msgContact.number,
|
||||
profilePicUrl: profilePicUrl
|
||||
});
|
||||
}
|
||||
|
||||
return contact;
|
||||
};
|
||||
|
||||
const verifyTicket = async (contact, whatsappId) => {
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending"]
|
||||
},
|
||||
contactId: contact.id
|
||||
}
|
||||
});
|
||||
|
||||
if (!ticket) {
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
createdAt: { [Op.between]: [subHours(new Date(), 2), new Date()] },
|
||||
contactId: contact.id
|
||||
},
|
||||
order: [["createdAt", "DESC"]]
|
||||
});
|
||||
|
||||
if (ticket) {
|
||||
await ticket.update({ status: "pending", userId: null });
|
||||
}
|
||||
}
|
||||
|
||||
if (!ticket) {
|
||||
ticket = await Ticket.create({
|
||||
contactId: contact.id,
|
||||
status: "pending",
|
||||
whatsappId
|
||||
});
|
||||
}
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
const handlMedia = async (msg, ticket) => {
|
||||
const media = await msg.downloadMedia();
|
||||
let newMessage;
|
||||
console.log("criando midia");
|
||||
if (media) {
|
||||
if (!media.filename) {
|
||||
let ext = media.mimetype.split("/")[1].split(";")[0];
|
||||
media.filename = `${new Date().getTime()}.${ext}`;
|
||||
}
|
||||
|
||||
fs.writeFile(
|
||||
path.join(__dirname, "..", "..", "public", media.filename),
|
||||
media.data,
|
||||
"base64",
|
||||
err => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
|
||||
newMessage = await ticket.createMessage({
|
||||
id: msg.id.id,
|
||||
body: msg.body || media.filename,
|
||||
fromMe: msg.fromMe,
|
||||
mediaUrl: media.filename,
|
||||
mediaType: media.mimetype.split("/")[0]
|
||||
});
|
||||
await ticket.update({ lastMessage: msg.body || media.filename });
|
||||
}
|
||||
|
||||
return newMessage;
|
||||
};
|
||||
|
||||
const handleMessage = async (msg, ticket, contact) => {
|
||||
const io = getIO();
|
||||
let newMessage;
|
||||
|
||||
if (msg.hasMedia) {
|
||||
newMessage = await handlMedia(msg, ticket);
|
||||
} else {
|
||||
newMessage = await ticket.createMessage({
|
||||
id: msg.id.id,
|
||||
body: msg.body,
|
||||
fromMe: msg.fromMe
|
||||
});
|
||||
await ticket.update({ lastMessage: msg.body });
|
||||
}
|
||||
|
||||
const serializedMessage = {
|
||||
...newMessage.dataValues,
|
||||
mediaUrl: `${
|
||||
newMessage.mediaUrl
|
||||
? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${newMessage.mediaUrl}`
|
||||
: ""
|
||||
}`
|
||||
};
|
||||
|
||||
const serializaedTicket = {
|
||||
...ticket.dataValues,
|
||||
contact: contact
|
||||
};
|
||||
|
||||
io.to(ticket.id).to("notification").emit("appMessage", {
|
||||
action: "create",
|
||||
message: serializedMessage,
|
||||
ticket: serializaedTicket,
|
||||
contact: contact
|
||||
});
|
||||
};
|
||||
|
||||
const wbotMessageListener = whatsapp => {
|
||||
const whatsappId = whatsapp.id;
|
||||
const wbot = getWbot(whatsappId);
|
||||
const io = getIO();
|
||||
|
||||
wbot.on("message_create", async msg => {
|
||||
// console.log(msg);
|
||||
|
||||
if (
|
||||
msg.from === "status@broadcast" ||
|
||||
msg.type === "location" ||
|
||||
msg.type === "call_log" ||
|
||||
msg.author != null // Ignore Group Messages
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let msgContact;
|
||||
|
||||
if (msg.fromMe) {
|
||||
msgContact = await wbot.getContactById(msg.to);
|
||||
} else {
|
||||
msgContact = await msg.getContact();
|
||||
}
|
||||
|
||||
const profilePicUrl = await msgContact.getProfilePicUrl();
|
||||
const contact = await verifyContact(msgContact, profilePicUrl);
|
||||
const ticket = await verifyTicket(contact, whatsappId);
|
||||
|
||||
//return if message was already created by messageController
|
||||
if (msg.fromMe) {
|
||||
const alreadyExists = await Message.findOne({
|
||||
where: { id: msg.id.id }
|
||||
});
|
||||
|
||||
if (alreadyExists) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await handleMessage(msg, ticket, contact);
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
wbot.on("message_ack", async (msg, ack) => {
|
||||
try {
|
||||
const messageToUpdate = await Message.findOne({
|
||||
where: { id: msg.id.id }
|
||||
});
|
||||
if (!messageToUpdate) {
|
||||
return;
|
||||
}
|
||||
await messageToUpdate.update({ ack: ack });
|
||||
|
||||
io.to(messageToUpdate.ticketId).emit("appMessage", {
|
||||
action: "update",
|
||||
message: messageToUpdate
|
||||
});
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = wbotMessageListener;
|
||||
@@ -1,206 +0,0 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { Op } = require("sequelize");
|
||||
const { subHours } = require("date-fns");
|
||||
const Sentry = require("@sentry/node");
|
||||
|
||||
const Contact = require("../models/Contact");
|
||||
const Ticket = require("../models/Ticket");
|
||||
const Message = require("../models/Message");
|
||||
const Whatsapp = require("../models/Whatsapp");
|
||||
|
||||
const { getIO } = require("../libs/socket");
|
||||
const { getWbot, initWbot } = require("../libs/wbot");
|
||||
|
||||
const verifyContact = async (msgContact, profilePicUrl) => {
|
||||
let contact = await Contact.findOne({
|
||||
where: { number: msgContact.number },
|
||||
});
|
||||
|
||||
if (contact) {
|
||||
await contact.update({ profilePicUrl: profilePicUrl });
|
||||
} else {
|
||||
contact = await Contact.create({
|
||||
name: msgContact.pushname || msgContact.number.toString(),
|
||||
number: msgContact.number,
|
||||
profilePicUrl: profilePicUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return contact;
|
||||
};
|
||||
|
||||
const verifyTicket = async (contact, whatsappId) => {
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending"],
|
||||
},
|
||||
contactId: contact.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!ticket) {
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
createdAt: { [Op.between]: [subHours(new Date(), 2), new Date()] },
|
||||
contactId: contact.id,
|
||||
},
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
|
||||
if (ticket) {
|
||||
await ticket.update({ status: "pending", userId: null });
|
||||
}
|
||||
}
|
||||
|
||||
if (!ticket) {
|
||||
ticket = await Ticket.create({
|
||||
contactId: contact.id,
|
||||
status: "pending",
|
||||
whatsappId,
|
||||
});
|
||||
}
|
||||
|
||||
return ticket;
|
||||
};
|
||||
|
||||
const handlMedia = async (msg, ticket) => {
|
||||
const media = await msg.downloadMedia();
|
||||
let newMessage;
|
||||
console.log("criando midia");
|
||||
if (media) {
|
||||
if (!media.filename) {
|
||||
let ext = media.mimetype.split("/")[1].split(";")[0];
|
||||
media.filename = `${new Date().getTime()}.${ext}`;
|
||||
}
|
||||
|
||||
fs.writeFile(
|
||||
path.join(__dirname, "..", "..", "public", media.filename),
|
||||
media.data,
|
||||
"base64",
|
||||
err => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
|
||||
newMessage = await ticket.createMessage({
|
||||
id: msg.id.id,
|
||||
body: msg.body || media.filename,
|
||||
fromMe: msg.fromMe,
|
||||
mediaUrl: media.filename,
|
||||
mediaType: media.mimetype.split("/")[0],
|
||||
});
|
||||
await ticket.update({ lastMessage: msg.body || media.filename });
|
||||
}
|
||||
|
||||
return newMessage;
|
||||
};
|
||||
|
||||
const handleMessage = async (msg, ticket, contact) => {
|
||||
const io = getIO();
|
||||
let newMessage;
|
||||
|
||||
if (msg.hasMedia) {
|
||||
newMessage = await handlMedia(msg, ticket);
|
||||
} else {
|
||||
newMessage = await ticket.createMessage({
|
||||
id: msg.id.id,
|
||||
body: msg.body,
|
||||
fromMe: msg.fromMe,
|
||||
});
|
||||
await ticket.update({ lastMessage: msg.body });
|
||||
}
|
||||
|
||||
const serializedMessage = {
|
||||
...newMessage.dataValues,
|
||||
mediaUrl: `${
|
||||
newMessage.mediaUrl
|
||||
? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${newMessage.mediaUrl}`
|
||||
: ""
|
||||
}`,
|
||||
};
|
||||
|
||||
const serializaedTicket = {
|
||||
...ticket.dataValues,
|
||||
contact: contact,
|
||||
};
|
||||
|
||||
io.to(ticket.id).to("notification").emit("appMessage", {
|
||||
action: "create",
|
||||
message: serializedMessage,
|
||||
ticket: serializaedTicket,
|
||||
contact: contact,
|
||||
});
|
||||
};
|
||||
|
||||
const wbotMessageListener = whatsapp => {
|
||||
const whatsappId = whatsapp.id;
|
||||
const wbot = getWbot(whatsappId);
|
||||
const io = getIO();
|
||||
|
||||
wbot.on("message_create", async msg => {
|
||||
// console.log(msg);
|
||||
|
||||
if (
|
||||
msg.from === "status@broadcast" ||
|
||||
msg.type === "location" ||
|
||||
msg.type === "call_log" ||
|
||||
msg.author != null // Ignore Group Messages
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let msgContact;
|
||||
|
||||
if (msg.fromMe) {
|
||||
msgContact = await wbot.getContactById(msg.to);
|
||||
} else {
|
||||
msgContact = await msg.getContact();
|
||||
}
|
||||
|
||||
const profilePicUrl = await msgContact.getProfilePicUrl();
|
||||
const contact = await verifyContact(msgContact, profilePicUrl);
|
||||
const ticket = await verifyTicket(contact, whatsappId);
|
||||
|
||||
//return if message was already created by messageController
|
||||
if (msg.fromMe) {
|
||||
const alreadyExists = await Message.findOne({
|
||||
where: { id: msg.id.id },
|
||||
});
|
||||
|
||||
if (alreadyExists) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await handleMessage(msg, ticket, contact);
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
wbot.on("message_ack", async (msg, ack) => {
|
||||
try {
|
||||
const messageToUpdate = await Message.findOne({
|
||||
where: { id: msg.id.id },
|
||||
});
|
||||
if (!messageToUpdate) {
|
||||
return;
|
||||
}
|
||||
await messageToUpdate.update({ ack: ack });
|
||||
|
||||
io.to(messageToUpdate.ticketId).emit("appMessage", {
|
||||
action: "update",
|
||||
message: messageToUpdate,
|
||||
});
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = wbotMessageListener;
|
||||
Reference in New Issue
Block a user