mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2026-01-13 15:22:32 -06:00
Merge branch 'develop' into feat/add-async-lock
This commit is contained in:
@@ -99,6 +99,7 @@ import makeWASocket, {
|
||||
Contact,
|
||||
delay,
|
||||
DisconnectReason,
|
||||
downloadContentFromMessage,
|
||||
downloadMediaMessage,
|
||||
generateWAMessageFromContent,
|
||||
getAggregateVotesInPollMessage,
|
||||
@@ -122,7 +123,7 @@ import makeWASocket, {
|
||||
WABrowserDescription,
|
||||
WAMediaUpload,
|
||||
WAMessage,
|
||||
WAMessageUpdate,
|
||||
WAMessageKey,
|
||||
WAPresence,
|
||||
WASocket,
|
||||
} from 'baileys';
|
||||
@@ -894,7 +895,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
}: {
|
||||
chats: Chat[];
|
||||
contacts: Contact[];
|
||||
messages: proto.IWebMessageInfo[];
|
||||
messages: WAMessage[];
|
||||
isLatest?: boolean;
|
||||
progress?: number;
|
||||
syncType?: proto.HistorySync.HistorySyncType;
|
||||
@@ -980,6 +981,10 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.key.remoteJid?.includes('@lid') && m.key.senderPn) {
|
||||
m.key.remoteJid = m.key.senderPn;
|
||||
}
|
||||
|
||||
if (Long.isLong(m?.messageTimestamp)) {
|
||||
m.messageTimestamp = m.messageTimestamp?.toNumber();
|
||||
}
|
||||
@@ -1037,11 +1042,29 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
},
|
||||
|
||||
'messages.upsert': async (
|
||||
{ messages, type, requestId }: { messages: proto.IWebMessageInfo[]; type: MessageUpsertType; requestId?: string },
|
||||
{ messages, type, requestId }: { messages: WAMessage[]; type: MessageUpsertType; requestId?: string },
|
||||
settings: any,
|
||||
) => {
|
||||
try {
|
||||
for (const received of messages) {
|
||||
if (received.key.remoteJid?.includes('@lid') && received.key.senderPn) {
|
||||
(received.key as { previousRemoteJid?: string | null }).previousRemoteJid = received.key.remoteJid;
|
||||
received.key.remoteJid = received.key.senderPn;
|
||||
}
|
||||
if (
|
||||
received?.messageStubParameters?.some?.((param) =>
|
||||
[
|
||||
'No matching sessions found for message',
|
||||
'Bad MAC',
|
||||
'failed to decrypt message',
|
||||
'SessionError',
|
||||
'Invalid PreKey ID',
|
||||
].some((err) => param?.includes?.(err)),
|
||||
)
|
||||
) {
|
||||
this.logger.warn(`Message ignored with messageStubParameters: ${JSON.stringify(received, null, 2)}`);
|
||||
continue;
|
||||
}
|
||||
if (received.message?.conversation || received.message?.extendedTextMessage?.text) {
|
||||
const text = received.message?.conversation || received.message?.extendedTextMessage?.text;
|
||||
|
||||
@@ -1233,33 +1256,41 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
if (this.configService.get<S3>('S3').ENABLE) {
|
||||
try {
|
||||
const message: any = received;
|
||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||
|
||||
const { buffer, mediaType, fileName, size } = media;
|
||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||
const fullName = join(
|
||||
`${this.instance.id}`,
|
||||
received.key.remoteJid,
|
||||
mediaType,
|
||||
`${Date.now()}_${fileName}`,
|
||||
);
|
||||
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { 'Content-Type': mimetype });
|
||||
// Verificação adicional para garantir que há conteúdo de mídia real
|
||||
const hasRealMedia = this.hasValidMediaContent(message);
|
||||
|
||||
await this.prismaRepository.media.create({
|
||||
data: {
|
||||
messageId: msg.id,
|
||||
instanceId: this.instanceId,
|
||||
type: mediaType,
|
||||
fileName: fullName,
|
||||
mimetype,
|
||||
},
|
||||
});
|
||||
if (!hasRealMedia) {
|
||||
this.logger.warn('Message detected as media but contains no valid media content');
|
||||
} else {
|
||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||
|
||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||
const { buffer, mediaType, fileName, size } = media;
|
||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||
const fullName = join(
|
||||
`${this.instance.id}`,
|
||||
received.key.remoteJid,
|
||||
mediaType,
|
||||
`${Date.now()}_${fileName}`,
|
||||
);
|
||||
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { 'Content-Type': mimetype });
|
||||
|
||||
messageRaw.message.mediaUrl = mediaUrl;
|
||||
await this.prismaRepository.media.create({
|
||||
data: {
|
||||
messageId: msg.id,
|
||||
instanceId: this.instanceId,
|
||||
type: mediaType,
|
||||
fileName: fullName,
|
||||
mimetype,
|
||||
},
|
||||
});
|
||||
|
||||
await this.prismaRepository.message.update({ where: { id: msg.id }, data: messageRaw });
|
||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||
|
||||
messageRaw.message.mediaUrl = mediaUrl;
|
||||
|
||||
await this.prismaRepository.message.update({ where: { id: msg.id }, data: messageRaw });
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
|
||||
}
|
||||
@@ -1363,7 +1394,7 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
}
|
||||
},
|
||||
|
||||
'messages.update': async (args: WAMessageUpdate[], settings: any) => {
|
||||
'messages.update': async (args: { update: Partial<WAMessage>; key: WAMessageKey }[], settings: any) => {
|
||||
this.logger.log(`Update messages ${JSON.stringify(args, undefined, 2)}`);
|
||||
|
||||
const readChatToUpdate: Record<string, true> = {}; // {remoteJid: true}
|
||||
@@ -1373,6 +1404,10 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.remoteJid?.includes('@lid') && key.senderPn) {
|
||||
key.remoteJid = key.senderPn;
|
||||
}
|
||||
|
||||
const updateKey = `${this.instance.id}_${key.id}_${update.status}`;
|
||||
|
||||
const cached = await this.baileysCache.get(updateKey);
|
||||
@@ -2130,31 +2165,39 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
if (isMedia && this.configService.get<S3>('S3').ENABLE) {
|
||||
try {
|
||||
const message: any = messageRaw;
|
||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||
|
||||
const { buffer, mediaType, fileName, size } = media;
|
||||
// Verificação adicional para garantir que há conteúdo de mídia real
|
||||
const hasRealMedia = this.hasValidMediaContent(message);
|
||||
|
||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||
if (!hasRealMedia) {
|
||||
this.logger.warn('Message detected as media but contains no valid media content');
|
||||
} else {
|
||||
const media = await this.getBase64FromMediaMessage({ message }, true);
|
||||
|
||||
const fullName = join(
|
||||
`${this.instance.id}`,
|
||||
messageRaw.key.remoteJid,
|
||||
`${messageRaw.key.id}`,
|
||||
mediaType,
|
||||
fileName,
|
||||
);
|
||||
const { buffer, mediaType, fileName, size } = media;
|
||||
|
||||
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { 'Content-Type': mimetype });
|
||||
const mimetype = mimeTypes.lookup(fileName).toString();
|
||||
|
||||
await this.prismaRepository.media.create({
|
||||
data: { messageId: msg.id, instanceId: this.instanceId, type: mediaType, fileName: fullName, mimetype },
|
||||
});
|
||||
const fullName = join(
|
||||
`${this.instance.id}`,
|
||||
messageRaw.key.remoteJid,
|
||||
`${messageRaw.key.id}`,
|
||||
mediaType,
|
||||
fileName,
|
||||
);
|
||||
|
||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { 'Content-Type': mimetype });
|
||||
|
||||
messageRaw.message.mediaUrl = mediaUrl;
|
||||
await this.prismaRepository.media.create({
|
||||
data: { messageId: msg.id, instanceId: this.instanceId, type: mediaType, fileName: fullName, mimetype },
|
||||
});
|
||||
|
||||
await this.prismaRepository.message.update({ where: { id: msg.id }, data: messageRaw });
|
||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||
|
||||
messageRaw.message.mediaUrl = mediaUrl;
|
||||
|
||||
await this.prismaRepository.message.update({ where: { id: msg.id }, data: messageRaw });
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
|
||||
}
|
||||
@@ -3422,6 +3465,18 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
}
|
||||
}
|
||||
|
||||
public async mapMediaType(mediaType) {
|
||||
const map = {
|
||||
imageMessage: 'image',
|
||||
videoMessage: 'video',
|
||||
documentMessage: 'document',
|
||||
stickerMessage: 'sticker',
|
||||
audioMessage: 'audio',
|
||||
ptvMessage: 'video',
|
||||
};
|
||||
return map[mediaType] || null;
|
||||
}
|
||||
|
||||
public async getBase64FromMediaMessage(data: getBase64FromMediaMessageDto, getBuffer = false) {
|
||||
try {
|
||||
const m = data?.message;
|
||||
@@ -3446,28 +3501,76 @@ export class BaileysStartupService extends ChannelStartupService {
|
||||
let mediaMessage: any;
|
||||
let mediaType: string;
|
||||
|
||||
for (const type of TypeMediaMessage) {
|
||||
mediaMessage = msg.message[type];
|
||||
if (mediaMessage) {
|
||||
mediaType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msg.message?.templateMessage) {
|
||||
const template =
|
||||
msg.message.templateMessage.hydratedTemplate || msg.message.templateMessage.hydratedFourRowTemplate;
|
||||
|
||||
if (!mediaMessage) {
|
||||
throw 'The message is not of the media type';
|
||||
for (const type of TypeMediaMessage) {
|
||||
if (template[type]) {
|
||||
mediaMessage = template[type];
|
||||
mediaType = type;
|
||||
msg.message = { [type]: { ...template[type], url: template[type].staticUrl } };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mediaMessage) {
|
||||
throw 'Template message does not contain a supported media type';
|
||||
}
|
||||
} else {
|
||||
for (const type of TypeMediaMessage) {
|
||||
mediaMessage = msg.message[type];
|
||||
if (mediaMessage) {
|
||||
mediaType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mediaMessage) {
|
||||
throw 'The message is not of the media type';
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof mediaMessage['mediaKey'] === 'object') {
|
||||
msg.message = JSON.parse(JSON.stringify(msg.message));
|
||||
}
|
||||
|
||||
const buffer = await downloadMediaMessage(
|
||||
{ key: msg?.key, message: msg?.message },
|
||||
'buffer',
|
||||
{},
|
||||
{ logger: P({ level: 'error' }) as any, reuploadRequest: this.client.updateMediaMessage },
|
||||
);
|
||||
let buffer: Buffer;
|
||||
|
||||
try {
|
||||
buffer = await downloadMediaMessage(
|
||||
{ key: msg?.key, message: msg?.message },
|
||||
'buffer',
|
||||
{},
|
||||
{ logger: P({ level: 'error' }) as any, reuploadRequest: this.client.updateMediaMessage },
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.error('Download Media failed, trying to retry in 5 seconds...');
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
const mediaType = Object.keys(msg.message).find((key) => key.endsWith('Message'));
|
||||
if (!mediaType) throw new Error('Could not determine mediaType for fallback');
|
||||
|
||||
try {
|
||||
const media = await downloadContentFromMessage(
|
||||
{
|
||||
mediaKey: msg.message?.[mediaType]?.mediaKey,
|
||||
directPath: msg.message?.[mediaType]?.directPath,
|
||||
url: `https://mmg.whatsapp.net${msg?.message?.[mediaType]?.directPath}`,
|
||||
},
|
||||
await this.mapMediaType(mediaType),
|
||||
{},
|
||||
);
|
||||
const chunks = [];
|
||||
for await (const chunk of media) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
buffer = Buffer.concat(chunks);
|
||||
this.logger.info('Download Media with downloadContentFromMessage was successful!');
|
||||
} catch (fallbackErr) {
|
||||
this.logger.error('Download Media with downloadContentFromMessage also failed!');
|
||||
throw fallbackErr;
|
||||
}
|
||||
}
|
||||
const typeMessage = getContentType(msg.message);
|
||||
|
||||
const ext = mimeTypes.extension(mediaMessage?.['mimetype']);
|
||||
|
||||
Reference in New Issue
Block a user