mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-16 12:12:55 -06:00
Enhance settings and integrate Baileys controller for WhatsApp functionality
- Added `wavoipToken` field to `Setting` model in both MySQL and PostgreSQL schemas. - Updated `package.json` and `package-lock.json` to include `mime-types` and `socket.io-client` dependencies. - Introduced `BaileysController` and `BaileysRouter` for handling WhatsApp interactions. - Refactored media type handling to use `mime-types` instead of `mime` across various services. - Updated DTOs and validation schemas to accommodate the new `wavoipToken` field. - Implemented voice call functionalities using the Wavoip service in the Baileys integration. - Enhanced event handling in the WebSocket controller to support new features.
This commit is contained in:
parent
616ae0a7eb
commit
540467293c
95
package-lock.json
generated
95
package-lock.json
generated
@ -39,6 +39,7 @@
|
|||||||
"long": "^5.2.3",
|
"long": "^5.2.3",
|
||||||
"mediainfo.js": "^0.3.4",
|
"mediainfo.js": "^0.3.4",
|
||||||
"mime": "^4.0.0",
|
"mime": "^4.0.0",
|
||||||
|
"mime-types": "^2.1.35",
|
||||||
"minio": "^8.0.3",
|
"minio": "^8.0.3",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
@ -53,6 +54,7 @@
|
|||||||
"redis": "^4.7.0",
|
"redis": "^4.7.0",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
"socket.io-client": "^4.8.1",
|
||||||
"tsup": "^8.3.5"
|
"tsup": "^8.3.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -61,6 +63,7 @@
|
|||||||
"@types/express": "^4.17.18",
|
"@types/express": "^4.17.18",
|
||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"@types/mime": "^4.0.0",
|
"@types/mime": "^4.0.0",
|
||||||
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
@ -3819,6 +3822,12 @@
|
|||||||
"mime": "*"
|
"mime": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/mime-types": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/mysql": {
|
"node_modules/@types/mysql": {
|
||||||
"version": "2.15.26",
|
"version": "2.15.26",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz",
|
||||||
@ -6089,6 +6098,54 @@
|
|||||||
"node": ">=10.2.0"
|
"node": ">=10.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/engine.io-client": {
|
||||||
|
"version": "6.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.2.tgz",
|
||||||
|
"integrity": "sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.17.1",
|
||||||
|
"xmlhttprequest-ssl": "~2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-client/node_modules/debug": {
|
||||||
|
"version": "4.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-client/node_modules/ws": {
|
||||||
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/engine.io-parser": {
|
"node_modules/engine.io-parser": {
|
||||||
"version": "5.2.3",
|
"version": "5.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||||
@ -10728,6 +10785,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socket.io-client": {
|
||||||
|
"version": "4.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||||
|
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.6.1",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socket.io-client/node_modules/debug": {
|
||||||
|
"version": "4.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/socket.io-parser": {
|
"node_modules/socket.io-parser": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
@ -12102,6 +12189,14 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xtend": {
|
"node_modules/xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
"long": "^5.2.3",
|
"long": "^5.2.3",
|
||||||
"mediainfo.js": "^0.3.4",
|
"mediainfo.js": "^0.3.4",
|
||||||
"mime": "^4.0.0",
|
"mime": "^4.0.0",
|
||||||
|
"mime-types": "^2.1.35",
|
||||||
"minio": "^8.0.3",
|
"minio": "^8.0.3",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
@ -93,6 +94,7 @@
|
|||||||
"redis": "^4.7.0",
|
"redis": "^4.7.0",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
"socket.io-client": "^4.8.1",
|
||||||
"tsup": "^8.3.5"
|
"tsup": "^8.3.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -101,6 +103,7 @@
|
|||||||
"@types/express": "^4.17.18",
|
"@types/express": "^4.17.18",
|
||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"@types/mime": "^4.0.0",
|
"@types/mime": "^4.0.0",
|
||||||
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
|
@ -264,6 +264,7 @@ model Setting {
|
|||||||
readMessages Boolean @default(false)
|
readMessages Boolean @default(false)
|
||||||
readStatus Boolean @default(false)
|
readStatus Boolean @default(false)
|
||||||
syncFullHistory Boolean @default(false)
|
syncFullHistory Boolean @default(false)
|
||||||
|
wavoipToken String? @db.VarChar(100)
|
||||||
createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp
|
createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp
|
||||||
updatedAt DateTime @updatedAt @db.Timestamp
|
updatedAt DateTime @updatedAt @db.Timestamp
|
||||||
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Chat` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Setting" ADD COLUMN "wavoipToken" VARCHAR(100);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Chat_remoteJid_instanceId_key" ON "Chat"("remoteJid", "instanceId");
|
@ -265,6 +265,7 @@ model Setting {
|
|||||||
readMessages Boolean @default(false) @db.Boolean
|
readMessages Boolean @default(false) @db.Boolean
|
||||||
readStatus Boolean @default(false) @db.Boolean
|
readStatus Boolean @default(false) @db.Boolean
|
||||||
syncFullHistory Boolean @default(false) @db.Boolean
|
syncFullHistory Boolean @default(false) @db.Boolean
|
||||||
|
wavoipToken String? @db.VarChar(100)
|
||||||
createdAt DateTime? @default(now()) @db.Timestamp
|
createdAt DateTime? @default(now()) @db.Timestamp
|
||||||
updatedAt DateTime @updatedAt @db.Timestamp
|
updatedAt DateTime @updatedAt @db.Timestamp
|
||||||
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
||||||
|
@ -119,6 +119,7 @@ export class InstanceController {
|
|||||||
readMessages: instanceData.readMessages === true,
|
readMessages: instanceData.readMessages === true,
|
||||||
readStatus: instanceData.readStatus === true,
|
readStatus: instanceData.readStatus === true,
|
||||||
syncFullHistory: instanceData.syncFullHistory === true,
|
syncFullHistory: instanceData.syncFullHistory === true,
|
||||||
|
wavoipToken: instanceData.wavoipToken || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.settingsService.create(instance, settings);
|
await this.settingsService.create(instance, settings);
|
||||||
|
@ -19,6 +19,7 @@ export class InstanceDto extends IntegrationDto {
|
|||||||
readMessages?: boolean;
|
readMessages?: boolean;
|
||||||
readStatus?: boolean;
|
readStatus?: boolean;
|
||||||
syncFullHistory?: boolean;
|
syncFullHistory?: boolean;
|
||||||
|
wavoipToken?: string;
|
||||||
// proxy
|
// proxy
|
||||||
proxyHost?: string;
|
proxyHost?: string;
|
||||||
proxyPort?: string;
|
proxyPort?: string;
|
||||||
|
@ -6,4 +6,5 @@ export class SettingsDto {
|
|||||||
readMessages?: boolean;
|
readMessages?: boolean;
|
||||||
readStatus?: boolean;
|
readStatus?: boolean;
|
||||||
syncFullHistory?: boolean;
|
syncFullHistory?: boolean;
|
||||||
|
wavoipToken?: string;
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,16 @@ import { Router } from 'express';
|
|||||||
|
|
||||||
import { EvolutionRouter } from './evolution/evolution.router';
|
import { EvolutionRouter } from './evolution/evolution.router';
|
||||||
import { MetaRouter } from './meta/meta.router';
|
import { MetaRouter } from './meta/meta.router';
|
||||||
|
import { BaileysRouter } from './whatsapp/baileys.router';
|
||||||
|
|
||||||
export class ChannelRouter {
|
export class ChannelRouter {
|
||||||
public readonly router: Router;
|
public readonly router: Router;
|
||||||
|
|
||||||
constructor(configService: any) {
|
constructor(configService: any, ...guards: any[]) {
|
||||||
this.router = Router();
|
this.router = Router();
|
||||||
|
|
||||||
this.router.use('/', new EvolutionRouter(configService).router);
|
this.router.use('/', new EvolutionRouter(configService).router);
|
||||||
this.router.use('/', new MetaRouter(configService).router);
|
this.router.use('/', new MetaRouter(configService).router);
|
||||||
|
this.router.use('/baileys', new BaileysRouter(...guards).router);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { BadRequestException, InternalServerErrorException } from '@exceptions';
|
|||||||
import { status } from '@utils/renderStatus';
|
import { status } from '@utils/renderStatus';
|
||||||
import { isURL } from 'class-validator';
|
import { isURL } from 'class-validator';
|
||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import mime from 'mime';
|
import mimeTypes from 'mime-types';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export class EvolutionStartupService extends ChannelStartupService {
|
export class EvolutionStartupService extends ChannelStartupService {
|
||||||
@ -396,7 +396,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
|||||||
mediaMessage.fileName = 'video.mp4';
|
mediaMessage.fileName = 'video.mp4';
|
||||||
}
|
}
|
||||||
|
|
||||||
let mimetype: string;
|
let mimetype: string | false;
|
||||||
|
|
||||||
const prepareMedia: any = {
|
const prepareMedia: any = {
|
||||||
caption: mediaMessage?.caption,
|
caption: mediaMessage?.caption,
|
||||||
@ -407,9 +407,9 @@ export class EvolutionStartupService extends ChannelStartupService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isURL(mediaMessage.media)) {
|
if (isURL(mediaMessage.media)) {
|
||||||
mimetype = mime.getType(mediaMessage.media);
|
mimetype = mimeTypes.lookup(mediaMessage.media);
|
||||||
} else {
|
} else {
|
||||||
mimetype = mime.getType(mediaMessage.fileName);
|
mimetype = mimeTypes.lookup(mediaMessage.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareMedia.mimetype = mimetype;
|
prepareMedia.mimetype = mimetype;
|
||||||
@ -449,7 +449,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
|||||||
number = number.replace(/\D/g, '');
|
number = number.replace(/\D/g, '');
|
||||||
const hash = `${number}-${new Date().getTime()}`;
|
const hash = `${number}-${new Date().getTime()}`;
|
||||||
|
|
||||||
let mimetype: string;
|
let mimetype: string | false;
|
||||||
|
|
||||||
const prepareMedia: any = {
|
const prepareMedia: any = {
|
||||||
fileName: `${hash}.mp4`,
|
fileName: `${hash}.mp4`,
|
||||||
@ -458,9 +458,9 @@ export class EvolutionStartupService extends ChannelStartupService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isURL(audio)) {
|
if (isURL(audio)) {
|
||||||
mimetype = mime.getType(audio);
|
mimetype = mimeTypes.lookup(audio);
|
||||||
} else {
|
} else {
|
||||||
mimetype = mime.getType(prepareMedia.fileName);
|
mimetype = mimeTypes.lookup(prepareMedia.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareMedia.mimetype = mimetype;
|
prepareMedia.mimetype = mimetype;
|
||||||
|
@ -28,7 +28,7 @@ import { arrayUnique, isURL } from 'class-validator';
|
|||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import { createReadStream } from 'fs';
|
import { createReadStream } from 'fs';
|
||||||
import mime from 'mime';
|
import mimeTypes from 'mime-types';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
export class BusinessStartupService extends ChannelStartupService {
|
export class BusinessStartupService extends ChannelStartupService {
|
||||||
@ -1017,7 +1017,7 @@ export class BusinessStartupService extends ChannelStartupService {
|
|||||||
mediaMessage.fileName = 'video.mp4';
|
mediaMessage.fileName = 'video.mp4';
|
||||||
}
|
}
|
||||||
|
|
||||||
let mimetype: string;
|
let mimetype: string | false;
|
||||||
|
|
||||||
const prepareMedia: any = {
|
const prepareMedia: any = {
|
||||||
caption: mediaMessage?.caption,
|
caption: mediaMessage?.caption,
|
||||||
@ -1028,11 +1028,11 @@ export class BusinessStartupService extends ChannelStartupService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isURL(mediaMessage.media)) {
|
if (isURL(mediaMessage.media)) {
|
||||||
mimetype = mime.getType(mediaMessage.media);
|
mimetype = mimeTypes.lookup(mediaMessage.media);
|
||||||
prepareMedia.id = mediaMessage.media;
|
prepareMedia.id = mediaMessage.media;
|
||||||
prepareMedia.type = 'link';
|
prepareMedia.type = 'link';
|
||||||
} else {
|
} else {
|
||||||
mimetype = mime.getType(mediaMessage.fileName);
|
mimetype = mimeTypes.lookup(mediaMessage.fileName);
|
||||||
const id = await this.getIdMedia(prepareMedia);
|
const id = await this.getIdMedia(prepareMedia);
|
||||||
prepareMedia.id = id;
|
prepareMedia.id = id;
|
||||||
prepareMedia.type = 'id';
|
prepareMedia.type = 'id';
|
||||||
@ -1075,7 +1075,7 @@ export class BusinessStartupService extends ChannelStartupService {
|
|||||||
number = number.replace(/\D/g, '');
|
number = number.replace(/\D/g, '');
|
||||||
const hash = `${number}-${new Date().getTime()}`;
|
const hash = `${number}-${new Date().getTime()}`;
|
||||||
|
|
||||||
let mimetype: string;
|
let mimetype: string | false;
|
||||||
|
|
||||||
const prepareMedia: any = {
|
const prepareMedia: any = {
|
||||||
fileName: `${hash}.mp3`,
|
fileName: `${hash}.mp3`,
|
||||||
@ -1084,11 +1084,11 @@ export class BusinessStartupService extends ChannelStartupService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isURL(audio)) {
|
if (isURL(audio)) {
|
||||||
mimetype = mime.getType(audio);
|
mimetype = mimeTypes.lookup(audio);
|
||||||
prepareMedia.id = audio;
|
prepareMedia.id = audio;
|
||||||
prepareMedia.type = 'link';
|
prepareMedia.type = 'link';
|
||||||
} else {
|
} else {
|
||||||
mimetype = mime.getType(prepareMedia.fileName);
|
mimetype = mimeTypes.lookup(prepareMedia.fileName);
|
||||||
const id = await this.getIdMedia(prepareMedia);
|
const id = await this.getIdMedia(prepareMedia);
|
||||||
prepareMedia.id = id;
|
prepareMedia.id = id;
|
||||||
prepareMedia.type = 'id';
|
prepareMedia.type = 'id';
|
||||||
|
60
src/api/integrations/channel/whatsapp/baileys.controller.ts
Normal file
60
src/api/integrations/channel/whatsapp/baileys.controller.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
|
|
||||||
|
export class BaileysController {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
public async onWhatsapp({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysOnWhatsapp(body?.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async profilePictureUrl({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysProfilePictureUrl(body?.jid, body?.type, body?.timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async assertSessions({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysAssertSessions(body?.jids, body?.force);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createParticipantNodes({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysCreateParticipantNodes(body?.jids, body?.message, body?.extraAttrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getUSyncDevices({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysGetUSyncDevices(body?.jids, body?.useCache, body?.ignoreZeroDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async generateMessageTag({ instanceName }: InstanceDto) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysGenerateMessageTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendNode({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysSendNode(body?.stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async signalRepositoryDecryptMessage({ instanceName }: InstanceDto, body: any) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysSignalRepositoryDecryptMessage(body?.jid, body?.type, body?.ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAuthState({ instanceName }: InstanceDto) {
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
return instance.baileysGetAuthState();
|
||||||
|
}
|
||||||
|
}
|
105
src/api/integrations/channel/whatsapp/baileys.router.ts
Normal file
105
src/api/integrations/channel/whatsapp/baileys.router.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { RouterBroker } from '@api/abstract/abstract.router';
|
||||||
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
|
import { HttpStatus } from '@api/routes/index.router';
|
||||||
|
import { baileysController } from '@api/server.module';
|
||||||
|
import { instanceSchema } from '@validate/instance.schema';
|
||||||
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
export class BaileysRouter extends RouterBroker {
|
||||||
|
constructor(...guards: RequestHandler[]) {
|
||||||
|
super();
|
||||||
|
this.router
|
||||||
|
.post(this.routerPath('onWhatsapp'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.onWhatsapp(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('profilePictureUrl'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.profilePictureUrl(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('assertSessions'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.assertSessions(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('createParticipantNodes'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.createParticipantNodes(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('getUSyncDevices'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.getUSyncDevices(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('generateMessageTag'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.generateMessageTag(instance),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('sendNode'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.sendNode(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('signalRepositoryDecryptMessage'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.signalRepositoryDecryptMessage(instance, req.body),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('getAuthState'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance) => baileysController.getAuthState(instance),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly router: Router = Router();
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
import { BinaryNode, Contact, JidWithDevice, proto, WAConnectionState } from 'baileys';
|
||||||
|
|
||||||
|
export interface ServerToClientEvents {
|
||||||
|
withAck: (d: string, callback: (e: number) => void) => void;
|
||||||
|
onWhatsApp: onWhatsAppType;
|
||||||
|
profilePictureUrl: ProfilePictureUrlType;
|
||||||
|
assertSessions: AssertSessionsType;
|
||||||
|
createParticipantNodes: CreateParticipantNodesType;
|
||||||
|
getUSyncDevices: GetUSyncDevicesType;
|
||||||
|
generateMessageTag: GenerateMessageTagType;
|
||||||
|
sendNode: SendNodeType;
|
||||||
|
'signalRepository:decryptMessage': SignalRepositoryDecryptMessageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientToServerEvents {
|
||||||
|
init: (
|
||||||
|
me: Contact | undefined,
|
||||||
|
account: proto.IADVSignedDeviceIdentity | undefined,
|
||||||
|
status: WAConnectionState,
|
||||||
|
) => void;
|
||||||
|
'CB:call': (packet: any) => void;
|
||||||
|
'CB:ack,class:call': (packet: any) => void;
|
||||||
|
'connection.update:status': (
|
||||||
|
me: Contact | undefined,
|
||||||
|
account: proto.IADVSignedDeviceIdentity | undefined,
|
||||||
|
status: WAConnectionState,
|
||||||
|
) => void;
|
||||||
|
'connection.update:qr': (qr: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type onWhatsAppType = (jid: string, callback: onWhatsAppCallback) => void;
|
||||||
|
export type onWhatsAppCallback = (
|
||||||
|
response: {
|
||||||
|
exists: boolean;
|
||||||
|
jid: string;
|
||||||
|
}[],
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export type ProfilePictureUrlType = (
|
||||||
|
jid: string,
|
||||||
|
type: 'image' | 'preview',
|
||||||
|
timeoutMs: number | undefined,
|
||||||
|
callback: ProfilePictureUrlCallback,
|
||||||
|
) => void;
|
||||||
|
export type ProfilePictureUrlCallback = (response: string | undefined) => void;
|
||||||
|
|
||||||
|
export type AssertSessionsType = (jids: string[], force: boolean, callback: AssertSessionsCallback) => void;
|
||||||
|
export type AssertSessionsCallback = (response: boolean) => void;
|
||||||
|
|
||||||
|
export type CreateParticipantNodesType = (
|
||||||
|
jids: string[],
|
||||||
|
message: any,
|
||||||
|
extraAttrs: any,
|
||||||
|
callback: CreateParticipantNodesCallback,
|
||||||
|
) => void;
|
||||||
|
export type CreateParticipantNodesCallback = (nodes: any, shouldIncludeDeviceIdentity: boolean) => void;
|
||||||
|
|
||||||
|
export type GetUSyncDevicesType = (
|
||||||
|
jids: string[],
|
||||||
|
useCache: boolean,
|
||||||
|
ignoreZeroDevices: boolean,
|
||||||
|
callback: GetUSyncDevicesTypeCallback,
|
||||||
|
) => void;
|
||||||
|
export type GetUSyncDevicesTypeCallback = (jids: JidWithDevice[]) => void;
|
||||||
|
|
||||||
|
export type GenerateMessageTagType = (callback: GenerateMessageTagTypeCallback) => void;
|
||||||
|
export type GenerateMessageTagTypeCallback = (response: string) => void;
|
||||||
|
|
||||||
|
export type SendNodeType = (stanza: BinaryNode, callback: SendNodeTypeCallback) => void;
|
||||||
|
export type SendNodeTypeCallback = (response: boolean) => void;
|
||||||
|
|
||||||
|
export type SignalRepositoryDecryptMessageType = (
|
||||||
|
jid: string,
|
||||||
|
type: 'pkmsg' | 'msg',
|
||||||
|
ciphertext: Buffer,
|
||||||
|
callback: SignalRepositoryDecryptMessageCallback,
|
||||||
|
) => void;
|
||||||
|
export type SignalRepositoryDecryptMessageCallback = (response: any) => void;
|
@ -0,0 +1,181 @@
|
|||||||
|
import { ConnectionState, WAConnectionState, WASocket } from 'baileys';
|
||||||
|
import { io, Socket } from 'socket.io-client';
|
||||||
|
|
||||||
|
import { ClientToServerEvents, ServerToClientEvents } from './transport.type';
|
||||||
|
|
||||||
|
let baileys_connection_state: WAConnectionState = 'close';
|
||||||
|
|
||||||
|
export const useVoiceCallsBaileys = async (
|
||||||
|
wavoip_token: string,
|
||||||
|
baileys_sock: WASocket,
|
||||||
|
status?: WAConnectionState,
|
||||||
|
logger?: boolean,
|
||||||
|
) => {
|
||||||
|
baileys_connection_state = status ?? 'close';
|
||||||
|
|
||||||
|
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io('https://devices.wavoip.com/baileys', {
|
||||||
|
transports: ['websocket'],
|
||||||
|
path: `/${wavoip_token}/websocket`,
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('connect', () => {
|
||||||
|
if (logger) console.log('[*] - Wavoip connected', socket.id);
|
||||||
|
|
||||||
|
socket.emit(
|
||||||
|
'init',
|
||||||
|
baileys_sock.authState.creds.me,
|
||||||
|
baileys_sock.authState.creds.account,
|
||||||
|
baileys_connection_state,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
if (logger) console.log('[*] - Wavoip disconnect');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('connect_error', (error) => {
|
||||||
|
if (socket.active) {
|
||||||
|
if (logger)
|
||||||
|
console.log(
|
||||||
|
'[*] - Wavoip connection error temporary failure, the socket will automatically try to reconnect',
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (logger) console.log('[*] - Wavoip connection error', error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('onWhatsApp', async (jid, callback) => {
|
||||||
|
try {
|
||||||
|
const response: any = await baileys_sock.onWhatsApp(jid);
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call onWhatsApp function', response, jid);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call onWhatsApp function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('profilePictureUrl', async (jid, type, timeoutMs, callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.profilePictureUrl(jid, type, timeoutMs);
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call profilePictureUrl function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call profilePictureUrl function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('assertSessions', async (jids, force, callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.assertSessions(jids, force);
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call assertSessions function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call assertSessions function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('createParticipantNodes', async (jids, message, extraAttrs, callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.createParticipantNodes(jids, message, extraAttrs);
|
||||||
|
|
||||||
|
callback(response, true);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call createParticipantNodes function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call createParticipantNodes function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('getUSyncDevices', async (jids, useCache, ignoreZeroDevices, callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.getUSyncDevices(jids, useCache, ignoreZeroDevices);
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call getUSyncDevices function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call getUSyncDevices function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('generateMessageTag', async (callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.generateMessageTag();
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call generateMessageTag function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call generateMessageTag function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('sendNode', async (stanza, callback) => {
|
||||||
|
try {
|
||||||
|
console.log('sendNode', JSON.stringify(stanza));
|
||||||
|
const response = await baileys_sock.sendNode(stanza);
|
||||||
|
|
||||||
|
callback(true);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call sendNode function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call sendNode function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('signalRepository:decryptMessage', async (jid, type, ciphertext, callback) => {
|
||||||
|
try {
|
||||||
|
const response = await baileys_sock.signalRepository.decryptMessage({
|
||||||
|
jid: jid,
|
||||||
|
type: type,
|
||||||
|
ciphertext: ciphertext,
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(response);
|
||||||
|
|
||||||
|
if (logger) console.log('[*] Success on call signalRepository:decryptMessage function', response);
|
||||||
|
} catch (error) {
|
||||||
|
if (logger) console.error('[*] Error on call signalRepository:decryptMessage function', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// we only use this connection data to inform the webphone that the device is connected and creeds account to generate e2e whatsapp key for make call packets
|
||||||
|
baileys_sock.ev.on('connection.update', (update: Partial<ConnectionState>) => {
|
||||||
|
const { connection } = update;
|
||||||
|
|
||||||
|
if (connection) {
|
||||||
|
baileys_connection_state = connection;
|
||||||
|
socket
|
||||||
|
.timeout(1000)
|
||||||
|
.emit(
|
||||||
|
'connection.update:status',
|
||||||
|
baileys_sock.authState.creds.me,
|
||||||
|
baileys_sock.authState.creds.account,
|
||||||
|
connection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update.qr) {
|
||||||
|
socket.timeout(1000).emit('connection.update:qr', update.qr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
baileys_sock.ws.on('CB:call', (packet) => {
|
||||||
|
if (logger) console.log('[*] Signling received');
|
||||||
|
socket.volatile.timeout(1000).emit('CB:call', packet);
|
||||||
|
});
|
||||||
|
|
||||||
|
baileys_sock.ws.on('CB:ack,class:call', (packet) => {
|
||||||
|
if (logger) console.log('[*] Signling ack received');
|
||||||
|
socket.volatile.timeout(1000).emit('CB:ack,class:call', packet);
|
||||||
|
});
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
};
|
@ -131,7 +131,7 @@ import ffmpeg from 'fluent-ffmpeg';
|
|||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import mime from 'mime';
|
import mimeTypes from 'mime-types';
|
||||||
import NodeCache from 'node-cache';
|
import NodeCache from 'node-cache';
|
||||||
import cron from 'node-cron';
|
import cron from 'node-cron';
|
||||||
import { release } from 'os';
|
import { release } from 'os';
|
||||||
@ -143,6 +143,8 @@ import sharp from 'sharp';
|
|||||||
import { PassThrough, Readable } from 'stream';
|
import { PassThrough, Readable } from 'stream';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { useVoiceCallsBaileys } from './voiceCalls/useVoiceCallsBaileys';
|
||||||
|
|
||||||
const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine());
|
const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine());
|
||||||
|
|
||||||
// Adicione a função getVideoDuration no início do arquivo
|
// Adicione a função getVideoDuration no início do arquivo
|
||||||
@ -673,8 +675,30 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
|
|
||||||
this.client = makeWASocket(socketConfig);
|
this.client = makeWASocket(socketConfig);
|
||||||
|
|
||||||
|
if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) {
|
||||||
|
useVoiceCallsBaileys(this.localSettings.wavoipToken, this.client, this.connectionStatus.state as any, true);
|
||||||
|
}
|
||||||
|
|
||||||
this.eventHandler();
|
this.eventHandler();
|
||||||
|
|
||||||
|
this.client.ws.on('CB:call', (packet) => {
|
||||||
|
console.log('CB:call', packet);
|
||||||
|
const payload = {
|
||||||
|
event: 'CB:call',
|
||||||
|
packet: packet,
|
||||||
|
};
|
||||||
|
this.sendDataWebhook(Events.CALL, payload, true, ['websocket']);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.client.ws.on('CB:ack,class:call', (packet) => {
|
||||||
|
console.log('CB:ack,class:call', packet);
|
||||||
|
const payload = {
|
||||||
|
event: 'CB:ack,class:call',
|
||||||
|
packet: packet,
|
||||||
|
};
|
||||||
|
this.sendDataWebhook(Events.CALL, payload, true, ['websocket']);
|
||||||
|
});
|
||||||
|
|
||||||
this.phoneNumber = number;
|
this.phoneNumber = number;
|
||||||
|
|
||||||
return this.client;
|
return this.client;
|
||||||
@ -1248,7 +1272,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { buffer, mediaType, fileName, size } = media;
|
const { buffer, mediaType, fileName, size } = media;
|
||||||
const mimetype = mime.getType(fileName).toString();
|
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||||
const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName);
|
const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName);
|
||||||
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, {
|
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, {
|
||||||
'Content-Type': mimetype,
|
'Content-Type': mimetype,
|
||||||
@ -2210,7 +2234,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
|
|
||||||
const { buffer, mediaType, fileName, size } = media;
|
const { buffer, mediaType, fileName, size } = media;
|
||||||
|
|
||||||
const mimetype = mime.getType(fileName).toString();
|
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||||
|
|
||||||
const fullName = join(
|
const fullName = join(
|
||||||
`${this.instance.id}`,
|
`${this.instance.id}`,
|
||||||
@ -2532,12 +2556,12 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
mediaMessage.fileName = 'video.mp4';
|
mediaMessage.fileName = 'video.mp4';
|
||||||
}
|
}
|
||||||
|
|
||||||
let mimetype: string;
|
let mimetype: string | false;
|
||||||
|
|
||||||
if (mediaMessage.mimetype) {
|
if (mediaMessage.mimetype) {
|
||||||
mimetype = mediaMessage.mimetype;
|
mimetype = mediaMessage.mimetype;
|
||||||
} else {
|
} else {
|
||||||
mimetype = mime.getType(mediaMessage.fileName);
|
mimetype = mimeTypes.lookup(mediaMessage.fileName);
|
||||||
|
|
||||||
if (!mimetype && isURL(mediaMessage.media)) {
|
if (!mimetype && isURL(mediaMessage.media)) {
|
||||||
let config: any = {
|
let config: any = {
|
||||||
@ -3590,7 +3614,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
);
|
);
|
||||||
const typeMessage = getContentType(msg.message);
|
const typeMessage = getContentType(msg.message);
|
||||||
|
|
||||||
const ext = mime.getExtension(mediaMessage?.['mimetype']);
|
const ext = mimeTypes.extension(mediaMessage?.['mimetype']);
|
||||||
const fileName = mediaMessage?.['fileName'] || `${msg.key.id}.${ext}` || `${v4()}.${ext}`;
|
const fileName = mediaMessage?.['fileName'] || `${msg.key.id}.${ext}` || `${v4()}.${ext}`;
|
||||||
|
|
||||||
if (convertToMp4 && typeMessage === 'audioMessage') {
|
if (convertToMp4 && typeMessage === 'audioMessage') {
|
||||||
@ -4395,4 +4419,85 @@ export class BaileysStartupService extends ChannelStartupService {
|
|||||||
id,
|
id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async baileysOnWhatsapp(jid: string) {
|
||||||
|
const response = await this.client.onWhatsApp(jid);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysProfilePictureUrl(jid: string, type: 'image' | 'preview', timeoutMs: number) {
|
||||||
|
const response = await this.client.profilePictureUrl(jid, type, timeoutMs);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysAssertSessions(jids: string[], force: boolean) {
|
||||||
|
const response = await this.client.assertSessions(jids, force);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysCreateParticipantNodes(jids: string[], message: proto.IMessage, extraAttrs: any) {
|
||||||
|
const response = await this.client.createParticipantNodes(jids, message, extraAttrs);
|
||||||
|
|
||||||
|
const convertedResponse = {
|
||||||
|
...response,
|
||||||
|
nodes: response.nodes.map((node: any) => ({
|
||||||
|
...node,
|
||||||
|
content: node.content?.map((c: any) => ({
|
||||||
|
...c,
|
||||||
|
content: c.content instanceof Uint8Array ? Buffer.from(c.content).toString('base64') : c.content,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
return convertedResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysSendNode(stanza: any) {
|
||||||
|
console.log('stanza', JSON.stringify(stanza));
|
||||||
|
const response = await this.client.sendNode(stanza);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysGetUSyncDevices(jids: string[], useCache: boolean, ignoreZeroDevices: boolean) {
|
||||||
|
const response = await this.client.getUSyncDevices(jids, useCache, ignoreZeroDevices);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysGenerateMessageTag() {
|
||||||
|
const response = await this.client.generateMessageTag();
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysSignalRepositoryDecryptMessage(jid: string, type: 'pkmsg' | 'msg', ciphertext: string) {
|
||||||
|
try {
|
||||||
|
const ciphertextBuffer = Buffer.from(ciphertext, 'base64');
|
||||||
|
|
||||||
|
const response = await this.client.signalRepository.decryptMessage({
|
||||||
|
jid,
|
||||||
|
type,
|
||||||
|
ciphertext: ciphertextBuffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response instanceof Uint8Array ? Buffer.from(response).toString('base64') : response;
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Error decrypting message:');
|
||||||
|
this.logger.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async baileysGetAuthState() {
|
||||||
|
const response = {
|
||||||
|
me: this.client.authState.creds.me,
|
||||||
|
account: this.client.authState.creds.account,
|
||||||
|
};
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import dayjs from 'dayjs';
|
|||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import Jimp from 'jimp';
|
import Jimp from 'jimp';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import mime from 'mime';
|
import mimeTypes from 'mime-types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
@ -1066,7 +1066,7 @@ export class ChatwootService {
|
|||||||
public async sendAttachment(waInstance: any, number: string, media: any, caption?: string, options?: Options) {
|
public async sendAttachment(waInstance: any, number: string, media: any, caption?: string, options?: Options) {
|
||||||
try {
|
try {
|
||||||
const parsedMedia = path.parse(decodeURIComponent(media));
|
const parsedMedia = path.parse(decodeURIComponent(media));
|
||||||
let mimeType = mime.getType(parsedMedia?.ext) || '';
|
let mimeType = mimeTypes.lookup(parsedMedia?.ext) || '';
|
||||||
let fileName = parsedMedia?.name + parsedMedia?.ext;
|
let fileName = parsedMedia?.name + parsedMedia?.ext;
|
||||||
|
|
||||||
if (!mimeType) {
|
if (!mimeType) {
|
||||||
@ -1958,7 +1958,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!nameFile) {
|
if (!nameFile) {
|
||||||
nameFile = `${Math.random().toString(36).substring(7)}.${mime.getExtension(downloadBase64.mimetype) || ''}`;
|
nameFile = `${Math.random().toString(36).substring(7)}.${mimeTypes.extension(downloadBase64.mimetype) || ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
||||||
@ -2057,8 +2057,8 @@ export class ChatwootService {
|
|||||||
if (isAdsMessage) {
|
if (isAdsMessage) {
|
||||||
const imgBuffer = await axios.get(adsMessage.thumbnailUrl, { responseType: 'arraybuffer' });
|
const imgBuffer = await axios.get(adsMessage.thumbnailUrl, { responseType: 'arraybuffer' });
|
||||||
|
|
||||||
const extension = mime.getExtension(imgBuffer.headers['content-type']);
|
const extension = mimeTypes.extension(imgBuffer.headers['content-type']);
|
||||||
const mimeType = extension && mime.getType(extension);
|
const mimeType = extension && mimeTypes.lookup(extension);
|
||||||
|
|
||||||
if (!mimeType) {
|
if (!mimeType) {
|
||||||
this.logger.warn('mimetype of Ads message not found');
|
this.logger.warn('mimetype of Ads message not found');
|
||||||
@ -2066,7 +2066,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const random = Math.random().toString(36).substring(7);
|
const random = Math.random().toString(36).substring(7);
|
||||||
const nameFile = `${random}.${mime.getExtension(mimeType)}`;
|
const nameFile = `${random}.${mimeTypes.extension(mimeType)}`;
|
||||||
const fileData = Buffer.from(imgBuffer.data, 'binary');
|
const fileData = Buffer.from(imgBuffer.data, 'binary');
|
||||||
|
|
||||||
const img = await Jimp.read(fileData);
|
const img = await Jimp.read(fileData);
|
||||||
|
@ -13,6 +13,7 @@ export type EmitData = {
|
|||||||
sender: string;
|
sender: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
local?: boolean;
|
local?: boolean;
|
||||||
|
integration?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface EventControllerInterface {
|
export interface EventControllerInterface {
|
||||||
@ -23,7 +24,7 @@ export interface EventControllerInterface {
|
|||||||
|
|
||||||
export class EventController {
|
export class EventController {
|
||||||
public prismaRepository: PrismaRepository;
|
public prismaRepository: PrismaRepository;
|
||||||
private waMonitor: WAMonitoringService;
|
protected waMonitor: WAMonitoringService;
|
||||||
private integrationStatus: boolean;
|
private integrationStatus: boolean;
|
||||||
private integrationName: string;
|
private integrationName: string;
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ export class EventManager {
|
|||||||
sender: string;
|
sender: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
local?: boolean;
|
local?: boolean;
|
||||||
|
integration?: string[];
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
await this.websocket.emit(eventData);
|
await this.websocket.emit(eventData);
|
||||||
await this.rabbitmq.emit(eventData);
|
await this.rabbitmq.emit(eventData);
|
||||||
|
@ -120,7 +120,11 @@ export class PusherController extends EventController implements EventController
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
local,
|
local,
|
||||||
|
integration,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
|
if (integration && !integration.includes('pusher')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this.status) {
|
if (!this.status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,12 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
dateTime,
|
dateTime,
|
||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
|
integration,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
|
if (integration && !integration.includes('rabbitmq')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.status) {
|
if (!this.status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,12 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
dateTime,
|
dateTime,
|
||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
|
integration,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
|
if (integration && !integration.includes('sqs')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.status) {
|
if (!this.status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,12 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
local,
|
local,
|
||||||
|
integration,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
|
if (integration && !integration.includes('webhook')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const instance = (await this.get(instanceName)) as wa.LocalWebHook;
|
const instance = (await this.get(instanceName)) as wa.LocalWebHook;
|
||||||
|
|
||||||
const webhookConfig = configService.get<Webhook>('WEBHOOK');
|
const webhookConfig = configService.get<Webhook>('WEBHOOK');
|
||||||
@ -85,7 +90,7 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
apikey: apiKey,
|
apikey: apiKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((local && !instance) || !instance?.enabled) {
|
if (local && instance?.enabled) {
|
||||||
if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) {
|
if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) {
|
||||||
let baseURL: string;
|
let baseURL: string;
|
||||||
|
|
||||||
|
@ -35,6 +35,16 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
this.logger.info('User disconnected');
|
this.logger.info('User disconnected');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('sendNode', async (data) => {
|
||||||
|
try {
|
||||||
|
await this.waMonitor.waInstances[data.instanceId].baileysSendNode(data.stanza);
|
||||||
|
this.logger.info('Node sent successfully');
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Error sending node:');
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.info('Socket.io initialized');
|
this.logger.info('Socket.io initialized');
|
||||||
@ -65,7 +75,12 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
dateTime,
|
dateTime,
|
||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
|
integration,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
|
if (integration && !integration.includes('websocket')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.status) {
|
if (!this.status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { StorageRouter } from '@api/integrations/storage/storage.router';
|
|||||||
import { configService } from '@config/env.config';
|
import { configService } from '@config/env.config';
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import mime from 'mime';
|
import mimeTypes from 'mime-types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { CallRouter } from './call.router';
|
import { CallRouter } from './call.router';
|
||||||
@ -49,7 +49,7 @@ router.get('/assets/*', (req, res) => {
|
|||||||
const filePath = path.join(basePath, 'assets/', fileName);
|
const filePath = path.join(basePath, 'assets/', fileName);
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
res.set('Content-Type', mime.getType(filePath) || 'text/css');
|
res.set('Content-Type', mimeTypes.lookup(filePath) || 'text/css');
|
||||||
res.send(fs.readFileSync(filePath));
|
res.send(fs.readFileSync(filePath));
|
||||||
} else {
|
} else {
|
||||||
res.status(404).send('File not found');
|
res.status(404).send('File not found');
|
||||||
@ -87,7 +87,7 @@ router
|
|||||||
.use('/settings', new SettingsRouter(...guards).router)
|
.use('/settings', new SettingsRouter(...guards).router)
|
||||||
.use('/proxy', new ProxyRouter(...guards).router)
|
.use('/proxy', new ProxyRouter(...guards).router)
|
||||||
.use('/label', new LabelRouter(...guards).router)
|
.use('/label', new LabelRouter(...guards).router)
|
||||||
.use('', new ChannelRouter(configService).router)
|
.use('', new ChannelRouter(configService, ...guards).router)
|
||||||
.use('', new EventRouter(configService, ...guards).router)
|
.use('', new EventRouter(configService, ...guards).router)
|
||||||
.use('', new ChatbotRouter(...guards).router)
|
.use('', new ChatbotRouter(...guards).router)
|
||||||
.use('', new StorageRouter(...guards).router);
|
.use('', new StorageRouter(...guards).router);
|
||||||
|
@ -15,6 +15,7 @@ import { TemplateController } from './controllers/template.controller';
|
|||||||
import { ChannelController } from './integrations/channel/channel.controller';
|
import { ChannelController } from './integrations/channel/channel.controller';
|
||||||
import { EvolutionController } from './integrations/channel/evolution/evolution.controller';
|
import { EvolutionController } from './integrations/channel/evolution/evolution.controller';
|
||||||
import { MetaController } from './integrations/channel/meta/meta.controller';
|
import { MetaController } from './integrations/channel/meta/meta.controller';
|
||||||
|
import { BaileysController } from './integrations/channel/whatsapp/baileys.controller';
|
||||||
import { ChatbotController } from './integrations/chatbot/chatbot.controller';
|
import { ChatbotController } from './integrations/chatbot/chatbot.controller';
|
||||||
import { ChatwootController } from './integrations/chatbot/chatwoot/controllers/chatwoot.controller';
|
import { ChatwootController } from './integrations/chatbot/chatwoot/controllers/chatwoot.controller';
|
||||||
import { ChatwootService } from './integrations/chatbot/chatwoot/services/chatwoot.service';
|
import { ChatwootService } from './integrations/chatbot/chatwoot/services/chatwoot.service';
|
||||||
@ -107,7 +108,7 @@ export const channelController = new ChannelController(prismaRepository, waMonit
|
|||||||
// channels
|
// channels
|
||||||
export const evolutionController = new EvolutionController(prismaRepository, waMonitor);
|
export const evolutionController = new EvolutionController(prismaRepository, waMonitor);
|
||||||
export const metaController = new MetaController(prismaRepository, waMonitor);
|
export const metaController = new MetaController(prismaRepository, waMonitor);
|
||||||
|
export const baileysController = new BaileysController(waMonitor);
|
||||||
// chatbots
|
// chatbots
|
||||||
const typebotService = new TypebotService(waMonitor, configService, prismaRepository);
|
const typebotService = new TypebotService(waMonitor, configService, prismaRepository);
|
||||||
export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor);
|
export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor);
|
||||||
|
@ -151,6 +151,7 @@ export class ChannelStartupService {
|
|||||||
this.localSettings.readMessages = data?.readMessages;
|
this.localSettings.readMessages = data?.readMessages;
|
||||||
this.localSettings.readStatus = data?.readStatus;
|
this.localSettings.readStatus = data?.readStatus;
|
||||||
this.localSettings.syncFullHistory = data?.syncFullHistory;
|
this.localSettings.syncFullHistory = data?.syncFullHistory;
|
||||||
|
this.localSettings.wavoipToken = data?.wavoipToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setSettings(data: SettingsDto) {
|
public async setSettings(data: SettingsDto) {
|
||||||
@ -166,6 +167,7 @@ export class ChannelStartupService {
|
|||||||
readMessages: data.readMessages,
|
readMessages: data.readMessages,
|
||||||
readStatus: data.readStatus,
|
readStatus: data.readStatus,
|
||||||
syncFullHistory: data.syncFullHistory,
|
syncFullHistory: data.syncFullHistory,
|
||||||
|
wavoipToken: data.wavoipToken,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
rejectCall: data.rejectCall,
|
rejectCall: data.rejectCall,
|
||||||
@ -175,6 +177,7 @@ export class ChannelStartupService {
|
|||||||
readMessages: data.readMessages,
|
readMessages: data.readMessages,
|
||||||
readStatus: data.readStatus,
|
readStatus: data.readStatus,
|
||||||
syncFullHistory: data.syncFullHistory,
|
syncFullHistory: data.syncFullHistory,
|
||||||
|
wavoipToken: data.wavoipToken,
|
||||||
instanceId: this.instanceId,
|
instanceId: this.instanceId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -186,6 +189,12 @@ export class ChannelStartupService {
|
|||||||
this.localSettings.readMessages = data?.readMessages;
|
this.localSettings.readMessages = data?.readMessages;
|
||||||
this.localSettings.readStatus = data?.readStatus;
|
this.localSettings.readStatus = data?.readStatus;
|
||||||
this.localSettings.syncFullHistory = data?.syncFullHistory;
|
this.localSettings.syncFullHistory = data?.syncFullHistory;
|
||||||
|
this.localSettings.wavoipToken = data?.wavoipToken;
|
||||||
|
|
||||||
|
if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) {
|
||||||
|
this.client.ws.close();
|
||||||
|
this.client.ws.connect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findSettings() {
|
public async findSettings() {
|
||||||
@ -207,6 +216,7 @@ export class ChannelStartupService {
|
|||||||
readMessages: data.readMessages,
|
readMessages: data.readMessages,
|
||||||
readStatus: data.readStatus,
|
readStatus: data.readStatus,
|
||||||
syncFullHistory: data.syncFullHistory,
|
syncFullHistory: data.syncFullHistory,
|
||||||
|
wavoipToken: data.wavoipToken,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +429,7 @@ export class ChannelStartupService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendDataWebhook<T = any>(event: Events, data: T, local = true) {
|
public async sendDataWebhook<T = any>(event: Events, data: T, local = true, integration?: string[]) {
|
||||||
const serverUrl = this.configService.get<HttpServer>('SERVER').URL;
|
const serverUrl = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
||||||
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
||||||
@ -439,6 +449,7 @@ export class ChannelStartupService {
|
|||||||
sender: this.wuid,
|
sender: this.wuid,
|
||||||
apiKey: expose && instanceApikey ? instanceApikey : null,
|
apiKey: expose && instanceApikey ? instanceApikey : null,
|
||||||
local,
|
local,
|
||||||
|
integration,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ export declare namespace wa {
|
|||||||
readMessages?: boolean;
|
readMessages?: boolean;
|
||||||
readStatus?: boolean;
|
readStatus?: boolean;
|
||||||
syncFullHistory?: boolean;
|
syncFullHistory?: boolean;
|
||||||
|
wavoipToken?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalEvent = {
|
export type LocalEvent = {
|
||||||
|
@ -43,6 +43,7 @@ export const instanceSchema: JSONSchema7 = {
|
|||||||
readMessages: { type: 'boolean' },
|
readMessages: { type: 'boolean' },
|
||||||
readStatus: { type: 'boolean' },
|
readStatus: { type: 'boolean' },
|
||||||
syncFullHistory: { type: 'boolean' },
|
syncFullHistory: { type: 'boolean' },
|
||||||
|
wavoipToken: { type: 'string' },
|
||||||
// Proxy
|
// Proxy
|
||||||
proxyHost: { type: 'string' },
|
proxyHost: { type: 'string' },
|
||||||
proxyPort: { type: 'string' },
|
proxyPort: { type: 'string' },
|
||||||
|
@ -31,7 +31,24 @@ export const settingsSchema: JSONSchema7 = {
|
|||||||
readMessages: { type: 'boolean' },
|
readMessages: { type: 'boolean' },
|
||||||
readStatus: { type: 'boolean' },
|
readStatus: { type: 'boolean' },
|
||||||
syncFullHistory: { type: 'boolean' },
|
syncFullHistory: { type: 'boolean' },
|
||||||
|
wavoipToken: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: ['rejectCall', 'groupsIgnore', 'alwaysOnline', 'readMessages', 'readStatus', 'syncFullHistory'],
|
required: [
|
||||||
...isNotEmpty('rejectCall', 'groupsIgnore', 'alwaysOnline', 'readMessages', 'readStatus', 'syncFullHistory'),
|
'rejectCall',
|
||||||
|
'groupsIgnore',
|
||||||
|
'alwaysOnline',
|
||||||
|
'readMessages',
|
||||||
|
'readStatus',
|
||||||
|
'syncFullHistory',
|
||||||
|
'wavoipToken',
|
||||||
|
],
|
||||||
|
...isNotEmpty(
|
||||||
|
'rejectCall',
|
||||||
|
'groupsIgnore',
|
||||||
|
'alwaysOnline',
|
||||||
|
'readMessages',
|
||||||
|
'readStatus',
|
||||||
|
'syncFullHistory',
|
||||||
|
'wavoipToken',
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user