mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-14 09:51:24 -06:00
mobile connection
This commit is contained in:
parent
240f01f378
commit
1172b6c871
@ -46,7 +46,7 @@
|
|||||||
"@figuro/chatwoot-sdk": "^1.1.16",
|
"@figuro/chatwoot-sdk": "^1.1.16",
|
||||||
"@hapi/boom": "^10.0.1",
|
"@hapi/boom": "^10.0.1",
|
||||||
"@sentry/node": "^7.59.2",
|
"@sentry/node": "^7.59.2",
|
||||||
"@whiskeysockets/baileys": "6.6.0",
|
"@whiskeysockets/baileys": "github:AtendAI/Baileys",
|
||||||
"amqplib": "^0.10.3",
|
"amqplib": "^0.10.3",
|
||||||
"aws-sdk": "^2.1499.0",
|
"aws-sdk": "^2.1499.0",
|
||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
|
@ -53,6 +53,7 @@ export class InstanceController {
|
|||||||
events,
|
events,
|
||||||
qrcode,
|
qrcode,
|
||||||
number,
|
number,
|
||||||
|
mobile,
|
||||||
integration,
|
integration,
|
||||||
token,
|
token,
|
||||||
chatwoot_account_id,
|
chatwoot_account_id,
|
||||||
@ -115,7 +116,7 @@ export class InstanceController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.waMonitor.saveInstance({ integration, instanceName, token, number });
|
await this.waMonitor.saveInstance({ integration, instanceName, token, number, mobile });
|
||||||
|
|
||||||
instance.instanceName = instanceName;
|
instance.instanceName = instanceName;
|
||||||
|
|
||||||
@ -405,7 +406,7 @@ export class InstanceController {
|
|||||||
|
|
||||||
if (qrcode) {
|
if (qrcode) {
|
||||||
this.logger.verbose('creating qrcode');
|
this.logger.verbose('creating qrcode');
|
||||||
await instance.connectToWhatsapp(number);
|
await instance.connectToWhatsapp(number, mobile);
|
||||||
await delay(5000);
|
await delay(5000);
|
||||||
getQrcode = instance.qrCode;
|
getQrcode = instance.qrCode;
|
||||||
}
|
}
|
||||||
@ -569,7 +570,7 @@ export class InstanceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
|
public async connectToWhatsapp({ instanceName, number = null, mobile = null }: InstanceDto) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
|
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
|
||||||
|
|
||||||
@ -592,7 +593,7 @@ export class InstanceController {
|
|||||||
|
|
||||||
if (state == 'close') {
|
if (state == 'close') {
|
||||||
this.logger.verbose('connecting');
|
this.logger.verbose('connecting');
|
||||||
await instance.connectToWhatsapp(number);
|
await instance.connectToWhatsapp(number, mobile);
|
||||||
|
|
||||||
await delay(5000);
|
await delay(5000);
|
||||||
return instance.qrCode;
|
return instance.qrCode;
|
||||||
@ -633,6 +634,20 @@ export class InstanceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async registerMobileCode({ instanceName }: InstanceDto, { mobileCode }: any) {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('requested registerMobileCode from ' + instanceName + ' instance');
|
||||||
|
|
||||||
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
|
|
||||||
|
console.log('mobileCode', mobileCode);
|
||||||
|
return await instance.receiveMobileCode(mobileCode);
|
||||||
|
// return { status: 'SUCCESS', error: false, response: { message: 'Mobile code registered' } };
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async connectionState({ instanceName }: InstanceDto) {
|
public async connectionState({ instanceName }: InstanceDto) {
|
||||||
this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
|
this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
|
||||||
return {
|
return {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { WAPresence } from "@whiskeysockets/baileys";
|
import { WAPresence } from '@whiskeysockets/baileys';
|
||||||
|
|
||||||
export class InstanceDto {
|
export class InstanceDto {
|
||||||
instanceName: string;
|
instanceName: string;
|
||||||
instanceId?: string;
|
instanceId?: string;
|
||||||
qrcode?: boolean;
|
qrcode?: boolean;
|
||||||
number?: string;
|
number?: string;
|
||||||
|
mobile?: boolean;
|
||||||
integration?: string;
|
integration?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
webhook?: string;
|
webhook?: string;
|
||||||
|
@ -3,7 +3,7 @@ import { RequestHandler, Router } from 'express';
|
|||||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { dbserver } from '../../libs/db.connect';
|
import { dbserver } from '../../libs/db.connect';
|
||||||
import {instanceNameSchema, oldTokenSchema, presenceOnlySchema} from '../../validate/validate.schema';
|
import { instanceNameSchema, oldTokenSchema, presenceOnlySchema } from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import { InstanceDto, SetPresenceDto } from '../dto/instance.dto';
|
import { InstanceDto, SetPresenceDto } from '../dto/instance.dto';
|
||||||
import { OldToken } from '../services/auth.service';
|
import { OldToken } from '../services/auth.service';
|
||||||
@ -50,6 +50,22 @@ export class InstanceRouter extends RouterBroker {
|
|||||||
|
|
||||||
return res.status(HttpStatus.OK).json(response);
|
return res.status(HttpStatus.OK).json(response);
|
||||||
})
|
})
|
||||||
|
.post(this.routerPath('registerMobileCode'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in registerMobileCode');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
const response = await this.dataValidate<null>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceNameSchema,
|
||||||
|
ClassRef: SetPresenceDto,
|
||||||
|
execute: (instance, data) => instanceController.registerMobileCode(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
.get(this.routerPath('connect'), ...guards, async (req, res) => {
|
.get(this.routerPath('connect'), ...guards, async (req, res) => {
|
||||||
logger.verbose('request received in connectInstance');
|
logger.verbose('request received in connectInstance');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
|
@ -12,6 +12,7 @@ import makeWASocket, {
|
|||||||
DisconnectReason,
|
DisconnectReason,
|
||||||
downloadMediaMessage,
|
downloadMediaMessage,
|
||||||
fetchLatestBaileysVersion,
|
fetchLatestBaileysVersion,
|
||||||
|
generateMobileNode,
|
||||||
generateWAMessageFromContent,
|
generateWAMessageFromContent,
|
||||||
getAggregateVotesInPollMessage,
|
getAggregateVotesInPollMessage,
|
||||||
getContentType,
|
getContentType,
|
||||||
@ -24,6 +25,7 @@ import makeWASocket, {
|
|||||||
MessageUpsertType,
|
MessageUpsertType,
|
||||||
MiscMessageGenerationOptions,
|
MiscMessageGenerationOptions,
|
||||||
ParticipantAction,
|
ParticipantAction,
|
||||||
|
PHONENUMBER_MCC,
|
||||||
prepareWAMessageMedia,
|
prepareWAMessageMedia,
|
||||||
proto,
|
proto,
|
||||||
useMultiFileAuthState,
|
useMultiFileAuthState,
|
||||||
@ -42,6 +44,7 @@ import { exec } from 'child_process';
|
|||||||
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import fs, { existsSync, readFileSync } from 'fs';
|
import fs, { existsSync, readFileSync } from 'fs';
|
||||||
|
import { parsePhoneNumber } from 'libphonenumber-js';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import NodeCache from 'node-cache';
|
import NodeCache from 'node-cache';
|
||||||
import { getMIMEType } from 'node-mime-types';
|
import { getMIMEType } from 'node-mime-types';
|
||||||
@ -132,6 +135,7 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
this.logger.verbose('BaileysStartupService initialized');
|
this.logger.verbose('BaileysStartupService initialized');
|
||||||
this.cleanStore();
|
this.cleanStore();
|
||||||
this.instance.qrcode = { count: 0 };
|
this.instance.qrcode = { count: 0 };
|
||||||
|
this.mobile = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly msgRetryCounterCache: CacheStore = new NodeCache();
|
private readonly msgRetryCounterCache: CacheStore = new NodeCache();
|
||||||
@ -141,7 +145,8 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
|
|
||||||
public stateConnection: wa.StateConnection = { state: 'close' };
|
public stateConnection: wa.StateConnection = { state: 'close' };
|
||||||
|
|
||||||
private phoneNumber: string;
|
public phoneNumber: string;
|
||||||
|
public mobile: boolean;
|
||||||
|
|
||||||
public get connectionStatus() {
|
public get connectionStatus() {
|
||||||
this.logger.verbose('Getting connection status');
|
this.logger.verbose('Getting connection status');
|
||||||
@ -389,6 +394,10 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connection === 'connecting') {
|
||||||
|
if (this.mobile) this.sendMobileCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getMessage(key: proto.IMessageKey, full = false) {
|
private async getMessage(key: proto.IMessageKey, full = false) {
|
||||||
@ -446,7 +455,7 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name));
|
return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connectToWhatsapp(number?: string): Promise<WASocket> {
|
public async connectToWhatsapp(number?: string, mobile?: boolean): Promise<WASocket> {
|
||||||
this.logger.verbose('Connecting to whatsapp');
|
this.logger.verbose('Connecting to whatsapp');
|
||||||
try {
|
try {
|
||||||
this.loadWebhook();
|
this.loadWebhook();
|
||||||
@ -461,7 +470,14 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
|
|
||||||
this.instance.authState = await this.defineAuthState();
|
this.instance.authState = await this.defineAuthState();
|
||||||
|
|
||||||
|
if (!mobile) {
|
||||||
|
this.mobile = false;
|
||||||
|
} else {
|
||||||
|
this.mobile = mobile;
|
||||||
|
}
|
||||||
|
|
||||||
const { version } = await fetchLatestBaileysVersion();
|
const { version } = await fetchLatestBaileysVersion();
|
||||||
|
|
||||||
this.logger.verbose('Baileys version: ' + version);
|
this.logger.verbose('Baileys version: ' + version);
|
||||||
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
|
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
|
||||||
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
|
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
|
||||||
@ -500,6 +516,7 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
},
|
},
|
||||||
logger: P({ level: this.logBaileys }),
|
logger: P({ level: this.logBaileys }),
|
||||||
printQRInTerminal: false,
|
printQRInTerminal: false,
|
||||||
|
mobile,
|
||||||
browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser,
|
browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser,
|
||||||
version,
|
version,
|
||||||
markOnlineOnConnect: this.localSettings.always_online,
|
markOnlineOnConnect: this.localSettings.always_online,
|
||||||
@ -564,6 +581,70 @@ export class BaileysStartupService extends WAStartupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async sendMobileCode() {
|
||||||
|
const { registration } = this.client.authState.creds || null;
|
||||||
|
|
||||||
|
let phoneNumber = registration.phoneNumber || this.phoneNumber;
|
||||||
|
|
||||||
|
if (!phoneNumber.startsWith('+')) {
|
||||||
|
phoneNumber = '+' + phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!phoneNumber) {
|
||||||
|
this.logger.error('Phone number not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('phoneNumber', phoneNumber);
|
||||||
|
|
||||||
|
const parsedPhoneNumber = parsePhoneNumber(phoneNumber);
|
||||||
|
|
||||||
|
console.log('parsedPhoneNumber', parsedPhoneNumber);
|
||||||
|
|
||||||
|
if (!parsedPhoneNumber?.isValid()) {
|
||||||
|
this.logger.error('Phone number invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration.phoneNumber = parsedPhoneNumber.format('E.164');
|
||||||
|
registration.phoneNumberCountryCode = parsedPhoneNumber.countryCallingCode;
|
||||||
|
registration.phoneNumberNationalNumber = parsedPhoneNumber.nationalNumber;
|
||||||
|
|
||||||
|
const mcc = await PHONENUMBER_MCC[parsedPhoneNumber.countryCallingCode];
|
||||||
|
if (!mcc) {
|
||||||
|
this.logger.error('MCC not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration.phoneNumberMobileCountryCode = mcc;
|
||||||
|
registration.method = 'voice';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.client.requestRegistrationCode(registration);
|
||||||
|
|
||||||
|
console.log('response', response);
|
||||||
|
if (['ok', 'sent'].includes(response?.status)) {
|
||||||
|
this.logger.verbose('Registration code sent successfully');
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async receiveMobileCode(code: string) {
|
||||||
|
await this.client
|
||||||
|
.register(code.replace(/["']/g, '').trim().toLowerCase())
|
||||||
|
.then(async (response) => {
|
||||||
|
this.logger.verbose('Registration code received successfully');
|
||||||
|
console.log(response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.logger.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async reloadConnection(): Promise<WASocket> {
|
public async reloadConnection(): Promise<WASocket> {
|
||||||
try {
|
try {
|
||||||
this.instance.authState = await this.defineAuthState();
|
this.instance.authState = await this.defineAuthState();
|
||||||
|
@ -44,7 +44,8 @@ export class BusinessStartupService extends WAStartupService {
|
|||||||
|
|
||||||
public stateConnection: wa.StateConnection = { state: 'open' };
|
public stateConnection: wa.StateConnection = { state: 'open' };
|
||||||
|
|
||||||
private phoneNumber: string;
|
public phoneNumber: string;
|
||||||
|
public mobile: boolean;
|
||||||
|
|
||||||
public get connectionStatus() {
|
public get connectionStatus() {
|
||||||
this.logger.verbose('Getting connection status');
|
this.logger.verbose('Getting connection status');
|
||||||
@ -1347,4 +1348,7 @@ export class BusinessStartupService extends WAStartupService {
|
|||||||
public async handleLabel() {
|
public async handleLabel() {
|
||||||
throw new BadRequestException('Method not available on WhatsApp Business API');
|
throw new BadRequestException('Method not available on WhatsApp Business API');
|
||||||
}
|
}
|
||||||
|
public async receiveMobileCode() {
|
||||||
|
throw new BadRequestException('Method not available on WhatsApp Business API');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user