[core] Apply pre-commit with prettier
This commit is contained in:
1 parent
2af3940be7
commit
bf615efa96
33 files changed
+2276
-2083
No files matched your search
+128
-118
@@ -1,141 +1,151 @@
|
||||
import {Body, Controller, Get, Post, Put, Query} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import { Body, Controller, Get, Post, Put, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery, GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextQuery,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest, SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextQuery,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api')
|
||||
@ApiTags('chatting')
|
||||
export class ChattingController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/checkNumberStatus')
|
||||
@ApiOperation({summary: 'Check number status'})
|
||||
async checkNumberStatus(@Query() request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.checkNumberStatus(request)
|
||||
}
|
||||
@Get('/checkNumberStatus')
|
||||
@ApiOperation({ summary: 'Check number status' })
|
||||
async checkNumberStatus(
|
||||
@Query() request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.checkNumberStatus(request);
|
||||
}
|
||||
|
||||
@Post('/sendContactVcard')
|
||||
sendContactVcard(@Body() request: MessageContactVcardRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendContactVCard(request)
|
||||
}
|
||||
@Post('/sendContactVcard')
|
||||
sendContactVcard(@Body() request: MessageContactVcardRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendContactVCard(request);
|
||||
}
|
||||
|
||||
@Get('/sendText')
|
||||
@ApiOperation({summary: 'Send a text message'})
|
||||
sendTextGet(
|
||||
@Query() query: MessageTextQuery,
|
||||
) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
const msg = new MessageTextRequest()
|
||||
msg.chatId = query.phone
|
||||
msg.text = query.text
|
||||
return whatsapp.sendText(msg)
|
||||
}
|
||||
@Get('/sendText')
|
||||
@ApiOperation({ summary: 'Send a text message' })
|
||||
sendTextGet(@Query() query: MessageTextQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
const msg = new MessageTextRequest();
|
||||
msg.chatId = query.phone;
|
||||
msg.text = query.text;
|
||||
return whatsapp.sendText(msg);
|
||||
}
|
||||
|
||||
@Post('/sendText')
|
||||
@ApiOperation({summary: 'Send a text message'})
|
||||
sendText(@Body() request: MessageTextRequest): Promise<WAMessage> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendText(request)
|
||||
}
|
||||
@Post('/sendText')
|
||||
@ApiOperation({ summary: 'Send a text message' })
|
||||
sendText(@Body() request: MessageTextRequest): Promise<WAMessage> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendText(request);
|
||||
}
|
||||
|
||||
@Post('/sendTextButtons')
|
||||
@ApiOperation({summary: 'Send a text message with buttons'})
|
||||
sendTextButtons(@Body() request: MessageTextButtonsRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendTextButtons(request)
|
||||
}
|
||||
@Post('/sendTextButtons')
|
||||
@ApiOperation({ summary: 'Send a text message with buttons' })
|
||||
sendTextButtons(@Body() request: MessageTextButtonsRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendTextButtons(request);
|
||||
}
|
||||
|
||||
@Post('/sendLocation')
|
||||
sendLocation(@Body() request: MessageLocationRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendLocation(request)
|
||||
}
|
||||
@Post('/sendLocation')
|
||||
sendLocation(@Body() request: MessageLocationRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendLocation(request);
|
||||
}
|
||||
|
||||
@Post('/sendLinkPreview')
|
||||
sendLinkPreview(@Body() request: MessageLinkPreviewRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendLinkPreview(request)
|
||||
}
|
||||
@Post('/sendLinkPreview')
|
||||
sendLinkPreview(@Body() request: MessageLinkPreviewRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendLinkPreview(request);
|
||||
}
|
||||
|
||||
@Post('/sendImage')
|
||||
@ApiOperation({summary: "Send an image. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendImage(@Body() request: MessageImageRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendImage(request)
|
||||
}
|
||||
@Post('/sendImage')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send an image. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendImage(@Body() request: MessageImageRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendImage(request);
|
||||
}
|
||||
|
||||
@Post('/sendFile')
|
||||
@ApiOperation({summary: "Send a file. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendFile(@Body() request: MessageFileRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendFile(request)
|
||||
}
|
||||
@Post('/sendFile')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send a file. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendFile(@Body() request: MessageFileRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendFile(request);
|
||||
}
|
||||
|
||||
@Post('/sendVoice')
|
||||
@ApiOperation({summary: "Send an voice message. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendVoice(@Body() request: MessageVoiceRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendVoice(request)
|
||||
}
|
||||
@Post('/sendVoice')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send an voice message. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendVoice(@Body() request: MessageVoiceRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendVoice(request);
|
||||
}
|
||||
|
||||
@Post('/reply')
|
||||
@ApiOperation({summary: 'Reply to a text message'})
|
||||
reply(@Body() request: MessageReplyRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.reply(request)
|
||||
}
|
||||
@Post('/reply')
|
||||
@ApiOperation({ summary: 'Reply to a text message' })
|
||||
reply(@Body() request: MessageReplyRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.reply(request);
|
||||
}
|
||||
|
||||
@Post('/sendSeen')
|
||||
sendSeen(@Body() chat: SendSeenRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
return whatsapp.sendSeen(chat)
|
||||
}
|
||||
@Post('/sendSeen')
|
||||
sendSeen(@Body() chat: SendSeenRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
return whatsapp.sendSeen(chat);
|
||||
}
|
||||
|
||||
@Post('/startTyping')
|
||||
async startTyping(@Body() chat: ChatRequest) {
|
||||
// It's infinitive action
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
await whatsapp.startTyping(chat)
|
||||
return {result: true}
|
||||
}
|
||||
@Post('/startTyping')
|
||||
async startTyping(@Body() chat: ChatRequest) {
|
||||
// It's infinitive action
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
await whatsapp.startTyping(chat);
|
||||
return { result: true };
|
||||
}
|
||||
|
||||
@Post('/stopTyping')
|
||||
async stopTyping(@Body() chat: ChatRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
await whatsapp.stopTyping(chat)
|
||||
return {result: true}
|
||||
}
|
||||
@Post('/stopTyping')
|
||||
async stopTyping(@Body() chat: ChatRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
await whatsapp.stopTyping(chat);
|
||||
return { result: true };
|
||||
}
|
||||
|
||||
@Put('/reaction')
|
||||
@ApiOperation({summary: 'React to a message with an emoji'})
|
||||
setReaction(@Body() request: MessageReactionRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.setReaction(request)
|
||||
}
|
||||
@Put('/reaction')
|
||||
@ApiOperation({ summary: 'React to a message with an emoji' })
|
||||
setReaction(@Body() request: MessageReactionRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.setReaction(request);
|
||||
}
|
||||
|
||||
@Get('/messages')
|
||||
@ApiOperation({summary: 'Get messages in a chat'})
|
||||
getMessages( @Query() query: GetMessageQuery ) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getMessages(query)
|
||||
}
|
||||
@Get('/messages')
|
||||
@ApiOperation({ summary: 'Get messages in a chat' })
|
||||
getMessages(@Query() query: GetMessageQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getMessages(query);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,73 @@
|
||||
import {Body, Controller, Get, Post, Query} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
|
||||
import {SessionQuery} from "../structures/base.dto";
|
||||
import {CheckNumberStatusQuery} from "../structures/chatting.dto";
|
||||
import {WANumberExistResult} from "../structures/responses.dto";
|
||||
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import { SessionQuery } from '../structures/base.dto';
|
||||
import { CheckNumberStatusQuery } from '../structures/chatting.dto';
|
||||
import { WANumberExistResult } from '../structures/responses.dto';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/contacts')
|
||||
@ApiTags('contacts')
|
||||
export class ContactsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/')
|
||||
@ApiOperation({summary: 'Get contact basic info. The method always return result, even if the phone number is not registered in WhatsApp. For that - use /check-exists endpoint below.'})
|
||||
get(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContact(query)
|
||||
}
|
||||
@Get('/')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Get contact basic info. The method always return result, even if the phone number is not registered in WhatsApp. For that - use /check-exists endpoint below.',
|
||||
})
|
||||
get(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContact(query);
|
||||
}
|
||||
|
||||
@Get('/all')
|
||||
@ApiOperation({summary: 'Get all contacts'})
|
||||
getAll(@Query() query: SessionQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContacts()
|
||||
}
|
||||
@Get('/all')
|
||||
@ApiOperation({ summary: 'Get all contacts' })
|
||||
getAll(@Query() query: SessionQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContacts();
|
||||
}
|
||||
|
||||
@Get('/check-exists')
|
||||
@ApiOperation({summary: 'Check phone number is registered in WhatsApp.'})
|
||||
async checkExists(@Query() request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.checkNumberStatus(request)
|
||||
}
|
||||
@Get('/check-exists')
|
||||
@ApiOperation({ summary: 'Check phone number is registered in WhatsApp.' })
|
||||
async checkExists(
|
||||
@Query() request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.checkNumberStatus(request);
|
||||
}
|
||||
|
||||
@Get('/about')
|
||||
@ApiOperation({summary: 'Gets the Contact\'s current "about" info. Returns null if you don\'t have permission to read their status.'})
|
||||
getAbout(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContactAbout(query)
|
||||
}
|
||||
@Get('/about')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Gets the Contact\'s current "about" info. Returns null if you don\'t have permission to read their status.',
|
||||
})
|
||||
getAbout(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContactAbout(query);
|
||||
}
|
||||
|
||||
@Get('/profile-picture')
|
||||
@ApiOperation({summary: 'Returns the contact\'s profile picture URL, if privacy settings allow it.'})
|
||||
getProfilePicture(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContactProfilePicture(query)
|
||||
}
|
||||
@Get('/profile-picture')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Returns the contact's profile picture URL, if privacy settings allow it.",
|
||||
})
|
||||
getProfilePicture(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContactProfilePicture(query);
|
||||
}
|
||||
|
||||
@Post('/block')
|
||||
@ApiOperation({summary:"Block contact"})
|
||||
block(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.blockContact(request)
|
||||
}
|
||||
@Post('/unblock')
|
||||
@ApiOperation({summary:"Unblock contact"})
|
||||
unblock(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.unblockContact(request)
|
||||
}
|
||||
@Post('/block')
|
||||
@ApiOperation({ summary: 'Block contact' })
|
||||
block(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.blockContact(request);
|
||||
}
|
||||
@Post('/unblock')
|
||||
@ApiOperation({ summary: 'Unblock contact' })
|
||||
unblock(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.unblockContact(request);
|
||||
}
|
||||
}
|
||||
+35
-35
@@ -1,6 +1,12 @@
|
||||
import {ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus,} from '@nestjs/common';
|
||||
import {Request, Response} from 'express';
|
||||
import {VERSION} from "../version";
|
||||
import {
|
||||
ArgumentsHost,
|
||||
Catch,
|
||||
ExceptionFilter,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request, Response } from 'express';
|
||||
import { VERSION } from '../version';
|
||||
|
||||
/**
|
||||
* Serializer error to JSON.
|
||||
@@ -8,42 +14,36 @@ import {VERSION} from "../version";
|
||||
* Credits: https://stackoverflow.com/a/72707578/6753144
|
||||
*/
|
||||
export function serializeError(err: unknown) {
|
||||
const properties = Object.getOwnPropertyNames(err)
|
||||
// getOwnPropertyNames does not get 'name', like "ReferenceError"
|
||||
properties.push('name')
|
||||
return JSON.parse(JSON.stringify(err, properties))
|
||||
const properties = Object.getOwnPropertyNames(err);
|
||||
// getOwnPropertyNames does not get 'name', like "ReferenceError"
|
||||
properties.push('name');
|
||||
return JSON.parse(JSON.stringify(err, properties));
|
||||
}
|
||||
|
||||
@Catch()
|
||||
export class AllExceptionsFilter implements ExceptionFilter {
|
||||
catch(exception: HttpException | Error, host: ArgumentsHost): void {
|
||||
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
|
||||
if (exception instanceof HttpException) {
|
||||
response
|
||||
.status(exception.getStatus())
|
||||
.json(exception.getResponse());
|
||||
return
|
||||
}
|
||||
|
||||
const httpStatus = HttpStatus.INTERNAL_SERVER_ERROR
|
||||
response
|
||||
.status(httpStatus)
|
||||
.json({
|
||||
statusCode: httpStatus,
|
||||
timestamp: new Date().toISOString(),
|
||||
exception: serializeError(exception),
|
||||
request: {
|
||||
path: request.url,
|
||||
method: request.method,
|
||||
body: request.body,
|
||||
query: request.query,
|
||||
},
|
||||
version: VERSION,
|
||||
});
|
||||
catch(exception: HttpException | Error, host: ArgumentsHost): void {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
|
||||
if (exception instanceof HttpException) {
|
||||
response.status(exception.getStatus()).json(exception.getResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
const httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
response.status(httpStatus).json({
|
||||
statusCode: httpStatus,
|
||||
timestamp: new Date().toISOString(),
|
||||
exception: serializeError(exception),
|
||||
request: {
|
||||
path: request.url,
|
||||
method: request.method,
|
||||
body: request.body,
|
||||
query: request.query,
|
||||
},
|
||||
version: VERSION,
|
||||
});
|
||||
}
|
||||
}
|
||||
+153
-145
@@ -1,165 +1,173 @@
|
||||
import {Body, Controller, Delete, Get, Param, Post, Put} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {CreateGroupRequest, DescriptionRequest, ParticipantsRequest, SubjectRequest} from "../structures/groups.dto";
|
||||
import {WhatsappSession} from "../core/abc/session.abc";
|
||||
import {SessionApiParam, SessionParam} from "./helpers";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
DescriptionRequest,
|
||||
ParticipantsRequest,
|
||||
SubjectRequest,
|
||||
} from '../structures/groups.dto';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
import { SessionApiParam, SessionParam } from './helpers';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/:session/groups')
|
||||
@ApiTags('groups')
|
||||
export class GroupsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Post('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Create a new group."})
|
||||
createGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() request: CreateGroupRequest,
|
||||
) {
|
||||
return session.createGroup(request)
|
||||
}
|
||||
@Post('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Create a new group.' })
|
||||
createGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() request: CreateGroupRequest,
|
||||
) {
|
||||
return session.createGroup(request);
|
||||
}
|
||||
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Get all groups."})
|
||||
getGroups(
|
||||
@SessionParam session: WhatsappSession,
|
||||
) {
|
||||
return session.getGroups()
|
||||
}
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get all groups.' })
|
||||
getGroups(@SessionParam session: WhatsappSession) {
|
||||
return session.getGroups();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Get the group."})
|
||||
getGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getGroup(id)
|
||||
}
|
||||
@Get(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get the group.' })
|
||||
getGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.getGroup(id);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Delete the group."})
|
||||
deleteGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.deleteGroup(id)
|
||||
}
|
||||
@Delete(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Delete the group.' })
|
||||
deleteGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.deleteGroup(id);
|
||||
}
|
||||
|
||||
@Post(':id/leave')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Leave the group."})
|
||||
leaveGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.leaveGroup(id)
|
||||
}
|
||||
@Post(':id/leave')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Leave the group.' })
|
||||
leaveGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.leaveGroup(id);
|
||||
}
|
||||
|
||||
@Put(':id/description')
|
||||
@ApiOperation({
|
||||
summary: "Updates the group description.\n" +
|
||||
"Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n"
|
||||
})
|
||||
@SessionApiParam
|
||||
setDescription(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: DescriptionRequest
|
||||
) {
|
||||
return session.setDescription(id, request.description)
|
||||
}
|
||||
@Put(':id/description')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Updates the group description.\n' +
|
||||
'Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n',
|
||||
})
|
||||
@SessionApiParam
|
||||
setDescription(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: DescriptionRequest,
|
||||
) {
|
||||
return session.setDescription(id, request.description);
|
||||
}
|
||||
|
||||
@Put(':id/subject')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: "Updates the group subject.\n" +
|
||||
"Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n"
|
||||
})
|
||||
setSubject(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: SubjectRequest
|
||||
) {
|
||||
return session.setSubject(id, request.subject)
|
||||
}
|
||||
@Put(':id/subject')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Updates the group subject.\n' +
|
||||
'Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n',
|
||||
})
|
||||
setSubject(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: SubjectRequest,
|
||||
) {
|
||||
return session.setSubject(id, request.subject);
|
||||
}
|
||||
|
||||
@Get(':id/invite-code')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Gets the invite code for a specific group."})
|
||||
getInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.getInviteCode(id)
|
||||
}
|
||||
@Get(':id/invite-code')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Gets the invite code for a specific group.' })
|
||||
getInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.getInviteCode(id);
|
||||
}
|
||||
|
||||
@Post(':id/invite-code/revoke')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Invalidates the current group invite code and generates a new one."})
|
||||
revokeInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.revokeInviteCode(id)
|
||||
}
|
||||
@Post(':id/invite-code/revoke')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Invalidates the current group invite code and generates a new one.',
|
||||
})
|
||||
revokeInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.revokeInviteCode(id);
|
||||
}
|
||||
|
||||
@Get(':id/participants/')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Get a list of participants by in the group.'})
|
||||
getParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getParticipants(id)
|
||||
}
|
||||
@Get(':id/participants/')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get a list of participants by in the group.' })
|
||||
getParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getParticipants(id);
|
||||
}
|
||||
|
||||
@Post(':id/participants/add')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Adds a list of participants by ID to the group.'})
|
||||
addParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.addParticipants(id, request)
|
||||
}
|
||||
@Post(':id/participants/add')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Adds a list of participants by ID to the group.' })
|
||||
addParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.addParticipants(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/participants/remove')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Removes a list of participants by ID to the group.'})
|
||||
removeParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.removeParticipants(id, request)
|
||||
}
|
||||
@Post(':id/participants/remove')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: 'Removes a list of participants by ID to the group.',
|
||||
})
|
||||
removeParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.removeParticipants(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/admin/promote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Promote participants to admin users.'})
|
||||
promoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.promoteParticipantsToAdmin(id, request)
|
||||
}
|
||||
@Post(':id/admin/promote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Promote participants to admin users.' })
|
||||
promoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.promoteParticipantsToAdmin(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/admin/demote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Demotes participants by to regular users.'})
|
||||
demoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.demoteParticipantsToUser(id, request)
|
||||
}
|
||||
@Post(':id/admin/demote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Demotes participants by to regular users.' })
|
||||
demoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.demoteParticipantsToUser(id, request);
|
||||
}
|
||||
}
|
||||
+14
-16
@@ -1,7 +1,7 @@
|
||||
import { ApiParam } from "@nestjs/swagger";
|
||||
import { Injectable, Param, PipeTransform } from "@nestjs/common";
|
||||
import { SessionManager } from "../core/abc/manager.abc";
|
||||
import { WhatsappSession } from "../core/abc/session.abc";
|
||||
import { ApiParam } from '@nestjs/swagger';
|
||||
import { Injectable, Param, PipeTransform } from '@nestjs/common';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
|
||||
/**
|
||||
* Get session name and return Whatsapp session back (if exists)
|
||||
@@ -10,27 +10,25 @@ import { WhatsappSession } from "../core/abc/session.abc";
|
||||
*/
|
||||
@Injectable()
|
||||
export class SessionPipe implements PipeTransform<WhatsappSession> {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
async transform(value: any) {
|
||||
return this.manager.getSession(value)
|
||||
}
|
||||
async transform(value: any) {
|
||||
return this.manager.getSession(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorator for a method that uses SessionPipe above
|
||||
*/
|
||||
export const SessionApiParam = ApiParam({
|
||||
name: 'session',
|
||||
required: true,
|
||||
type: "string",
|
||||
description: "WhatsApp session name",
|
||||
})
|
||||
name: 'session',
|
||||
required: true,
|
||||
type: 'string',
|
||||
description: 'WhatsApp session name',
|
||||
});
|
||||
|
||||
/**
|
||||
* Session param
|
||||
@SessionParam session: WhatsappSession,
|
||||
*/
|
||||
export const SessionParam = Param('session', SessionPipe)
|
||||
|
||||
export const SessionParam = Param('session', SessionPipe);
|
||||
@@ -1,34 +1,28 @@
|
||||
import {Controller, Get, Query, Res} from '@nestjs/common';
|
||||
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {Readable} from "stream";
|
||||
import {Response} from 'express';
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {SessionQuery} from "../structures/base.dto";
|
||||
|
||||
import { Controller, Get, Query, Res } from '@nestjs/common';
|
||||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { Readable } from 'stream';
|
||||
import { Response } from 'express';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { SessionQuery } from '../structures/base.dto';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api')
|
||||
@ApiTags('screenshot')
|
||||
export class ScreenshotController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/screenshot')
|
||||
async screenshot(
|
||||
@Res() res: Response,
|
||||
@Query() sessionQuery: SessionQuery,
|
||||
) {
|
||||
const whatsappService = this.manager.getSession(sessionQuery.session)
|
||||
const buffer = await whatsappService.getScreenshot();
|
||||
const stream = new Readable();
|
||||
stream.push(buffer);
|
||||
stream.push(null);
|
||||
@Get('/screenshot')
|
||||
async screenshot(@Res() res: Response, @Query() sessionQuery: SessionQuery) {
|
||||
const whatsappService = this.manager.getSession(sessionQuery.session);
|
||||
const buffer = await whatsappService.getScreenshot();
|
||||
const stream = new Readable();
|
||||
stream.push(buffer);
|
||||
stream.push(null);
|
||||
|
||||
res.set({
|
||||
'Content-Type': 'image/png',
|
||||
'Content-Length': buffer.length,
|
||||
});
|
||||
stream.pipe(res)
|
||||
}
|
||||
res.set({
|
||||
'Content-Type': 'image/png',
|
||||
'Content-Length': buffer.length,
|
||||
});
|
||||
stream.pipe(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,52 @@
|
||||
import { Body, Controller, Get, Post, Query } from "@nestjs/common";
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from "@nestjs/swagger";
|
||||
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest,
|
||||
ListSessionsQuery
|
||||
} from "../structures/sessions.dto";
|
||||
import { SessionManager } from "../core/abc/manager.abc";
|
||||
import { UnprocessableEntityException } from "@nestjs/common/exceptions/unprocessable-entity.exception";
|
||||
import { parseBool } from "../helpers";
|
||||
ListSessionsQuery,
|
||||
} from '../structures/sessions.dto';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import { parseBool } from '../helpers';
|
||||
|
||||
|
||||
@ApiSecurity("api_key")
|
||||
@Controller("api/sessions")
|
||||
@ApiTags("sessions")
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/sessions')
|
||||
@ApiTags('sessions')
|
||||
export class SessionsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Post("/start/")
|
||||
@Post('/start/')
|
||||
start(@Body() request: SessionStartRequest): SessionDTO {
|
||||
return this.manager.start(request);
|
||||
}
|
||||
|
||||
@Post("/stop/")
|
||||
@ApiOperation({summary: 'Stop session'})
|
||||
@Post('/stop/')
|
||||
@ApiOperation({ summary: 'Stop session' })
|
||||
async stop(@Body() request: SessionStopRequest): Promise<void> {
|
||||
await this.manager.stop(request);
|
||||
if (request.logout){
|
||||
if (request.logout) {
|
||||
await this.manager.logout(request);
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
@Post("/logout/")
|
||||
@ApiOperation({summary: 'Logout from session.'})
|
||||
@Post('/logout/')
|
||||
@ApiOperation({ summary: 'Logout from session.' })
|
||||
clean(@Body() request: SessionLogoutRequest): Promise<void> {
|
||||
const session = this.manager.getSession(request.name, false);
|
||||
if (session) {
|
||||
throw new UnprocessableEntityException(
|
||||
`Can not clean running session, please stop it first. You can set 'clean' field to 'True' in stop request so it stops and cleans at the same time.`
|
||||
`Can not clean running session, please stop it first. You can set 'clean' field to 'True' in stop request so it stops and cleans at the same time.`,
|
||||
);
|
||||
}
|
||||
return this.manager.logout(request);
|
||||
}
|
||||
|
||||
@Get("/")
|
||||
@Get('/')
|
||||
list(@Query() query: ListSessionsQuery): SessionDTO[] {
|
||||
const all = parseBool(query.all)
|
||||
const all = parseBool(query.all);
|
||||
return this.manager.getSessions(all);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import {Controller, Get} from '@nestjs/common';
|
||||
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {VERSION} from "../version";
|
||||
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { VERSION } from '../version';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/version')
|
||||
@ApiTags('other')
|
||||
export class VersionController {
|
||||
@Get('')
|
||||
async get() {
|
||||
return VERSION
|
||||
}
|
||||
@Get('')
|
||||
async get() {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
+92
-93
@@ -1,104 +1,103 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { WhatsappEngine } from "./structures/enums.dto";
|
||||
import { parseBool } from "./helpers";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { WhatsappEngine } from './structures/enums.dto';
|
||||
import { parseBool } from './helpers';
|
||||
|
||||
@Injectable()
|
||||
export class WhatsappConfigService {
|
||||
public files_uri = '/api/files'
|
||||
public schema = "http"
|
||||
public files_uri = '/api/files';
|
||||
public schema = 'http';
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
get filesURL(): string {
|
||||
return `${this.schema}://${this.hostname}:${this.port}${this.files_uri}/`;
|
||||
}
|
||||
|
||||
get hostname(): string {
|
||||
return this.configService.get('WHATSAPP_API_HOSTNAME', 'localhost');
|
||||
}
|
||||
|
||||
get port(): string {
|
||||
return this.configService.get('WHATSAPP_API_PORT', '3000');
|
||||
}
|
||||
|
||||
get filesFolder(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_FILES_FOLDER',
|
||||
'/tmp/whatsapp-files',
|
||||
);
|
||||
}
|
||||
|
||||
get filesLifetime(): number {
|
||||
return this.configService.get<number>('WHATSAPP_FILES_LIFETIME', 180);
|
||||
}
|
||||
|
||||
get mimetypes(): string[] | null {
|
||||
const types = this.configService.get('WHATSAPP_FILES_MIMETYPES', '');
|
||||
return types ? types.split(',') : null;
|
||||
}
|
||||
|
||||
get startSessions(): string[] {
|
||||
const value: string = this.configService.get('WHATSAPP_START_SESSION', '');
|
||||
if (!value) {
|
||||
return [];
|
||||
}
|
||||
return value.split(',');
|
||||
}
|
||||
|
||||
get filesURL(): string {
|
||||
return `${this.schema}://${this.hostname}:${this.port}${this.files_uri}/`
|
||||
get shouldRestartAllSessions(): boolean {
|
||||
const value: string = this.configService.get(
|
||||
'WHATSAPP_RESTART_ALL_SESSIONS',
|
||||
'false',
|
||||
);
|
||||
return parseBool(value);
|
||||
}
|
||||
|
||||
getWebhookUrl(): string | undefined {
|
||||
return this.get('WHATSAPP_HOOK_URL');
|
||||
}
|
||||
|
||||
getWebhookEvents(): string[] {
|
||||
const value = this.get('WHATSAPP_HOOK_EVENTS', '');
|
||||
return value ? value.split(',') : [];
|
||||
}
|
||||
|
||||
getDefaultEngineName(): WhatsappEngine {
|
||||
const value = this.get('WHATSAPP_DEFAULT_ENGINE', WhatsappEngine.WEBJS);
|
||||
if (value in WhatsappEngine) {
|
||||
return WhatsappEngine[value];
|
||||
}
|
||||
console.log(
|
||||
`Unknown WhatsApp default engine, using WEBJS. WHATSAPP_DEFAULT_ENGINE=${value}`,
|
||||
);
|
||||
}
|
||||
|
||||
get hostname(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_API_HOSTNAME',
|
||||
'localhost',
|
||||
)
|
||||
get(name: string, defaultValue = undefined): any {
|
||||
return this.configService.get(name, defaultValue);
|
||||
}
|
||||
|
||||
getApiKey(): string | undefined {
|
||||
return this.configService.get('WHATSAPP_API_KEY', '');
|
||||
}
|
||||
|
||||
getSwaggerUsernamePassword(): [string, string] | undefined {
|
||||
const user = this.configService.get('WHATSAPP_SWAGGER_USERNAME', undefined);
|
||||
const password = this.configService.get(
|
||||
'WHATSAPP_SWAGGER_PASSWORD',
|
||||
undefined,
|
||||
);
|
||||
if (!user && !password) {
|
||||
console.log(
|
||||
'Please set up both WHATSAPP_SWAGGER_USERNAME and WHATSAPP_SWAGGER_PASSWORD ' +
|
||||
'to enable swagger authentication.',
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
return [user, password];
|
||||
}
|
||||
|
||||
get port(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_API_PORT',
|
||||
'3000',
|
||||
)
|
||||
}
|
||||
|
||||
get filesFolder(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_FILES_FOLDER',
|
||||
'/tmp/whatsapp-files',
|
||||
)
|
||||
}
|
||||
|
||||
get filesLifetime(): number {
|
||||
return this.configService.get<number>(
|
||||
'WHATSAPP_FILES_LIFETIME',
|
||||
180,
|
||||
)
|
||||
}
|
||||
|
||||
get mimetypes(): string[] | null {
|
||||
const types = this.configService.get('WHATSAPP_FILES_MIMETYPES', "")
|
||||
return types ? types.split(',') : null
|
||||
}
|
||||
|
||||
get startSessions(): string[] {
|
||||
const value: string = this.configService.get('WHATSAPP_START_SESSION', "")
|
||||
if (!value){
|
||||
return []
|
||||
}
|
||||
return value.split(",")
|
||||
}
|
||||
|
||||
get shouldRestartAllSessions(): boolean {
|
||||
const value: string = this.configService.get('WHATSAPP_RESTART_ALL_SESSIONS', "false")
|
||||
return parseBool(value)
|
||||
}
|
||||
|
||||
getWebhookUrl(): string | undefined {
|
||||
return this.get('WHATSAPP_HOOK_URL')
|
||||
}
|
||||
|
||||
getWebhookEvents(): string[] {
|
||||
const value = this.get('WHATSAPP_HOOK_EVENTS', "")
|
||||
return value ? value.split(',') : []
|
||||
}
|
||||
|
||||
getDefaultEngineName(): WhatsappEngine {
|
||||
const value = this.get("WHATSAPP_DEFAULT_ENGINE", WhatsappEngine.WEBJS)
|
||||
if (value in WhatsappEngine) {
|
||||
return WhatsappEngine[value]
|
||||
}
|
||||
console.log(`Unknown WhatsApp default engine, using WEBJS. WHATSAPP_DEFAULT_ENGINE=${value}`)
|
||||
|
||||
}
|
||||
|
||||
get(name: string, defaultValue = undefined): any {
|
||||
return this.configService.get(name, defaultValue)
|
||||
}
|
||||
|
||||
getApiKey(): string | undefined {
|
||||
return this.configService.get("WHATSAPP_API_KEY", "")
|
||||
}
|
||||
|
||||
getSwaggerUsernamePassword(): [string, string] | undefined {
|
||||
const user = this.configService.get("WHATSAPP_SWAGGER_USERNAME", undefined)
|
||||
const password = this.configService.get("WHATSAPP_SWAGGER_PASSWORD", undefined)
|
||||
if (!user && !password) {
|
||||
console.log("Please set up both WHATSAPP_SWAGGER_USERNAME and WHATSAPP_SWAGGER_PASSWORD " +
|
||||
"to enable swagger authentication.")
|
||||
return undefined
|
||||
}
|
||||
return [user, password]
|
||||
}
|
||||
|
||||
getSwaggerAdvancedConfigEnabled(): boolean {
|
||||
return this.configService.get("WHATSAPP_SWAGGER_CONFIG_ADVANCED", false)
|
||||
}
|
||||
getSwaggerAdvancedConfigEnabled(): boolean {
|
||||
return this.configService.get('WHATSAPP_SWAGGER_CONFIG_ADVANCED', false);
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,11 +1,11 @@
|
||||
export class QR {
|
||||
private base64: string;
|
||||
private base64: string;
|
||||
|
||||
save(base64) {
|
||||
this.base64 = base64.replace(/^data:image\/png;base64,/, '');
|
||||
}
|
||||
save(base64) {
|
||||
this.base64 = base64.replace(/^data:image\/png;base64,/, '');
|
||||
}
|
||||
|
||||
get(): Buffer {
|
||||
return Buffer.from(this.base64, "base64")
|
||||
}
|
||||
get(): Buffer {
|
||||
return Buffer.from(this.base64, 'base64');
|
||||
}
|
||||
}
|
||||
+17
-19
@@ -1,38 +1,36 @@
|
||||
import { OnApplicationShutdown } from "@nestjs/common";
|
||||
import { OnApplicationShutdown } from '@nestjs/common';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest
|
||||
} from "../../structures/sessions.dto";
|
||||
import { WhatsappSession } from "./session.abc";
|
||||
import { WhatsappEngine } from "../../structures/enums.dto";
|
||||
import { MediaStorage } from "./storage.abc";
|
||||
import { WebhookConductor } from "./webhooks.abc";
|
||||
SessionStopRequest,
|
||||
} from '../../structures/sessions.dto';
|
||||
import { WhatsappSession } from './session.abc';
|
||||
import { WhatsappEngine } from '../../structures/enums.dto';
|
||||
import { MediaStorage } from './storage.abc';
|
||||
import { WebhookConductor } from './webhooks.abc';
|
||||
|
||||
export abstract class SessionManager implements OnApplicationShutdown {
|
||||
protected abstract getEngine(engine: WhatsappEngine): typeof WhatsappSession;
|
||||
|
||||
protected abstract getEngine(engine: WhatsappEngine): typeof WhatsappSession
|
||||
protected abstract get EngineClass(): typeof WhatsappSession;
|
||||
|
||||
protected abstract get EngineClass(): typeof WhatsappSession
|
||||
protected abstract get WebhookConductorClass(): typeof WebhookConductor;
|
||||
|
||||
protected abstract get WebhookConductorClass(): typeof WebhookConductor
|
||||
protected abstract get MediaStorageClass(): typeof MediaStorage;
|
||||
|
||||
protected abstract get MediaStorageClass(): typeof MediaStorage
|
||||
|
||||
abstract onApplicationShutdown(signal ?: string)
|
||||
abstract onApplicationShutdown(signal?: string);
|
||||
|
||||
//
|
||||
// API Methods
|
||||
//
|
||||
abstract start(request: SessionStartRequest): SessionDTO
|
||||
abstract start(request: SessionStartRequest): SessionDTO;
|
||||
|
||||
abstract stop(request: SessionStopRequest): Promise<void>
|
||||
abstract stop(request: SessionStopRequest): Promise<void>;
|
||||
|
||||
abstract logout(request: SessionLogoutRequest): Promise<void>
|
||||
abstract logout(request: SessionLogoutRequest): Promise<void>;
|
||||
|
||||
abstract getSession(name: string, error?: boolean): WhatsappSession
|
||||
abstract getSession(name: string, error?: boolean): WhatsappSession;
|
||||
|
||||
abstract getSessions(all: boolean): SessionDTO[]
|
||||
abstract getSessions(all: boolean): SessionDTO[];
|
||||
}
|
||||
|
||||
+202
-202
@@ -1,264 +1,264 @@
|
||||
import { WAEvents, WhatsappEngine, WhatsappStatus } from "../../structures/enums.dto";
|
||||
import {ConsoleLogger} from "@nestjs/common";
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery, GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest
|
||||
} from "../../structures/chatting.dto";
|
||||
import { LocalSessionStorage, MediaStorage } from "./storage.abc";
|
||||
import {MessageId} from "whatsapp-web.js";
|
||||
import {ContactQuery, ContactRequest} from "../../structures/contacts.dto";
|
||||
import {NotImplementedByEngineError} from "../exceptions";
|
||||
import {CreateGroupRequest, ParticipantsRequest} from "../../structures/groups.dto";
|
||||
import * as fs from "fs";
|
||||
|
||||
const CHROME_PATH = "/usr/bin/google-chrome-stable"
|
||||
const CHROMIUM_PATH = "/usr/bin/chromium"
|
||||
import { EventEmitter } from 'events'
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../../structures/enums.dto';
|
||||
import { ConsoleLogger } from '@nestjs/common';
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
} from '../../structures/chatting.dto';
|
||||
import { LocalSessionStorage, MediaStorage } from './storage.abc';
|
||||
import { MessageId } from 'whatsapp-web.js';
|
||||
import { ContactQuery, ContactRequest } from '../../structures/contacts.dto';
|
||||
import { NotImplementedByEngineError } from '../exceptions';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../../structures/groups.dto';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const CHROME_PATH = '/usr/bin/google-chrome-stable';
|
||||
const CHROMIUM_PATH = '/usr/bin/chromium';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export function getBrowserExecutablePath() {
|
||||
if (fs.existsSync(CHROME_PATH)) {
|
||||
return CHROME_PATH
|
||||
}
|
||||
return CHROMIUM_PATH
|
||||
if (fs.existsSync(CHROME_PATH)) {
|
||||
return CHROME_PATH;
|
||||
}
|
||||
return CHROMIUM_PATH;
|
||||
}
|
||||
export function ensureSuffix(phone) {
|
||||
const suffix = "@c.us"
|
||||
if (phone.includes("@")) {
|
||||
return phone
|
||||
}
|
||||
return phone + suffix
|
||||
const suffix = '@c.us';
|
||||
if (phone.includes('@')) {
|
||||
return phone;
|
||||
}
|
||||
return phone + suffix;
|
||||
}
|
||||
|
||||
export enum WAHAInternalEvent {
|
||||
engine_start = "engine.start",
|
||||
engine_start = 'engine.start',
|
||||
}
|
||||
|
||||
export interface WhatsAppSessionConfig {
|
||||
name: string,
|
||||
storage: MediaStorage,
|
||||
log: ConsoleLogger,
|
||||
sessionStorage: LocalSessionStorage,
|
||||
name: string;
|
||||
storage: MediaStorage;
|
||||
log: ConsoleLogger;
|
||||
sessionStorage: LocalSessionStorage;
|
||||
}
|
||||
|
||||
export abstract class WhatsappSession {
|
||||
public status: WhatsappStatus;
|
||||
public events: EventEmitter
|
||||
public engine: WhatsappEngine
|
||||
public status: WhatsappStatus;
|
||||
public events: EventEmitter;
|
||||
public engine: WhatsappEngine;
|
||||
|
||||
public name: string
|
||||
protected storage: MediaStorage
|
||||
protected log: ConsoleLogger
|
||||
protected sessionStorage: LocalSessionStorage
|
||||
public name: string;
|
||||
protected storage: MediaStorage;
|
||||
protected log: ConsoleLogger;
|
||||
protected sessionStorage: LocalSessionStorage;
|
||||
|
||||
public constructor({ name, log, sessionStorage }: WhatsAppSessionConfig) {
|
||||
this.name = name;
|
||||
this.status = WhatsappStatus.STARTING;
|
||||
this.log = log;
|
||||
this.sessionStorage = sessionStorage;
|
||||
this.events = new EventEmitter();
|
||||
}
|
||||
|
||||
public constructor({name, log, sessionStorage}: WhatsAppSessionConfig ) {
|
||||
this.name = name
|
||||
this.status = WhatsappStatus.STARTING
|
||||
this.log = log
|
||||
this.sessionStorage = sessionStorage
|
||||
this.events = new EventEmitter()
|
||||
}
|
||||
getBrowserExecutablePath() {
|
||||
return getBrowserExecutablePath();
|
||||
}
|
||||
|
||||
getBrowserExecutablePath() {
|
||||
return getBrowserExecutablePath()
|
||||
}
|
||||
getBrowserArgsForPuppeteer() {
|
||||
// Run optimized version of Chrome
|
||||
// References:
|
||||
// https://github.com/pedroslopez/whatsapp-web.js/issues/1420
|
||||
// https://www.bannerbear.com/blog/ways-to-speed-up-puppeteer-screenshots/
|
||||
return [
|
||||
'--no-sandbox',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-speech-api',
|
||||
'--hide-scrollbars',
|
||||
'--mute-audio',
|
||||
'--disable-extensions',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--no-first-run',
|
||||
'--no-default-browser-check',
|
||||
'--no-pings',
|
||||
'--password-store=basic',
|
||||
'--use-mock-keychain',
|
||||
'--no-zygote',
|
||||
'--single-process',
|
||||
'--disable-gpu',
|
||||
];
|
||||
}
|
||||
|
||||
getBrowserArgsForPuppeteer() {
|
||||
// Run optimized version of Chrome
|
||||
// References:
|
||||
// https://github.com/pedroslopez/whatsapp-web.js/issues/1420
|
||||
// https://www.bannerbear.com/blog/ways-to-speed-up-puppeteer-screenshots/
|
||||
return [
|
||||
'--no-sandbox',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-speech-api',
|
||||
'--hide-scrollbars',
|
||||
'--mute-audio',
|
||||
'--disable-extensions',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--no-first-run',
|
||||
'--no-default-browser-check',
|
||||
'--no-pings',
|
||||
'--password-store=basic',
|
||||
'--use-mock-keychain',
|
||||
'--no-zygote',
|
||||
'--single-process',
|
||||
'--disable-gpu'
|
||||
]
|
||||
}
|
||||
/** Start the session */
|
||||
abstract start();
|
||||
|
||||
/** Stop the session */
|
||||
abstract stop(): void;
|
||||
|
||||
/** Start the session */
|
||||
abstract start()
|
||||
/** Subscribe the handler to specific hook */
|
||||
abstract subscribe(hook: WAEvents | string, handler: (message) => void);
|
||||
|
||||
/** Stop the session */
|
||||
abstract stop(): void
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
abstract getScreenshot(): Promise<Buffer | string>;
|
||||
|
||||
/** Subscribe the handler to specific hook */
|
||||
abstract subscribe(hook: WAEvents | string, handler: (message) => void)
|
||||
abstract checkNumberStatus(request: CheckNumberStatusQuery);
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
abstract getScreenshot(): Promise<Buffer | string>
|
||||
abstract sendText(request: MessageTextRequest);
|
||||
|
||||
abstract checkNumberStatus(request: CheckNumberStatusQuery)
|
||||
abstract sendContactVCard(request: MessageContactVcardRequest);
|
||||
|
||||
abstract sendText(request: MessageTextRequest)
|
||||
abstract sendTextButtons(request: MessageTextButtonsRequest);
|
||||
|
||||
abstract sendContactVCard(request: MessageContactVcardRequest)
|
||||
abstract sendLocation(request: MessageLocationRequest);
|
||||
|
||||
abstract sendTextButtons(request: MessageTextButtonsRequest)
|
||||
abstract sendLinkPreview(request: MessageLinkPreviewRequest);
|
||||
|
||||
abstract sendLocation(request: MessageLocationRequest)
|
||||
abstract sendImage(request: MessageImageRequest);
|
||||
|
||||
abstract sendLinkPreview(request: MessageLinkPreviewRequest)
|
||||
abstract sendFile(request: MessageFileRequest);
|
||||
|
||||
abstract sendImage(request: MessageImageRequest)
|
||||
abstract sendVoice(request: MessageVoiceRequest);
|
||||
|
||||
abstract sendFile(request: MessageFileRequest)
|
||||
abstract reply(request: MessageReplyRequest);
|
||||
|
||||
abstract sendVoice(request: MessageVoiceRequest)
|
||||
abstract sendSeen(chat: ChatRequest);
|
||||
|
||||
abstract reply(request: MessageReplyRequest)
|
||||
abstract startTyping(chat: ChatRequest);
|
||||
|
||||
abstract sendSeen(chat: ChatRequest)
|
||||
abstract stopTyping(chat: ChatRequest);
|
||||
|
||||
abstract startTyping(chat: ChatRequest)
|
||||
abstract getMessages(query: GetMessageQuery);
|
||||
|
||||
abstract stopTyping(chat: ChatRequest)
|
||||
abstract setReaction(request: MessageReactionRequest);
|
||||
|
||||
abstract getMessages(query: GetMessageQuery)
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
public getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
abstract setReaction(request: MessageReactionRequest)
|
||||
public getContacts() {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
public getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContacts() {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getGroups() {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public leaveGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public setDescription(id, description) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public setSubject(id, description) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public leaveGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public setDescription(id, description) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public revokeInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public setSubject(id, description) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getParticipants(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public addParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public revokeInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public removeParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getParticipants(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public addParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public removeParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
public promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add WhatsApp suffix (@c.us) to the phone number if it doesn't have it yet
|
||||
* @param phone
|
||||
*/
|
||||
protected ensureSuffix(phone) {
|
||||
return ensureSuffix(phone)
|
||||
}
|
||||
|
||||
protected deserializeId(messageId: string): MessageId {
|
||||
const parts = messageId.split("_")
|
||||
return {
|
||||
"fromMe": parts[0] === "true",
|
||||
"remote": parts[1],
|
||||
"id": parts[2],
|
||||
"_serialized": messageId
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add WhatsApp suffix (@c.us) to the phone number if it doesn't have it yet
|
||||
* @param phone
|
||||
*/
|
||||
protected ensureSuffix(phone) {
|
||||
return ensureSuffix(phone);
|
||||
}
|
||||
|
||||
protected deserializeId(messageId: string): MessageId {
|
||||
const parts = messageId.split('_');
|
||||
return {
|
||||
fromMe: parts[0] === 'true',
|
||||
remote: parts[1],
|
||||
id: parts[2],
|
||||
_serialized: messageId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
export abstract class MediaStorage {
|
||||
abstract save(messageId: string, mimetype: string, buffer: Buffer): Promise<string>
|
||||
abstract save(
|
||||
messageId: string,
|
||||
mimetype: string,
|
||||
buffer: Buffer,
|
||||
): Promise<string>;
|
||||
}
|
||||
|
||||
export abstract class LocalSessionStorage {
|
||||
public sessionsFolder: string;
|
||||
|
||||
protected constructor(public engine: string) {
|
||||
this.engine = engine
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
abstract init()
|
||||
abstract init();
|
||||
|
||||
abstract getFolderPath(sessionName: string): string
|
||||
abstract getFolderPath(sessionName: string): string;
|
||||
|
||||
abstract clean(sessionName: string)
|
||||
abstract clean(sessionName: string);
|
||||
|
||||
abstract getAll(): string[]
|
||||
abstract getAll(): string[];
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {WhatsappSession} from "./session.abc";
|
||||
import { WhatsappSession } from './session.abc';
|
||||
|
||||
export abstract class WebhookConductor {
|
||||
abstract configure(session: WhatsappSession)
|
||||
abstract configure(session: WhatsappSession);
|
||||
}
|
||||
+49
-50
@@ -1,57 +1,56 @@
|
||||
import {ConsoleLogger, Module} from '@nestjs/common';
|
||||
import {ScreenshotController} from "../api/screenshot.controller";
|
||||
import {ConfigModule} from "@nestjs/config";
|
||||
import {WhatsappConfigService} from "../config.service";
|
||||
import {ServeStaticModule} from "@nestjs/serve-static";
|
||||
import {SessionsController} from "../api/sessions.controller";
|
||||
import {ChattingController} from "../api/chatting.controller";
|
||||
import {ContactsController} from "../api/contacts.controller";
|
||||
import {VersionController} from "../api/version.controller";
|
||||
import {PassportModule} from "@nestjs/passport";
|
||||
import {SessionManager} from "./abc/manager.abc";
|
||||
import {SessionManagerCore} from "./manager.core";
|
||||
import {GroupsController} from "../api/groups.controller";
|
||||
import { ConsoleLogger, Module } from '@nestjs/common';
|
||||
import { ScreenshotController } from '../api/screenshot.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||
import { SessionsController } from '../api/sessions.controller';
|
||||
import { ChattingController } from '../api/chatting.controller';
|
||||
import { ContactsController } from '../api/contacts.controller';
|
||||
import { VersionController } from '../api/version.controller';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { SessionManager } from './abc/manager.abc';
|
||||
import { SessionManagerCore } from './manager.core';
|
||||
import { GroupsController } from '../api/groups.controller';
|
||||
|
||||
export const IMPORTS = [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
ServeStaticModule.forRootAsync({
|
||||
imports: [],
|
||||
extraProviders: [WhatsappConfigService],
|
||||
inject: [WhatsappConfigService],
|
||||
useFactory: (config: WhatsappConfigService) => {
|
||||
return [{
|
||||
rootPath: config.filesFolder,
|
||||
serveRoot: config.files_uri,
|
||||
}]
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
ServeStaticModule.forRootAsync({
|
||||
imports: [],
|
||||
extraProviders: [WhatsappConfigService],
|
||||
inject: [WhatsappConfigService],
|
||||
useFactory: (config: WhatsappConfigService) => {
|
||||
return [
|
||||
{
|
||||
rootPath: config.filesFolder,
|
||||
serveRoot: config.files_uri,
|
||||
},
|
||||
}),
|
||||
PassportModule,
|
||||
]
|
||||
export const CONTROLLERS = [
|
||||
SessionsController,
|
||||
ChattingController,
|
||||
ContactsController,
|
||||
GroupsController,
|
||||
ScreenshotController,
|
||||
VersionController,
|
||||
]
|
||||
const PROVIDERS = [
|
||||
{
|
||||
provide: SessionManager,
|
||||
useClass: SessionManagerCore,
|
||||
];
|
||||
},
|
||||
WhatsappConfigService,
|
||||
ConsoleLogger,
|
||||
]
|
||||
|
||||
}),
|
||||
PassportModule,
|
||||
];
|
||||
export const CONTROLLERS = [
|
||||
SessionsController,
|
||||
ChattingController,
|
||||
ContactsController,
|
||||
GroupsController,
|
||||
ScreenshotController,
|
||||
VersionController,
|
||||
];
|
||||
const PROVIDERS = [
|
||||
{
|
||||
provide: SessionManager,
|
||||
useClass: SessionManagerCore,
|
||||
},
|
||||
WhatsappConfigService,
|
||||
ConsoleLogger,
|
||||
];
|
||||
|
||||
@Module({
|
||||
imports: IMPORTS,
|
||||
controllers: CONTROLLERS,
|
||||
providers: PROVIDERS,
|
||||
imports: IMPORTS,
|
||||
controllers: CONTROLLERS,
|
||||
providers: PROVIDERS,
|
||||
})
|
||||
export class AppModuleCore {
|
||||
|
||||
}
|
||||
export class AppModuleCore {}
|
||||
+13
-12
@@ -1,20 +1,21 @@
|
||||
import {UnprocessableEntityException} from "@nestjs/common";
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
|
||||
export const DOCS_URL = "https://waha.devlike.pro/"
|
||||
export const DOCS_URL = 'https://waha.devlike.pro/';
|
||||
|
||||
export class NotImplementedByEngineError extends UnprocessableEntityException {
|
||||
constructor(msg = "") {
|
||||
let error = "The method is not implemented by the engine."
|
||||
if (msg) {
|
||||
error += ` ${msg}`
|
||||
}
|
||||
super(error);
|
||||
constructor(msg = '') {
|
||||
let error = 'The method is not implemented by the engine.';
|
||||
if (msg) {
|
||||
error += ` ${msg}`;
|
||||
}
|
||||
super(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class AvailableInPlusVersion extends UnprocessableEntityException {
|
||||
constructor() {
|
||||
super(`The feature is available only in Plus version. Check this out: ${DOCS_URL}`);
|
||||
}
|
||||
constructor() {
|
||||
super(
|
||||
`The feature is available only in Plus version. Check this out: ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+150
-126
@@ -1,144 +1,168 @@
|
||||
import {ConsoleLogger, Injectable, NotFoundException, UnprocessableEntityException} from "@nestjs/common";
|
||||
import {SessionManager} from "./abc/manager.abc";
|
||||
import { WAHAInternalEvent, WhatsappSession, WhatsAppSessionConfig } from "./abc/session.abc";
|
||||
import { WhatsappEngine, WhatsappStatus } from "../structures/enums.dto";
|
||||
import { SessionLogoutRequest, SessionDTO, SessionStartRequest, SessionStopRequest } from "../structures/sessions.dto";
|
||||
import {WhatsappConfigService} from "../config.service";
|
||||
import {WhatsappSessionVenomCore} from "./session.venom.core";
|
||||
import {WhatsappSessionWebJSCore} from "./session.webjs.core";
|
||||
import {DOCS_URL} from "./exceptions";
|
||||
import {WebhookConductorCore} from "./webhooks.core";
|
||||
import { MediaStorageCore, SessionStorageCore } from "./storage.core";
|
||||
import {WhatsappSessionNoWebCore} from "./session.noweb.core";
|
||||
import { LocalSessionStorage } from "./abc/storage.abc";
|
||||
import {
|
||||
ConsoleLogger,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
import { SessionManager } from './abc/manager.abc';
|
||||
import {
|
||||
WAHAInternalEvent,
|
||||
WhatsappSession,
|
||||
WhatsAppSessionConfig,
|
||||
} from './abc/session.abc';
|
||||
import { WhatsappEngine, WhatsappStatus } from '../structures/enums.dto';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest,
|
||||
} from '../structures/sessions.dto';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
import { WhatsappSessionVenomCore } from './session.venom.core';
|
||||
import { WhatsappSessionWebJSCore } from './session.webjs.core';
|
||||
import { DOCS_URL } from './exceptions';
|
||||
import { WebhookConductorCore } from './webhooks.core';
|
||||
import { MediaStorageCore, SessionStorageCore } from './storage.core';
|
||||
import { WhatsappSessionNoWebCore } from './session.noweb.core';
|
||||
import { LocalSessionStorage } from './abc/storage.abc';
|
||||
|
||||
export class OnlyDefaultSessionIsAllowed extends UnprocessableEntityException {
|
||||
constructor() {
|
||||
super(`WAHA Core support only 'default' session. If you want to run more then one WhatsApp account - please get WAHA PLUS version. Check this out: ${DOCS_URL}`);
|
||||
}
|
||||
constructor() {
|
||||
super(
|
||||
`WAHA Core support only 'default' session. If you want to run more then one WhatsApp account - please get WAHA PLUS version. Check this out: ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SessionManagerCore extends SessionManager {
|
||||
private session: WhatsappSession;
|
||||
DEFAULT = "default"
|
||||
private session: WhatsappSession;
|
||||
DEFAULT = 'default';
|
||||
|
||||
// @ts-ignore
|
||||
protected MediaStorageClass = MediaStorageCore
|
||||
// @ts-ignore
|
||||
protected WebhookConductorClass = WebhookConductorCore
|
||||
protected readonly EngineClass: typeof WhatsappSession;
|
||||
protected sessionStorage: LocalSessionStorage
|
||||
// @ts-ignore
|
||||
protected MediaStorageClass = MediaStorageCore;
|
||||
// @ts-ignore
|
||||
protected WebhookConductorClass = WebhookConductorCore;
|
||||
protected readonly EngineClass: typeof WhatsappSession;
|
||||
protected sessionStorage: LocalSessionStorage;
|
||||
|
||||
constructor(
|
||||
private config: WhatsappConfigService,
|
||||
private log: ConsoleLogger,
|
||||
) {
|
||||
super();
|
||||
|
||||
constructor(
|
||||
private config: WhatsappConfigService,
|
||||
private log: ConsoleLogger,
|
||||
) {
|
||||
super()
|
||||
this.log.setContext('SessionManager');
|
||||
this.session = undefined;
|
||||
const engineName = this.config.getDefaultEngineName();
|
||||
this.EngineClass = this.getEngine(engineName);
|
||||
this.sessionStorage = new SessionStorageCore(engineName.toLowerCase());
|
||||
this.sessionStorage.init();
|
||||
|
||||
this.log.setContext('SessionManager')
|
||||
this.session = undefined
|
||||
const engineName = this.config.getDefaultEngineName()
|
||||
this.EngineClass = this.getEngine(engineName)
|
||||
this.sessionStorage = new SessionStorageCore(engineName.toLowerCase())
|
||||
this.sessionStorage.init()
|
||||
this.startPredefinedSessions();
|
||||
}
|
||||
|
||||
this.startPredefinedSessions()
|
||||
protected startPredefinedSessions() {
|
||||
const startSessions = this.config.startSessions;
|
||||
startSessions.forEach((sessionName) => {
|
||||
this.start({ name: sessionName });
|
||||
});
|
||||
}
|
||||
|
||||
protected getEngine(engine: WhatsappEngine): typeof WhatsappSession {
|
||||
if (engine === WhatsappEngine.WEBJS) {
|
||||
return WhatsappSessionWebJSCore;
|
||||
} else if (engine === WhatsappEngine.VENOM) {
|
||||
return WhatsappSessionVenomCore;
|
||||
} else if (engine === WhatsappEngine.NOWEB) {
|
||||
return WhatsappSessionNoWebCore;
|
||||
} else {
|
||||
throw new NotFoundException(`Unknown whatsapp engine '${engine}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
protected startPredefinedSessions() {
|
||||
const startSessions = this.config.startSessions;
|
||||
startSessions.forEach((sessionName) => {
|
||||
this.start({ name: sessionName });
|
||||
}
|
||||
private onlyDefault(name: string) {
|
||||
if (name !== this.DEFAULT) {
|
||||
throw new OnlyDefaultSessionIsAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
async onApplicationShutdown(signal?: string) {
|
||||
if (!this.session) {
|
||||
return;
|
||||
}
|
||||
await this.stop({ name: this.DEFAULT, logout: false });
|
||||
}
|
||||
|
||||
//
|
||||
// API Methods
|
||||
//
|
||||
start(request: SessionStartRequest): SessionDTO {
|
||||
this.onlyDefault(request.name);
|
||||
|
||||
const name = request.name;
|
||||
this.log.log(`'${name}' - starting session...`);
|
||||
const log = new ConsoleLogger(`WhatsappSession - ${name}`);
|
||||
const storage = new this.MediaStorageClass();
|
||||
const webhookLog = new ConsoleLogger(`Webhook - ${name}`);
|
||||
const webhook = new this.WebhookConductorClass(
|
||||
webhookLog,
|
||||
this.config.getWebhookUrl(),
|
||||
this.config.getWebhookEvents(),
|
||||
);
|
||||
|
||||
const sessionConfig: WhatsAppSessionConfig = {
|
||||
name,
|
||||
storage,
|
||||
log,
|
||||
sessionStorage: this.sessionStorage,
|
||||
};
|
||||
// @ts-ignore
|
||||
const session = new this.EngineClass(sessionConfig);
|
||||
this.session = session;
|
||||
|
||||
session.events.on(WAHAInternalEvent.engine_start, () =>
|
||||
webhook.configure(session),
|
||||
);
|
||||
session.start();
|
||||
return { name: session.name, status: session.status };
|
||||
}
|
||||
|
||||
async stop(request: SessionStopRequest): Promise<void> {
|
||||
this.onlyDefault(request.name);
|
||||
|
||||
const name = request.name;
|
||||
this.log.log(`Stopping ${name} session...`);
|
||||
const session = this.getSession(name);
|
||||
await session.stop();
|
||||
this.log.log(`"${name}" has been stopped.`);
|
||||
this.session = undefined;
|
||||
}
|
||||
|
||||
async logout(request: SessionLogoutRequest) {
|
||||
this.sessionStorage.clean(request.name);
|
||||
}
|
||||
|
||||
getSession(name: string, error = true): WhatsappSession {
|
||||
this.onlyDefault(name);
|
||||
const session = this.session;
|
||||
if (!session) {
|
||||
if (error) {
|
||||
throw new NotFoundException(
|
||||
`We didn't find a session with name '${name}'. Please start it first by using POST /sessions/start request`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
protected getEngine(engine: WhatsappEngine): typeof WhatsappSession {
|
||||
if (engine === WhatsappEngine.WEBJS) {
|
||||
return WhatsappSessionWebJSCore
|
||||
} else if (engine === WhatsappEngine.VENOM) {
|
||||
return WhatsappSessionVenomCore
|
||||
} else if (engine === WhatsappEngine.NOWEB) {
|
||||
return WhatsappSessionNoWebCore
|
||||
} else {
|
||||
throw new NotFoundException(`Unknown whatsapp engine '${engine}'.`)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private onlyDefault(name: string) {
|
||||
if (name !== this.DEFAULT) {
|
||||
throw new OnlyDefaultSessionIsAllowed()
|
||||
}
|
||||
}
|
||||
|
||||
async onApplicationShutdown(signal?: string) {
|
||||
if (!this.session){
|
||||
return
|
||||
}
|
||||
await this.stop({name: this.DEFAULT, logout: false})
|
||||
}
|
||||
|
||||
//
|
||||
// API Methods
|
||||
//
|
||||
start(request: SessionStartRequest): SessionDTO {
|
||||
this.onlyDefault(request.name)
|
||||
|
||||
const name = request.name
|
||||
this.log.log(`'${name}' - starting session...`)
|
||||
const log = new ConsoleLogger(`WhatsappSession - ${name}`)
|
||||
const storage = new this.MediaStorageClass()
|
||||
const webhookLog = new ConsoleLogger(`Webhook - ${name}`)
|
||||
const webhook = new this.WebhookConductorClass(
|
||||
webhookLog,
|
||||
this.config.getWebhookUrl(),
|
||||
this.config.getWebhookEvents()
|
||||
)
|
||||
|
||||
const sessionConfig: WhatsAppSessionConfig = {name, storage, log, sessionStorage: this.sessionStorage}
|
||||
// @ts-ignore
|
||||
const session = new this.EngineClass(sessionConfig)
|
||||
this.session = session
|
||||
|
||||
session.events.on(WAHAInternalEvent.engine_start, () => webhook.configure(session))
|
||||
session.start()
|
||||
return {name: session.name, status: session.status}
|
||||
}
|
||||
|
||||
async stop(request: SessionStopRequest): Promise<void> {
|
||||
this.onlyDefault(request.name)
|
||||
|
||||
const name = request.name
|
||||
this.log.log(`Stopping ${name} session...`)
|
||||
const session = this.getSession(name)
|
||||
await session.stop()
|
||||
this.log.log(`"${name}" has been stopped.`)
|
||||
this.session = undefined
|
||||
}
|
||||
|
||||
async logout(request: SessionLogoutRequest){
|
||||
this.sessionStorage.clean(request.name)
|
||||
}
|
||||
|
||||
getSession(name: string, error=true): WhatsappSession {
|
||||
this.onlyDefault(name)
|
||||
const session = this.session
|
||||
if (!session) {
|
||||
if (error){
|
||||
throw new NotFoundException( `We didn't find a session with name '${name}'. Please start it first by using POST /sessions/start request`);
|
||||
}
|
||||
return
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
getSessions(all: boolean): SessionDTO[] {
|
||||
if (!this.session){
|
||||
return all? [{name: this.DEFAULT, status: WhatsappStatus.STOPPED}] : []
|
||||
}
|
||||
return [{name: this.session.name, status: this.session.status}]
|
||||
getSessions(all: boolean): SessionDTO[] {
|
||||
if (!this.session) {
|
||||
return all
|
||||
? [{ name: this.DEFAULT, status: WhatsappStatus.STOPPED }]
|
||||
: [];
|
||||
}
|
||||
return [{ name: this.session.name, status: this.session.status }];
|
||||
}
|
||||
}
|
||||
+114
-78
@@ -1,13 +1,22 @@
|
||||
import { SECOND, WAEvents, WhatsappEngine, WhatsappStatus } from "../structures/enums.dto";
|
||||
import {
|
||||
SECOND,
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import makeWASocket, {
|
||||
DisconnectReason,
|
||||
isJidGroup,
|
||||
makeInMemoryStore,
|
||||
useMultiFileAuthState
|
||||
} from "@adiwajshing/baileys";
|
||||
useMultiFileAuthState,
|
||||
} from '@adiwajshing/baileys';
|
||||
|
||||
import { ensureSuffix, WAHAInternalEvent, WhatsappSession } from "./abc/session.abc";
|
||||
import { WAMessage, WANumberExistResult } from "../structures/responses.dto";
|
||||
import {
|
||||
ensureSuffix,
|
||||
WAHAInternalEvent,
|
||||
WhatsappSession,
|
||||
} from './abc/session.abc';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
@@ -23,34 +32,39 @@ import {
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import { AvailableInPlusVersion, NotImplementedByEngineError } from "./exceptions";
|
||||
import { ContactQuery, ContactRequest } from "../structures/contacts.dto";
|
||||
import { CreateGroupRequest, ParticipantsRequest } from "../structures/groups.dto";
|
||||
import { QR } from "./QR";
|
||||
import { MediaStorage } from "./abc/storage.abc";
|
||||
import { ConsoleLogger, UnprocessableEntityException } from "@nestjs/common";
|
||||
import { Message } from "whatsapp-web.js";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import {
|
||||
AvailableInPlusVersion,
|
||||
NotImplementedByEngineError,
|
||||
} from './exceptions';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../structures/groups.dto';
|
||||
import { QR } from './QR';
|
||||
import { MediaStorage } from './abc/storage.abc';
|
||||
import { ConsoleLogger, UnprocessableEntityException } from '@nestjs/common';
|
||||
import { Message } from 'whatsapp-web.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const QRCode = require("qrcode");
|
||||
const QRCode = require('qrcode');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const logger = require("pino")();
|
||||
|
||||
const logger = require('pino')();
|
||||
|
||||
export const BaileysEvents = {
|
||||
CONNECTION_UPDATE: "connection.update",
|
||||
CREDS_UPDATE: "creds.update",
|
||||
MESSAGES_UPSERT: "messages.upsert",
|
||||
GROUPS_UPSERT: "groups.upsert"
|
||||
CONNECTION_UPDATE: 'connection.update',
|
||||
CREDS_UPDATE: 'creds.update',
|
||||
MESSAGES_UPSERT: 'messages.upsert',
|
||||
GROUPS_UPSERT: 'groups.upsert',
|
||||
};
|
||||
|
||||
export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
engine = WhatsappEngine.NOWEB
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
sock: any;
|
||||
store: any;
|
||||
@@ -68,7 +82,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
|
||||
protected getAuthFolder() {
|
||||
const folder = this.sessionStorage.getFolderPath(this.name)
|
||||
const folder = this.sessionStorage.getFolderPath(this.name);
|
||||
return fs.mkdtempSync(folder);
|
||||
}
|
||||
|
||||
@@ -77,8 +91,8 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
const sock: any = makeWASocket({
|
||||
auth: state,
|
||||
printQRInTerminal: true,
|
||||
browser: ["Linux", "Chrome", "111.0.5563.64"],
|
||||
logger: logger
|
||||
browser: ['Linux', 'Chrome', '111.0.5563.64'],
|
||||
logger: logger,
|
||||
});
|
||||
sock.ev.on(BaileysEvents.CREDS_UPDATE, saveCreds);
|
||||
return sock;
|
||||
@@ -96,14 +110,21 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
this.connectStore();
|
||||
this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, async (update) => {
|
||||
const { connection, lastDisconnect, qr } = update;
|
||||
if (connection === "connecting") {
|
||||
this.qr.save("");
|
||||
if (connection === 'connecting') {
|
||||
this.qr.save('');
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
return;
|
||||
} else if (connection === "close") {
|
||||
const shouldReconnect = (lastDisconnect.error)?.output?.statusCode !== DisconnectReason.loggedOut;
|
||||
this.log.error("connection closed due to ", lastDisconnect.error, ", reconnecting ", shouldReconnect);
|
||||
this.qr.save("");
|
||||
} else if (connection === 'close') {
|
||||
const shouldReconnect =
|
||||
lastDisconnect.error?.output?.statusCode !==
|
||||
DisconnectReason.loggedOut;
|
||||
this.log.error(
|
||||
'connection closed due to ',
|
||||
lastDisconnect.error,
|
||||
', reconnecting ',
|
||||
shouldReconnect,
|
||||
);
|
||||
this.qr.save('');
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
// reconnect if not logged out
|
||||
if (shouldReconnect) {
|
||||
@@ -124,7 +145,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
|
||||
stop() {
|
||||
this.sock.ws.removeAllListeners();
|
||||
this.log.log("socket connection terminated");
|
||||
this.log.log('socket connection terminated');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,18 +154,24 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(`The session is starting, please try again after few seconds`);
|
||||
throw new UnprocessableEntityException(
|
||||
`The session is starting, please try again after few seconds`,
|
||||
);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get());
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
throw new UnprocessableEntityException(`Can not get screenshot for non chrome based engine.`);
|
||||
throw new UnprocessableEntityException(
|
||||
`Can not get screenshot for non chrome based engine.`,
|
||||
);
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const phone = request.phone.split("@")[0];
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const phone = request.phone.split('@')[0];
|
||||
const [result] = await this.sock.onWhatsApp(phone);
|
||||
if (!result) {
|
||||
return { numberExists: false };
|
||||
@@ -160,14 +187,16 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id, buttonText: { displayText: button.text }, type: 1
|
||||
buttonId: button.id,
|
||||
buttonText: { displayText: button.text },
|
||||
type: 1,
|
||||
};
|
||||
});
|
||||
|
||||
const buttonMessage = {
|
||||
text: request.title,
|
||||
buttons: buttons,
|
||||
headerType: 1
|
||||
headerType: 1,
|
||||
};
|
||||
|
||||
return this.sock.sendMessage(request.chatId, buttonMessage);
|
||||
@@ -180,7 +209,11 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
async reply(request: MessageReplyRequest) {
|
||||
const { id } = parseMessageId(request.reply_to);
|
||||
const message = await this.store.loadMessage(toJID(request.chatId), id);
|
||||
return await this.sock.sendMessage(request.chatId, { text: request.text }, { quoted: message });
|
||||
return await this.sock.sendMessage(
|
||||
request.chatId,
|
||||
{ text: request.text },
|
||||
{ quoted: message },
|
||||
);
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
@@ -196,10 +229,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.sock.sendMessage(
|
||||
request.chatId,
|
||||
{ location: { degreesLatitude: request.latitude, degreesLongitude: request.longitude } }
|
||||
);
|
||||
return this.sock.sendMessage(request.chatId, {
|
||||
location: {
|
||||
degreesLatitude: request.latitude,
|
||||
degreesLongitude: request.longitude,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
@@ -208,23 +243,22 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
return this.sock.sendMessage(chatId, { text: text });
|
||||
}
|
||||
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const key = parseMessageId(request.messageId);
|
||||
const data = {
|
||||
remoteJid: key.remoteJid,
|
||||
id: key.id,
|
||||
participant: request.participant
|
||||
participant: request.participant,
|
||||
};
|
||||
return this.sock.readMessages([data]);
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate("composing", request.chatId);
|
||||
return this.sock.sendPresenceUpdate('composing', request.chatId);
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate("paused", request.chatId);
|
||||
return this.sock.sendPresenceUpdate('paused', request.chatId);
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
@@ -236,13 +270,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
const reactionMessage = {
|
||||
react: {
|
||||
text: request.reaction,
|
||||
key: key
|
||||
}
|
||||
key: key,
|
||||
},
|
||||
};
|
||||
return this.sock.sendMessage(key.remoteJid, reactionMessage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
@@ -319,22 +352,22 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "add");
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'add');
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "remove");
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'remove');
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "promote");
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'promote');
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "demote");
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'demote');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,19 +376,21 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT,
|
||||
({ messages }) => this.handleIncomingMessages(messages, handler, false)
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT, ({ messages }) =>
|
||||
this.handleIncomingMessages(messages, handler, false),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT,
|
||||
({ messages }) => this.handleIncomingMessages(messages, handler, true)
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT, ({ messages }) =>
|
||||
this.handleIncomingMessages(messages, handler, true),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, handler);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.sock.ev.on(BaileysEvents.GROUPS_UPSERT, handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`);
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,12 +421,13 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
const from = message.key.remoteJid;
|
||||
const id = buildMessageId(message.key);
|
||||
let body = message.message.conversation
|
||||
if (!body){
|
||||
// Some of the messages have no conversation, but instead have text in extendedTextMessage
|
||||
// https://github.com/devlikeapro/whatsapp-http-api/issues/90
|
||||
body = message.message.extendedTextMessage?.text
|
||||
}return Promise.resolve({
|
||||
let body = message.message.conversation;
|
||||
if (!body) {
|
||||
// Some of the messages have no conversation, but instead have text in extendedTextMessage
|
||||
// https://github.com/devlikeapro/whatsapp-http-api/issues/90
|
||||
body = message.message.extendedTextMessage?.text;
|
||||
}
|
||||
return Promise.resolve({
|
||||
id: id,
|
||||
timestamp: message.messageTimestamp,
|
||||
from: toCusFormat(from),
|
||||
@@ -407,7 +443,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message
|
||||
_data: message,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -417,10 +453,9 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.key.id, "", undefined);
|
||||
message.mediaUrl = await this.storage.save(message.key.id, '', undefined);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,7 +468,7 @@ function toCusFormat(remoteJid) {
|
||||
if (!remoteJid) {
|
||||
return;
|
||||
}
|
||||
const number = remoteJid.split("@")[0];
|
||||
const number = remoteJid.split('@')[0];
|
||||
return ensureSuffix(number);
|
||||
}
|
||||
|
||||
@@ -445,8 +480,8 @@ function toJID(chatId) {
|
||||
if (isJidGroup(chatId)) {
|
||||
return chatId;
|
||||
}
|
||||
const number = chatId.split("@")[0];
|
||||
return number + "@s.whatsapp.net";
|
||||
const number = chatId.split('@')[0];
|
||||
return number + '@s.whatsapp.net';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,18 +500,19 @@ function buildMessageId({ id, remoteJid, fromMe }) {
|
||||
* {id: "AAA", remoteJid: "11111111111@s.whatsapp.net", "fromMe": false}
|
||||
*/
|
||||
function parseMessageId(messageId) {
|
||||
const parts = messageId.split("_");
|
||||
const parts = messageId.split('_');
|
||||
if (parts.length != 3) {
|
||||
throw new Error("Message id be in format false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA");
|
||||
throw new Error(
|
||||
'Message id be in format false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
);
|
||||
}
|
||||
const fromMe = parts[0] == "true";
|
||||
const fromMe = parts[0] == 'true';
|
||||
const chatId = parts[1];
|
||||
const remoteJid = toJID(chatId);
|
||||
const id = parts[2];
|
||||
return { fromMe: fromMe, id: id, remoteJid: remoteJid };
|
||||
}
|
||||
|
||||
|
||||
function getId(object) {
|
||||
return object.id;
|
||||
}
|
||||
+254
-219
@@ -1,239 +1,274 @@
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import {create, Message, Whatsapp} from "venom-bot";
|
||||
import { WAEvents, WhatsappEngine, WhatsappStatus } from "../structures/enums.dto";
|
||||
import {NotImplementedByEngineError} from "./exceptions";
|
||||
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
|
||||
import {QR} from "./QR";
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import { create, Message, Whatsapp } from 'venom-bot';
|
||||
import {
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import { NotImplementedByEngineError } from './exceptions';
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import { QR } from './QR';
|
||||
|
||||
export class WhatsappSessionVenomCore extends WhatsappSession {
|
||||
engine = WhatsappEngine.NOWEB
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
whatsapp: Whatsapp;
|
||||
private qr: QR
|
||||
whatsapp: Whatsapp;
|
||||
private qr: QR;
|
||||
|
||||
public constructor(config) {
|
||||
super(config);
|
||||
this.qr = new QR()
|
||||
public constructor(config) {
|
||||
super(config);
|
||||
this.qr = new QR();
|
||||
}
|
||||
|
||||
protected buildClient() {
|
||||
return create(this.name, this.getCatchQR(), undefined, {
|
||||
headless: true,
|
||||
devtools: false,
|
||||
useChrome: true,
|
||||
debug: false,
|
||||
logQR: true,
|
||||
browserArgs: this.getBrowserArgsForPuppeteer(),
|
||||
autoClose: 60000,
|
||||
puppeteerOptions: {},
|
||||
multidevice: true,
|
||||
});
|
||||
}
|
||||
|
||||
protected getCatchQR() {
|
||||
return (base64Qrimg, asciiQR, attempts, urlCode) => {
|
||||
this.qr.save(base64Qrimg);
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE;
|
||||
this.log.debug('Number of attempts to read the qrcode: ', attempts);
|
||||
this.log.log('Terminal qrcode:');
|
||||
// Log QR image in console without this.log to make it pretty
|
||||
console.log(asciiQR);
|
||||
};
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
this.whatsapp = await this.buildClient();
|
||||
} catch (error) {
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
this.log.error(error);
|
||||
this.qr.save('');
|
||||
return;
|
||||
}
|
||||
|
||||
protected buildClient() {
|
||||
return create(this.name,
|
||||
this.getCatchQR(),
|
||||
undefined,
|
||||
{
|
||||
headless: true,
|
||||
devtools: false,
|
||||
useChrome: true,
|
||||
debug: false,
|
||||
logQR: true,
|
||||
browserArgs: this.getBrowserArgsForPuppeteer(),
|
||||
autoClose: 60000,
|
||||
puppeteerOptions: {},
|
||||
multidevice: true,
|
||||
}
|
||||
)
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
this.events.emit(WAHAInternalEvent.engine_start);
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.close();
|
||||
}
|
||||
|
||||
subscribe(event: WAEvents | string, handler: (message) => void) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.whatsapp.onMessage((message: Message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.whatsapp.onAnyMessage((message: Message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.whatsapp.onStateChange(handler);
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
return this.whatsapp.onAck(handler);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.whatsapp.onAddedToGroup(handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected getCatchQR() {
|
||||
return (base64Qrimg, asciiQR, attempts, urlCode) => {
|
||||
this.qr.save(base64Qrimg)
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||
this.log.debug('Number of attempts to read the qrcode: ', attempts);
|
||||
this.log.log('Terminal qrcode:');
|
||||
// Log QR image in console without this.log to make it pretty
|
||||
console.log(asciiQR);
|
||||
};
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(
|
||||
`The session is starting, please try again after few seconds`,
|
||||
);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get());
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
return this.whatsapp.page.screenshot();
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
this.whatsapp = await this.buildClient()
|
||||
} catch (error) {
|
||||
this.status = WhatsappStatus.FAILED
|
||||
this.log.error(error)
|
||||
this.qr.save("")
|
||||
return
|
||||
}
|
||||
|
||||
this.status = WhatsappStatus.WORKING
|
||||
this.events.emit(WAHAInternalEvent.engine_start)
|
||||
return this
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
try {
|
||||
return await this.whatsapp.checkNumberStatus(
|
||||
this.ensureSuffix(request.phone),
|
||||
);
|
||||
} catch (error) {
|
||||
// Catch number doesn't exist error and return it as is
|
||||
if (error.status === 404 && !error.numberExists) {
|
||||
return error;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
return this.whatsapp.sendContactVcard(
|
||||
request.chatId,
|
||||
request.contactsId,
|
||||
request.name,
|
||||
);
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.close()
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendText(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.text,
|
||||
);
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
return this.whatsapp.reply(request.chatId, request.text, request.reply_to);
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async sendVoice(request) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
return this.whatsapp.sendLinkPreview(
|
||||
request.chatId,
|
||||
request.url,
|
||||
request.title,
|
||||
);
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.whatsapp.sendLocation(
|
||||
request.chatId,
|
||||
String(request.latitude),
|
||||
String(request.longitude),
|
||||
request.title,
|
||||
);
|
||||
}
|
||||
|
||||
sendSeen(chat: ChatRequest) {
|
||||
return this.whatsapp.sendSeen(chat.chatId);
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id,
|
||||
buttonText: {
|
||||
displayText: button.text,
|
||||
},
|
||||
};
|
||||
});
|
||||
return this.whatsapp.sendButtons(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.title,
|
||||
buttons,
|
||||
request.footer,
|
||||
);
|
||||
}
|
||||
|
||||
startTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.startTyping(chat.chatId);
|
||||
}
|
||||
|
||||
stopTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.stopTyping(chat.chatId);
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const messages = await this.whatsapp.getAllMessagesInChat(
|
||||
query.chatId,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = [];
|
||||
for (const [count, message] of messages.entries()) {
|
||||
if (count > query.limit) {
|
||||
// Have enough in the list, stop processing
|
||||
break;
|
||||
}
|
||||
result.push(await this.processIncomingMessage(message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
subscribe(event: WAEvents | string, handler: (message) => void) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.whatsapp.onMessage((message: Message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.whatsapp.onAnyMessage((message: Message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.whatsapp.onStateChange(handler)
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
return this.whatsapp.onAck(handler)
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.whatsapp.onAddedToGroup(handler)
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`)
|
||||
}
|
||||
setReaction(request: MessageReactionRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
protected async downloadAndDecryptMedia(message: Message) {
|
||||
if (!message.isMMS || !message.isMedia) {
|
||||
return message;
|
||||
}
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id, '', undefined);
|
||||
return message;
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadAndDecryptMedia(message).then(this.toWAMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(`The session is starting, please try again after few seconds`);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get())
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
return this.whatsapp.page.screenshot()
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
try {
|
||||
return await this.whatsapp.checkNumberStatus(this.ensureSuffix(request.phone))
|
||||
} catch (error) {
|
||||
// Catch number doesn't exist error and return it as is
|
||||
if (error.status === 404 && !error.numberExists) {
|
||||
return error
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
return this.whatsapp.sendContactVcard(request.chatId, request.contactsId, request.name)
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendText(this.ensureSuffix(request.chatId), request.text)
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
return this.whatsapp.reply(request.chatId, request.text, request.reply_to)
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
async sendVoice(request) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
return this.whatsapp.sendLinkPreview(request.chatId, request.url, request.title)
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.whatsapp.sendLocation(request.chatId, String(request.latitude), String(request.longitude), request.title)
|
||||
}
|
||||
|
||||
sendSeen(chat: ChatRequest) {
|
||||
return this.whatsapp.sendSeen(chat.chatId)
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id,
|
||||
buttonText: {
|
||||
displayText: button.text
|
||||
}
|
||||
}
|
||||
})
|
||||
return this.whatsapp.sendButtons(this.ensureSuffix(request.chatId), request.title, buttons, request.footer)
|
||||
}
|
||||
|
||||
startTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.startTyping(chat.chatId)
|
||||
}
|
||||
|
||||
stopTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.stopTyping(chat.chatId)
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const messages = await this.whatsapp.getAllMessagesInChat(query.chatId, true, false)
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = []
|
||||
for (const [count, message] of messages.entries()) {
|
||||
if (count > query.limit) {
|
||||
// Have enough in the list, stop processing
|
||||
break
|
||||
}
|
||||
result.push(await this.processIncomingMessage(message))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
setReaction(request: MessageReactionRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
protected async downloadAndDecryptMedia(message: Message) {
|
||||
if (!message.isMMS || !message.isMedia) {
|
||||
return message
|
||||
}
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id, "", undefined)
|
||||
return message
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadAndDecryptMedia(message).then(this.toWAMessage)
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: undefined,
|
||||
vCards: undefined,
|
||||
_data: message,
|
||||
})
|
||||
}
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: undefined,
|
||||
vCards: undefined,
|
||||
_data: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
+405
-340
@@ -1,351 +1,416 @@
|
||||
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
|
||||
import {Buttons, Chat, Client, Contact, Events, GroupChat, Location, Message} from "whatsapp-web.js";
|
||||
import {Message as MessageInstance} from "whatsapp-web.js/src/structures"
|
||||
import { WAEvents, WhatsappEngine, WhatsappStatus } from "../structures/enums.dto";
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest, SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {AvailableInPlusVersion, NotImplementedByEngineError} from "./exceptions";
|
||||
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
|
||||
import {CreateGroupRequest, ParticipantsRequest} from "../structures/groups.dto";
|
||||
Buttons,
|
||||
Chat,
|
||||
Client,
|
||||
Contact,
|
||||
Events,
|
||||
GroupChat,
|
||||
Location,
|
||||
Message,
|
||||
} from 'whatsapp-web.js';
|
||||
import { Message as MessageInstance } from 'whatsapp-web.js/src/structures';
|
||||
import {
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import {
|
||||
AvailableInPlusVersion,
|
||||
NotImplementedByEngineError,
|
||||
} from './exceptions';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../structures/groups.dto';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const qrcode = require('qrcode-terminal');
|
||||
|
||||
|
||||
export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
engine = WhatsappEngine.NOWEB
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
whatsapp: Client;
|
||||
whatsapp: Client;
|
||||
|
||||
protected buildClient() {
|
||||
return new Client({
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
executablePath: this.getBrowserExecutablePath(),
|
||||
args: this.getBrowserArgsForPuppeteer(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async start() {
|
||||
this.whatsapp = this.buildClient()
|
||||
|
||||
this.whatsapp.initialize().catch(error => {
|
||||
this.status = WhatsappStatus.FAILED
|
||||
this.log.error(error)
|
||||
return
|
||||
});
|
||||
|
||||
// Connect events
|
||||
this.whatsapp.on(Events.QR_RECEIVED, (qr) => {
|
||||
qrcode.generate(qr, {small: true});
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.AUTHENTICATED, () => {
|
||||
this.status = WhatsappStatus.WORKING
|
||||
this.log.log(`Session '${this.name}' has been authenticated!`)
|
||||
});
|
||||
this.events.emit(WAHAInternalEvent.engine_start)
|
||||
return this
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.destroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.FAILED) {
|
||||
throw new UnprocessableEntityException(`The session under FAILED status. Please try to restart it.`);
|
||||
}
|
||||
return await this.whatsapp.pupPage.screenshot()
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const exist = await this.whatsapp.isRegisteredUser(this.ensureSuffix(request.phone))
|
||||
return {numberExists: exist}
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendMessage(this.ensureSuffix(request.chatId), request.text)
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
id: button.id,
|
||||
body: button.text,
|
||||
}
|
||||
})
|
||||
const message = new Buttons("", buttons, request.title, request.footer)
|
||||
return this.whatsapp.sendMessage(this.ensureSuffix(request.chatId), message)
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
const options = {
|
||||
quotedMessageId: request.reply_to,
|
||||
};
|
||||
return this.whatsapp.sendMessage(request.chatId, request.text, options)
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
async sendLocation(request: MessageLocationRequest) {
|
||||
const location = new Location(
|
||||
request.latitude,
|
||||
request.longitude,
|
||||
request.title,
|
||||
)
|
||||
return this.whatsapp.sendMessage(request.chatId, location)
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.sendSeen()
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.sendStateTyping()
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.clearState()
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(this.ensureSuffix(query.chatId))
|
||||
const messages = await chat.fetchMessages({
|
||||
limit: query.limit,
|
||||
})
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = []
|
||||
for (const message of messages) {
|
||||
result.push(await this.processIncomingMessage(message))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const messageId = this.deserializeId(request.messageId)
|
||||
// Recreate instance to react on it
|
||||
const message = new MessageInstance(this.whatsapp)
|
||||
message.id = messageId
|
||||
message._data = {id: messageId}
|
||||
|
||||
return message.react(request.reaction)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
return this.whatsapp.getContactById(this.ensureSuffix(query.contactId)).then(this.toWAContact)
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
return this.whatsapp.getContacts().then(contacts => contacts.map(this.toWAContact))
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
|
||||
return {"about": await contact.getAbout()}
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
|
||||
return {"profilePictureURL": await contact.getProfilePicUrl()}
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
|
||||
await contact.block()
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
|
||||
await contact.unblock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return this.whatsapp.createGroup(request.name, participantIds)
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
return this.whatsapp.getChats().then(chats => chats.filter(chat => chat.isGroup))
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
return this.whatsapp.getChatById(id)
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.delete()
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.leave()
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.setDescription(description)
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.setSubject(subject)
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.getInviteCode()
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
await groupChat.revokeInvite()
|
||||
return groupChat.getInviteCode()
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.participants
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.addParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.removeParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.promoteParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.demoteParticipants(participantIds)
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
this.whatsapp.on(Events.MESSAGE_RECEIVED, (message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
this.whatsapp.on(Events.MESSAGE_CREATE, (message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
this.whatsapp.on(Events.STATE_CHANGED, handler)
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
// We do not download media here
|
||||
this.whatsapp.on(Events.MESSAGE_ACK, (message) => this.toWAMessage(message).then(handler))
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
this.whatsapp.on(Events.GROUP_JOIN, handler)
|
||||
} else if (event === WAEvents.GROUP_LEAVE) {
|
||||
this.whatsapp.on(Events.GROUP_LEAVE, handler)
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`)
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage)
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id._serialized,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message.rawData,
|
||||
})
|
||||
}
|
||||
|
||||
protected toWAContact(contact: Contact) {
|
||||
// @ts-ignore
|
||||
contact.id = contact.id._serialized
|
||||
return contact
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id._serialized, "", undefined)
|
||||
return message
|
||||
protected buildClient() {
|
||||
return new Client({
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
executablePath: this.getBrowserExecutablePath(),
|
||||
args: this.getBrowserArgsForPuppeteer(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async start() {
|
||||
this.whatsapp = this.buildClient();
|
||||
|
||||
this.whatsapp.initialize().catch((error) => {
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
this.log.error(error);
|
||||
return;
|
||||
});
|
||||
|
||||
// Connect events
|
||||
this.whatsapp.on(Events.QR_RECEIVED, (qr) => {
|
||||
qrcode.generate(qr, { small: true });
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE;
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.AUTHENTICATED, () => {
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
this.log.log(`Session '${this.name}' has been authenticated!`);
|
||||
});
|
||||
this.events.emit(WAHAInternalEvent.engine_start);
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.FAILED) {
|
||||
throw new UnprocessableEntityException(
|
||||
`The session under FAILED status. Please try to restart it.`,
|
||||
);
|
||||
}
|
||||
return await this.whatsapp.pupPage.screenshot();
|
||||
}
|
||||
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const exist = await this.whatsapp.isRegisteredUser(
|
||||
this.ensureSuffix(request.phone),
|
||||
);
|
||||
return { numberExists: exist };
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.text,
|
||||
);
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
id: button.id,
|
||||
body: button.text,
|
||||
};
|
||||
});
|
||||
const message = new Buttons('', buttons, request.title, request.footer);
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
const options = {
|
||||
quotedMessageId: request.reply_to,
|
||||
};
|
||||
return this.whatsapp.sendMessage(request.chatId, request.text, options);
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
async sendLocation(request: MessageLocationRequest) {
|
||||
const location = new Location(
|
||||
request.latitude,
|
||||
request.longitude,
|
||||
request.title,
|
||||
);
|
||||
return this.whatsapp.sendMessage(request.chatId, location);
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.sendSeen();
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.sendStateTyping();
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.clearState();
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(
|
||||
this.ensureSuffix(query.chatId),
|
||||
);
|
||||
const messages = await chat.fetchMessages({
|
||||
limit: query.limit,
|
||||
});
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = [];
|
||||
for (const message of messages) {
|
||||
result.push(await this.processIncomingMessage(message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const messageId = this.deserializeId(request.messageId);
|
||||
// Recreate instance to react on it
|
||||
const message = new MessageInstance(this.whatsapp);
|
||||
message.id = messageId;
|
||||
message._data = { id: messageId };
|
||||
|
||||
return message.react(request.reaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
return this.whatsapp
|
||||
.getContactById(this.ensureSuffix(query.contactId))
|
||||
.then(this.toWAContact);
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
return this.whatsapp
|
||||
.getContacts()
|
||||
.then((contacts) => contacts.map(this.toWAContact));
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(query.contactId),
|
||||
);
|
||||
return { about: await contact.getAbout() };
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(query.contactId),
|
||||
);
|
||||
return { profilePictureURL: await contact.getProfilePicUrl() };
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(request.contactId),
|
||||
);
|
||||
await contact.block();
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(request.contactId),
|
||||
);
|
||||
await contact.unblock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return this.whatsapp.createGroup(request.name, participantIds);
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
return this.whatsapp
|
||||
.getChats()
|
||||
.then((chats) => chats.filter((chat) => chat.isGroup));
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
return this.whatsapp.getChatById(id);
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.delete();
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.leave();
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.setDescription(description);
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.setSubject(subject);
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.getInviteCode();
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
await groupChat.revokeInvite();
|
||||
return groupChat.getInviteCode();
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.participants;
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.addParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.removeParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.promoteParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.demoteParticipants(participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
this.whatsapp.on(Events.MESSAGE_RECEIVED, (message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
this.whatsapp.on(Events.MESSAGE_CREATE, (message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
this.whatsapp.on(Events.STATE_CHANGED, handler);
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
// We do not download media here
|
||||
this.whatsapp.on(Events.MESSAGE_ACK, (message) =>
|
||||
this.toWAMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
this.whatsapp.on(Events.GROUP_JOIN, handler);
|
||||
} else if (event === WAEvents.GROUP_LEAVE) {
|
||||
this.whatsapp.on(Events.GROUP_LEAVE, handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage);
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id._serialized,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message.rawData,
|
||||
});
|
||||
}
|
||||
|
||||
protected toWAContact(contact: Contact) {
|
||||
// @ts-ignore
|
||||
contact.id = contact.id._serialized;
|
||||
return contact;
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(
|
||||
message.id._serialized,
|
||||
'',
|
||||
undefined,
|
||||
);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-13
@@ -1,12 +1,18 @@
|
||||
import { DOCS_URL } from "./exceptions";
|
||||
import { LocalSessionStorage, MediaStorage } from "./abc/storage.abc";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import { DOCS_URL } from './exceptions';
|
||||
import { LocalSessionStorage, MediaStorage } from './abc/storage.abc';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
|
||||
export class MediaStorageCore implements MediaStorage {
|
||||
async save(messageId: string, mimetype: string, buffer: Buffer): Promise<string> {
|
||||
return Promise.resolve(`Media attachment's available only in WAHA Plus version. ${DOCS_URL}`);
|
||||
async save(
|
||||
messageId: string,
|
||||
mimetype: string,
|
||||
buffer: Buffer,
|
||||
): Promise<string> {
|
||||
return Promise.resolve(
|
||||
`Media attachment's available only in WAHA Plus version. ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +21,15 @@ export class SessionStorageCore extends LocalSessionStorage {
|
||||
|
||||
constructor(engine: string) {
|
||||
super(engine);
|
||||
this.sessionsFolder = path.join(os.tmpdir(), 'waha-')
|
||||
this.sessionsFolder = path.join(os.tmpdir(), 'waha-');
|
||||
}
|
||||
|
||||
get engineFolder(){
|
||||
get engineFolder() {
|
||||
return path.join(this.sessionsFolder, this.engine);
|
||||
}
|
||||
|
||||
init() {
|
||||
fs.mkdirSync(this.engineFolder, {recursive: true});
|
||||
fs.mkdirSync(this.engineFolder, { recursive: true });
|
||||
}
|
||||
|
||||
getFolderPath(name: string): string {
|
||||
@@ -36,8 +42,9 @@ export class SessionStorageCore extends LocalSessionStorage {
|
||||
}
|
||||
|
||||
getAll(): string[] {
|
||||
return fs.readdirSync(this.engineFolder, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
return fs
|
||||
.readdirSync(this.engineFolder, { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,66 @@
|
||||
import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger";
|
||||
import {INestApplication} from "@nestjs/common";
|
||||
import {VERSION} from "../version";
|
||||
import { WhatsappConfigService } from "../config.service";
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { VERSION } from '../version';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
|
||||
export class SwaggerModuleCore {
|
||||
configure(app: INestApplication) {
|
||||
this.setUpAuth(app)
|
||||
const builder = new DocumentBuilder()
|
||||
configure(app: INestApplication) {
|
||||
this.setUpAuth(app);
|
||||
const builder = new DocumentBuilder();
|
||||
|
||||
builder
|
||||
.setTitle('WAHA - WhatsApp HTTP API')
|
||||
.setDescription('WhatsApp HTTP API that you can configure in a click!')
|
||||
.setExternalDoc("Documentation", "https://waha.devlike.pro/")
|
||||
.setVersion(VERSION.version)
|
||||
.addTag('sessions', 'Control WhatsApp sessions')
|
||||
.addTag('screenshot', 'Get screenshot of WhatsApp and show QR code')
|
||||
.addTag('chatting', 'Chat methods')
|
||||
.addTag(
|
||||
'contacts',
|
||||
`Contacts methods.<br>
|
||||
builder
|
||||
.setTitle('WAHA - WhatsApp HTTP API')
|
||||
.setDescription('WhatsApp HTTP API that you can configure in a click!')
|
||||
.setExternalDoc('Documentation', 'https://waha.devlike.pro/')
|
||||
.setVersion(VERSION.version)
|
||||
.addTag('sessions', 'Control WhatsApp sessions')
|
||||
.addTag('screenshot', 'Get screenshot of WhatsApp and show QR code')
|
||||
.addTag('chatting', 'Chat methods')
|
||||
.addTag(
|
||||
'contacts',
|
||||
`Contacts methods.<br>
|
||||
Use phone number (without +) or phone number and \`@c.us\` at the end as \`contactId\`.<br>
|
||||
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`
|
||||
)
|
||||
.addTag(
|
||||
'groups',
|
||||
`Groups methods.<br>`
|
||||
)
|
||||
.addTag('other', 'Other methods')
|
||||
.addApiKey({
|
||||
type: 'apiKey',
|
||||
description: 'Your secret api key',
|
||||
name: 'X-Api-Key'
|
||||
}
|
||||
)
|
||||
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`,
|
||||
)
|
||||
.addTag('groups', `Groups methods.<br>`)
|
||||
.addTag('other', 'Other methods')
|
||||
.addApiKey({
|
||||
type: 'apiKey',
|
||||
description: 'Your secret api key',
|
||||
name: 'X-Api-Key',
|
||||
});
|
||||
|
||||
const config = app.get(WhatsappConfigService)
|
||||
if (config.getSwaggerAdvancedConfigEnabled()){
|
||||
builder.addServer(
|
||||
"{protocol}://{host}:{port}/{baseUrl}",
|
||||
"",
|
||||
{
|
||||
"protocol": {
|
||||
"default": "http",
|
||||
"enum": ["http", "https"],
|
||||
"description": "The protocol used to access the server."
|
||||
},
|
||||
"host": {
|
||||
"default": config.hostname,
|
||||
"description": "The hostname or IP address of the server."
|
||||
},
|
||||
"port": {
|
||||
"default": config.port,
|
||||
"description": "The port number on which the server is listening for requests"
|
||||
},
|
||||
"baseUrl": {
|
||||
"default": "",
|
||||
"description": "The base URL path for all API endpoints. This can be used to group related endpoints together under a common path.",
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const options = builder.build()
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
SwaggerModule.setup('', app, document);
|
||||
const config = app.get(WhatsappConfigService);
|
||||
if (config.getSwaggerAdvancedConfigEnabled()) {
|
||||
builder.addServer('{protocol}://{host}:{port}/{baseUrl}', '', {
|
||||
protocol: {
|
||||
default: 'http',
|
||||
enum: ['http', 'https'],
|
||||
description: 'The protocol used to access the server.',
|
||||
},
|
||||
host: {
|
||||
default: config.hostname,
|
||||
description: 'The hostname or IP address of the server.',
|
||||
},
|
||||
port: {
|
||||
default: config.port,
|
||||
description:
|
||||
'The port number on which the server is listening for requests',
|
||||
},
|
||||
baseUrl: {
|
||||
default: '',
|
||||
description:
|
||||
'The base URL path for all API endpoints. This can be used to group related endpoints together under a common path.',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected setUpAuth(app: INestApplication) {
|
||||
return undefined
|
||||
}
|
||||
const options = builder.build();
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
SwaggerModule.setup('', app, document);
|
||||
}
|
||||
|
||||
protected setUpAuth(app: INestApplication) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
+72
-70
@@ -1,81 +1,83 @@
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {ConsoleLogger} from "@nestjs/common";
|
||||
import {WAEvents} from "../structures/enums.dto";
|
||||
import {WAWebhook} from "../structures/responses.dto";
|
||||
import {NotImplementedByEngineError} from "./exceptions";
|
||||
import {WebhookConductor} from "./abc/webhooks.abc";
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import { ConsoleLogger } from '@nestjs/common';
|
||||
import { WAEvents } from '../structures/enums.dto';
|
||||
import { WAWebhook } from '../structures/responses.dto';
|
||||
import { NotImplementedByEngineError } from './exceptions';
|
||||
import { WebhookConductor } from './abc/webhooks.abc';
|
||||
import request = require('request');
|
||||
|
||||
|
||||
export class WebhookConductorCore implements WebhookConductor {
|
||||
constructor(protected log: ConsoleLogger, private readonly url, private readonly events: WAEvents[] | string[]) {
|
||||
this.url = url
|
||||
this.events = this.getSuitableEvents(events)
|
||||
this.log = log
|
||||
constructor(
|
||||
protected log: ConsoleLogger,
|
||||
private readonly url,
|
||||
private readonly events: WAEvents[] | string[],
|
||||
) {
|
||||
this.url = url;
|
||||
this.events = this.getSuitableEvents(events);
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
private getSuitableEvents(events: WAEvents[] | string[]) {
|
||||
const allEvents = Object.values(WAEvents);
|
||||
|
||||
// Enable all events if * in the events
|
||||
// @ts-ignore
|
||||
if (events.includes('*')) {
|
||||
return allEvents;
|
||||
}
|
||||
|
||||
private getSuitableEvents(events: WAEvents[] | string[]) {
|
||||
const allEvents = Object.values(WAEvents)
|
||||
// Get only known events, log and ignore others
|
||||
const rightEvents = [];
|
||||
for (const event of events) {
|
||||
// @ts-ignore
|
||||
if (!allEvents.includes(event)) {
|
||||
this.log.error(`Unknown event for webhook: '${event}'`);
|
||||
continue;
|
||||
}
|
||||
rightEvents.push(event);
|
||||
}
|
||||
return rightEvents;
|
||||
}
|
||||
|
||||
// Enable all events if * in the events
|
||||
// @ts-ignore
|
||||
if (events.includes("*")) {
|
||||
return allEvents
|
||||
public configure(session: WhatsappSession) {
|
||||
this.log.log('Configuring webhooks...');
|
||||
for (const event of this.events) {
|
||||
try {
|
||||
session.subscribe(event, (data: any) =>
|
||||
this.callWebhook(event, session, data, this.url),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof NotImplementedByEngineError) {
|
||||
this.log.error(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Get only known events, log and ignore others
|
||||
const rightEvents = []
|
||||
for (const event of events) {
|
||||
// @ts-ignore
|
||||
if (!allEvents.includes(event)) {
|
||||
this.log.error(`Unknown event for webhook: '${event}'`)
|
||||
continue
|
||||
}
|
||||
rightEvents.push(event)
|
||||
}
|
||||
return rightEvents
|
||||
}
|
||||
this.log.log(`Event '${event}' is enabled for url: ${this.url}`);
|
||||
}
|
||||
this.log.log('Webhooks were configured.');
|
||||
}
|
||||
|
||||
public configure(session: WhatsappSession) {
|
||||
this.log.log('Configuring webhooks...')
|
||||
for (const event of this.events) {
|
||||
try {
|
||||
session.subscribe(event, (data: any) => this.callWebhook(event, session, data, this.url))
|
||||
} catch (error) {
|
||||
if (error instanceof NotImplementedByEngineError) {
|
||||
this.log.error(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
this.log.log(`Event '${event}' is enabled for url: ${this.url}`)
|
||||
}
|
||||
this.log.log('Webhooks were configured.')
|
||||
}
|
||||
public callWebhook(event, session: WhatsappSession, data: any, url) {
|
||||
const json: WAWebhook = {
|
||||
event: event,
|
||||
session: session.name,
|
||||
payload: data,
|
||||
engine: session.engine,
|
||||
};
|
||||
this.log.log(`Sending POST to ${url}...`);
|
||||
this.log.debug(`POST DATA: ${JSON.stringify(json)}`);
|
||||
this.post(json, url);
|
||||
}
|
||||
|
||||
public callWebhook(event, session: WhatsappSession, data: any, url) {
|
||||
const json: WAWebhook = {
|
||||
event: event,
|
||||
session: session.name,
|
||||
payload: data,
|
||||
engine: session.engine,
|
||||
}
|
||||
this.log.log(`Sending POST to ${url}...`)
|
||||
this.log.debug(`POST DATA: ${JSON.stringify(json)}`)
|
||||
this.post(json, url)
|
||||
}
|
||||
|
||||
protected post(json, url) {
|
||||
request.post(
|
||||
url,
|
||||
{json: json},
|
||||
(error, res, body) => {
|
||||
if (error) {
|
||||
this.log.error(error)
|
||||
return
|
||||
}
|
||||
this.log.log(`POST request was sent with status code: ${res.statusCode}`)
|
||||
this.log.verbose(`Response: ${JSON.stringify(body)}`)
|
||||
})
|
||||
}
|
||||
protected post(json, url) {
|
||||
request.post(url, { json: json }, (error, res, body) => {
|
||||
if (error) {
|
||||
this.log.error(error);
|
||||
return;
|
||||
}
|
||||
this.log.log(`POST request was sent with status code: ${res.statusCode}`);
|
||||
this.log.verbose(`Response: ${JSON.stringify(body)}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -2,13 +2,19 @@ export function parseBool(value: any): boolean {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
if (value.toLowerCase() === "true" || value.toLowerCase() === "1") {
|
||||
if (value.toLowerCase() === 'true' || value.toLowerCase() === '1') {
|
||||
return true;
|
||||
}
|
||||
if (value.toLowerCase() === "false" || value.toLowerCase() === "0") {
|
||||
if (value.toLowerCase() === 'false' || value.toLowerCase() === '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.error("parseBool got an unexpected value:", value, "(accepted values : \"true\", \"false\")");
|
||||
throw new Error("Error: parseBool got unexpected value - use \"true\" or \"false\" values");
|
||||
console.error(
|
||||
'parseBool got an unexpected value:',
|
||||
value,
|
||||
'(accepted values : "true", "false")',
|
||||
);
|
||||
throw new Error(
|
||||
'Error: parseBool got unexpected value - use "true" or "false" values',
|
||||
);
|
||||
}
|
||||
+41
-37
@@ -1,49 +1,53 @@
|
||||
import {NestFactory} from '@nestjs/core';
|
||||
import {WhatsappConfigService} from "./config.service";
|
||||
import {AllExceptionsFilter} from "./api/exception.filter";
|
||||
import {getWAHAVersion, VERSION, WAHAVersion} from "./version";
|
||||
import {AppModuleCore} from "./core/app.module.core";
|
||||
import {SwaggerModuleCore} from "./core/swagger.module.core";
|
||||
import {json, urlencoded} from "express";
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { WhatsappConfigService } from './config.service';
|
||||
import { AllExceptionsFilter } from './api/exception.filter';
|
||||
import { getWAHAVersion, VERSION, WAHAVersion } from './version';
|
||||
import { AppModuleCore } from './core/app.module.core';
|
||||
import { SwaggerModuleCore } from './core/swagger.module.core';
|
||||
import { json, urlencoded } from 'express';
|
||||
|
||||
async function loadModules(): Promise<[typeof AppModuleCore, typeof SwaggerModuleCore]> {
|
||||
const version = getWAHAVersion()
|
||||
console.log(`WAHA (WhatsApp HTTP API) - Running ${version} version...`)
|
||||
async function loadModules(): Promise<
|
||||
[typeof AppModuleCore, typeof SwaggerModuleCore]
|
||||
> {
|
||||
const version = getWAHAVersion();
|
||||
console.log(`WAHA (WhatsApp HTTP API) - Running ${version} version...`);
|
||||
|
||||
if (version === WAHAVersion.CORE) {
|
||||
const {AppModuleCore} = await import("./core/app.module.core")
|
||||
const {SwaggerModuleCore} = await import("./core/swagger.module.core")
|
||||
return [AppModuleCore, SwaggerModuleCore]
|
||||
}
|
||||
// Ignore if it's core version - there's no plus module
|
||||
// @ts-ignore
|
||||
const {AppModulePlus} = await import("./plus/app.module.plus")
|
||||
// @ts-ignore
|
||||
const {SwaggerModulePlus} = await import("./plus/swagger.module.plus")
|
||||
return [AppModulePlus, SwaggerModulePlus]
|
||||
if (version === WAHAVersion.CORE) {
|
||||
const { AppModuleCore } = await import('./core/app.module.core');
|
||||
const { SwaggerModuleCore } = await import('./core/swagger.module.core');
|
||||
return [AppModuleCore, SwaggerModuleCore];
|
||||
}
|
||||
// Ignore if it's core version - there's no plus module
|
||||
// @ts-ignore
|
||||
const { AppModulePlus } = await import('./plus/app.module.plus');
|
||||
// @ts-ignore
|
||||
const { SwaggerModulePlus } = await import('./plus/swagger.module.plus');
|
||||
return [AppModulePlus, SwaggerModulePlus];
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
const [AppModule, SwaggerModule] = await loadModules()
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
logger: process.env.DEBUG != undefined ? ['log', 'debug', 'error', 'verbose', 'warn'] :
|
||||
['log', 'error', 'warn'],
|
||||
});
|
||||
const [AppModule, SwaggerModule] = await loadModules();
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
logger:
|
||||
process.env.DEBUG != undefined
|
||||
? ['log', 'debug', 'error', 'verbose', 'warn']
|
||||
: ['log', 'error', 'warn'],
|
||||
});
|
||||
|
||||
app.enableShutdownHooks();
|
||||
app.useGlobalFilters(new AllExceptionsFilter());
|
||||
app.enableShutdownHooks();
|
||||
app.useGlobalFilters(new AllExceptionsFilter());
|
||||
|
||||
// Allow to send big body - for images and attachments
|
||||
app.use(json({limit: '50mb'}));
|
||||
app.use(urlencoded({limit: '50mb', extended: false}));
|
||||
// Allow to send big body - for images and attachments
|
||||
app.use(json({ limit: '50mb' }));
|
||||
app.use(urlencoded({ limit: '50mb', extended: false }));
|
||||
|
||||
// Configure swagger
|
||||
const swagger = new SwaggerModule()
|
||||
swagger.configure(app)
|
||||
// Configure swagger
|
||||
const swagger = new SwaggerModule();
|
||||
swagger.configure(app);
|
||||
|
||||
const config = app.get(WhatsappConfigService);
|
||||
await app.listen(config.port);
|
||||
console.log(`WhatsApp HTTP API is running on: ${await app.getUrl()}`);
|
||||
const config = app.get(WhatsappConfigService);
|
||||
await app.listen(config.port);
|
||||
console.log(`WhatsApp HTTP API is running on: ${await app.getUrl()}`);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
@@ -1,13 +1,13 @@
|
||||
import {IsNotEmpty} from "class-validator";
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
|
||||
export const WHATSAPP_DEFAULT_SESSION_NAME = "default"
|
||||
export const WHATSAPP_DEFAULT_SESSION_NAME = 'default';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class SessionQuery {
|
||||
@IsNotEmpty()
|
||||
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
@IsNotEmpty()
|
||||
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,5 +15,5 @@ export class SessionQuery {
|
||||
*/
|
||||
|
||||
export class SessionBaseRequest {
|
||||
session = WHATSAPP_DEFAULT_SESSION_NAME
|
||||
session = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
}
|
||||
+135
-132
@@ -1,218 +1,221 @@
|
||||
import {IsNotEmpty, IsString, IsOptional, IsNumber} from "class-validator";
|
||||
import {ApiExtraModels, ApiProperty, getSchemaPath} from "@nestjs/swagger";
|
||||
import {SessionBaseRequest, SessionQuery} from "./base.dto";
|
||||
|
||||
import { IsNotEmpty, IsString, IsOptional, IsNumber } from 'class-validator';
|
||||
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
|
||||
import { SessionBaseRequest, SessionQuery } from './base.dto';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class CheckNumberStatusQuery extends SessionQuery {
|
||||
@IsString()
|
||||
phone: string
|
||||
@IsString()
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export class MessageTextQuery extends SessionQuery {
|
||||
@IsString()
|
||||
phone: string
|
||||
@IsString()
|
||||
text: string
|
||||
@IsString()
|
||||
phone: string;
|
||||
@IsString()
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class ChatQuery extends SessionQuery {
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string;
|
||||
}
|
||||
|
||||
export class GetMessageQuery extends ChatQuery {
|
||||
@IsNumber()
|
||||
limit: number
|
||||
@IsNumber()
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
export class ChatRequest extends SessionBaseRequest {
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string;
|
||||
}
|
||||
|
||||
export class SendSeenRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
required: false,
|
||||
description: "NOWEB engine only - it's important to mark ALL messages as seen"
|
||||
})
|
||||
messageId?: string
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
required: false,
|
||||
description:
|
||||
"NOWEB engine only - it's important to mark ALL messages as seen",
|
||||
})
|
||||
messageId?: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
required: false,
|
||||
description: "NOWEB engine only - the ID of the user that sent the message (undefined for individual chats)"
|
||||
})
|
||||
participant?: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
required: false,
|
||||
description:
|
||||
'NOWEB engine only - the ID of the user that sent the message (undefined for individual chats)',
|
||||
})
|
||||
participant?: string;
|
||||
}
|
||||
|
||||
export class MessageRequest extends SessionBaseRequest {
|
||||
@ApiProperty({
|
||||
example: "false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA",
|
||||
})
|
||||
messageId: string
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
export class MessageContactVcardRequest extends ChatRequest {
|
||||
contactsId: string;
|
||||
name: string
|
||||
contactsId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class MessageTextRequest extends ChatRequest {
|
||||
text = "Hi there!"
|
||||
text = 'Hi there!';
|
||||
}
|
||||
|
||||
export class Button {
|
||||
id: string
|
||||
text: string
|
||||
id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class MessageTextButtonsRequest extends ChatRequest {
|
||||
title: string;
|
||||
footer?: string
|
||||
buttons?: Array<Button>;
|
||||
title: string;
|
||||
footer?: string;
|
||||
buttons?: Array<Button>;
|
||||
}
|
||||
|
||||
export class MessageReplyRequest extends ChatRequest {
|
||||
text = "Reply text"
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
reply_to: string;
|
||||
text = 'Reply text';
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
reply_to: string;
|
||||
}
|
||||
|
||||
export class MessageLocationRequest extends ChatRequest {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
title: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export class RemoteFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Value can be null",
|
||||
example: 'filename.jpg',
|
||||
})
|
||||
filename?: string | null
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Value can be null',
|
||||
example: 'filename.jpg',
|
||||
})
|
||||
filename?: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.jpg',
|
||||
})
|
||||
url: string
|
||||
@ApiProperty({
|
||||
example:
|
||||
'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.jpg',
|
||||
})
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class BinaryFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
example: 'filename.jpeg',
|
||||
})
|
||||
filename?: string | null
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
example: 'filename.jpeg',
|
||||
})
|
||||
filename?: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Base64-encoded data of the file",
|
||||
example: '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',
|
||||
})
|
||||
data: string
|
||||
@ApiProperty({
|
||||
description: 'Base64-encoded data of the file',
|
||||
example:
|
||||
'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',
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@ApiExtraModels(BinaryFile, RemoteFile)
|
||||
class FileRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{$ref: getSchemaPath(BinaryFile)},
|
||||
{$ref: getSchemaPath(RemoteFile)},
|
||||
],
|
||||
})
|
||||
file: BinaryFile | RemoteFile
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(BinaryFile) },
|
||||
{ $ref: getSchemaPath(RemoteFile) },
|
||||
],
|
||||
})
|
||||
file: BinaryFile | RemoteFile;
|
||||
}
|
||||
|
||||
export class MessageImageRequest extends FileRequest {
|
||||
caption: string;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
export class MessageFileRequest extends FileRequest {
|
||||
caption: string;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
export class VoiceBinaryFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
})
|
||||
mimetype = "audio/ogg; codecs=opus"
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
})
|
||||
mimetype = 'audio/ogg; codecs=opus';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
})
|
||||
filename = "voice-message.mp3"
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
})
|
||||
filename = 'voice-message.mp3';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Base64-encoded data of the file",
|
||||
example: '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
Line truncated
|
||||
})
|
||||
data: string
|
||||
@ApiProperty({
|
||||
description: 'Base64-encoded data of the file',
|
||||
example:
|
||||
'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
Line truncated
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
export class VoiceRemoteFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
})
|
||||
mimetype = "audio/ogg; codecs=opus"
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
})
|
||||
mimetype = 'audio/ogg; codecs=opus';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
})
|
||||
filename = "voice-message.mp3"
|
||||
|
||||
@ApiProperty({
|
||||
example: 'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.mp3',
|
||||
})
|
||||
url: string
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
})
|
||||
filename = 'voice-message.mp3';
|
||||
|
||||
@ApiProperty({
|
||||
example:
|
||||
'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.mp3',
|
||||
})
|
||||
url: string;
|
||||
}
|
||||
|
||||
@ApiExtraModels(VoiceBinaryFile, VoiceRemoteFile)
|
||||
export class MessageVoiceRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{$ref: getSchemaPath(VoiceBinaryFile)},
|
||||
{$ref: getSchemaPath(VoiceRemoteFile)},
|
||||
],
|
||||
})
|
||||
file: VoiceBinaryFile | VoiceRemoteFile
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(VoiceBinaryFile) },
|
||||
{ $ref: getSchemaPath(VoiceRemoteFile) },
|
||||
],
|
||||
})
|
||||
file: VoiceBinaryFile | VoiceRemoteFile;
|
||||
}
|
||||
|
||||
export class MessageLinkPreviewRequest extends ChatRequest {
|
||||
url: string;
|
||||
title: string;
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export class MessageReactionRequest extends MessageRequest {
|
||||
@ApiProperty({
|
||||
description: "Emoji to react with. Send an empty string to remove the reaction",
|
||||
example: '👍',
|
||||
})
|
||||
reaction: string
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Emoji to react with. Send an empty string to remove the reaction',
|
||||
example: '👍',
|
||||
})
|
||||
reaction: string;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import {IsString} from "class-validator";
|
||||
import {SessionBaseRequest, SessionQuery} from "./base.dto";
|
||||
|
||||
import { IsString } from 'class-validator';
|
||||
import { SessionBaseRequest, SessionQuery } from './base.dto';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
|
||||
export class ContactQuery extends SessionQuery {
|
||||
@IsString()
|
||||
contactId: string
|
||||
@IsString()
|
||||
contactId: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
|
||||
export class ContactRequest extends SessionBaseRequest {
|
||||
@IsString()
|
||||
contactId: string
|
||||
@IsString()
|
||||
contactId: string;
|
||||
}
|
||||
+14
-14
@@ -1,24 +1,24 @@
|
||||
export const SECOND = 1000;
|
||||
|
||||
export enum WAEvents {
|
||||
MESSAGE = "message",
|
||||
MESSAGE_ANY = "message.any",
|
||||
MESSAGE_ACK = "message.ack",
|
||||
STATE_CHANGE = "state.change",
|
||||
GROUP_JOIN = "group.join",
|
||||
GROUP_LEAVE = "group.leave",
|
||||
MESSAGE = 'message',
|
||||
MESSAGE_ANY = 'message.any',
|
||||
MESSAGE_ACK = 'message.ack',
|
||||
STATE_CHANGE = 'state.change',
|
||||
GROUP_JOIN = 'group.join',
|
||||
GROUP_LEAVE = 'group.leave',
|
||||
}
|
||||
|
||||
export enum WhatsappStatus {
|
||||
STOPPED = "STOPPED",
|
||||
STARTING = "STARTING",
|
||||
SCAN_QR_CODE = "SCAN_QR_CODE",
|
||||
WORKING = "WORKING",
|
||||
FAILED = "FAILED",
|
||||
STOPPED = 'STOPPED',
|
||||
STARTING = 'STARTING',
|
||||
SCAN_QR_CODE = 'SCAN_QR_CODE',
|
||||
WORKING = 'WORKING',
|
||||
FAILED = 'FAILED',
|
||||
}
|
||||
|
||||
export enum WhatsappEngine {
|
||||
VENOM = "VENOM",
|
||||
WEBJS = "WEBJS",
|
||||
NOWEB = "NOWEB",
|
||||
VENOM = 'VENOM',
|
||||
WEBJS = 'WEBJS',
|
||||
NOWEB = 'NOWEB',
|
||||
}
|
||||
@@ -1,40 +1,39 @@
|
||||
import {IsArray, IsString} from "class-validator";
|
||||
import { IsArray, IsString } from 'class-validator';
|
||||
|
||||
/**
|
||||
* Structures
|
||||
*/
|
||||
export class Participant {
|
||||
@IsString()
|
||||
id: string
|
||||
@IsString()
|
||||
id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
|
||||
export class ParticipantsRequest {
|
||||
@IsArray()
|
||||
participants: Array<Participant>
|
||||
@IsArray()
|
||||
participants: Array<Participant>;
|
||||
}
|
||||
|
||||
export class DescriptionRequest {
|
||||
@IsString()
|
||||
description: string
|
||||
@IsString()
|
||||
description: string;
|
||||
}
|
||||
export class SubjectRequest {
|
||||
@IsString()
|
||||
subject: string
|
||||
@IsString()
|
||||
subject: string;
|
||||
}
|
||||
|
||||
export class CreateGroupRequest {
|
||||
@IsString()
|
||||
name: string
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@IsArray()
|
||||
participants: Array<Participant>
|
||||
@IsArray()
|
||||
participants: Array<Participant>;
|
||||
}
|
||||
+109
-106
@@ -1,145 +1,148 @@
|
||||
import {ApiProperty} from "@nestjs/swagger";
|
||||
import { WAEvents, WhatsappEngine } from "./enums.dto";
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { WAEvents, WhatsappEngine } from './enums.dto';
|
||||
|
||||
export class WANumberExistResult {
|
||||
numberExists: boolean
|
||||
numberExists: boolean;
|
||||
}
|
||||
|
||||
|
||||
export class WAGroupNotification {
|
||||
@ApiProperty({
|
||||
description: "ID that represents the groupNotification",
|
||||
})
|
||||
id: any
|
||||
@ApiProperty({
|
||||
description: 'ID that represents the groupNotification',
|
||||
})
|
||||
id: any;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Unix timestamp for when the groupNotification was created",
|
||||
})
|
||||
timestamp: number
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp for when the groupNotification was created',
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ID for the Chat that this groupNotification was sent for",
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
description: 'ID for the Chat that this groupNotification was sent for',
|
||||
})
|
||||
chatId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ContactId for the user that produced the GroupNotification',
|
||||
})
|
||||
author: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ContactId for the user that produced the GroupNotification",
|
||||
})
|
||||
author: string
|
||||
@ApiProperty({
|
||||
description: 'Extra content',
|
||||
})
|
||||
body: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Extra content",
|
||||
})
|
||||
body: string
|
||||
|
||||
@ApiProperty({
|
||||
description: "Contact IDs for the users that were affected by this GroupNotification",
|
||||
})
|
||||
recipientIds: string[]
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Contact IDs for the users that were affected by this GroupNotification',
|
||||
})
|
||||
recipientIds: string[];
|
||||
}
|
||||
|
||||
export enum WAMessageAck {
|
||||
ACK_ERROR = -1,
|
||||
ACK_PENDING = 0,
|
||||
ACK_SERVER = 1,
|
||||
ACK_DEVICE = 2,
|
||||
ACK_READ = 3,
|
||||
ACK_PLAYED = 4,
|
||||
ACK_ERROR = -1,
|
||||
ACK_PENDING = 0,
|
||||
ACK_SERVER = 1,
|
||||
ACK_DEVICE = 2,
|
||||
ACK_READ = 3,
|
||||
ACK_PLAYED = 4,
|
||||
}
|
||||
|
||||
export class WALocation {
|
||||
description?: string | null
|
||||
latitude: string
|
||||
longitude: string
|
||||
description?: string | null;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
}
|
||||
|
||||
|
||||
export class WAMessage {
|
||||
@ApiProperty({
|
||||
description: "Message ID",
|
||||
example: "false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA"
|
||||
})
|
||||
id: string
|
||||
@ApiProperty({
|
||||
description: 'Message ID',
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
id: string;
|
||||
|
||||
/** */
|
||||
@ApiProperty({
|
||||
description: "Unix timestamp for when the message was created",
|
||||
example: 1666943582
|
||||
})
|
||||
timestamp: number
|
||||
/** */
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp for when the message was created',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ID for the Chat that this message was sent to, except if the message was sent by the current user "
|
||||
})
|
||||
from: string
|
||||
@ApiProperty({
|
||||
description:
|
||||
'ID for the Chat that this message was sent to, except if the message was sent by the current user ',
|
||||
})
|
||||
from: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Indicates if the message was sent by the current user"
|
||||
})
|
||||
fromMe: boolean
|
||||
@ApiProperty({
|
||||
description: 'Indicates if the message was sent by the current user',
|
||||
})
|
||||
fromMe: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: `
|
||||
@ApiProperty({
|
||||
description: `
|
||||
* ID for who this message is for.
|
||||
* If the message is sent by the current user, it will be the Chat to which the message is being sent.
|
||||
* If the message is sent by another user, it will be the ID for the current user.
|
||||
`
|
||||
})
|
||||
to: string
|
||||
`,
|
||||
})
|
||||
to: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "For groups - participant who sent the message"
|
||||
})
|
||||
participant: string
|
||||
@ApiProperty({
|
||||
description: 'For groups - participant who sent the message',
|
||||
})
|
||||
participant: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Message content"
|
||||
})
|
||||
body: string
|
||||
@ApiProperty({
|
||||
description: 'Message content',
|
||||
})
|
||||
body: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Indicates if the message has media available for download"
|
||||
})
|
||||
hasMedia: boolean
|
||||
@ApiProperty({
|
||||
description: 'Indicates if the message has media available for download',
|
||||
})
|
||||
hasMedia: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: "The URL for the media in the message if any",
|
||||
example: "http://localhost:3000/api/files/false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA.oga"
|
||||
})
|
||||
mediaUrl: string
|
||||
@ApiProperty({
|
||||
description: 'The URL for the media in the message if any',
|
||||
example:
|
||||
'http://localhost:3000/api/files/false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA.oga',
|
||||
})
|
||||
mediaUrl: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ACK status for the message"
|
||||
})
|
||||
ack: WAMessageAck
|
||||
@ApiProperty({
|
||||
description: 'ACK status for the message',
|
||||
})
|
||||
ack: WAMessageAck;
|
||||
|
||||
@ApiProperty({
|
||||
description: "If the message was sent to a group, this field will contain the user that sent the message."
|
||||
})
|
||||
author?: string;
|
||||
@ApiProperty({
|
||||
description:
|
||||
'If the message was sent to a group, this field will contain the user that sent the message.',
|
||||
})
|
||||
author?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Location information contained in the message, if the message is type \"location\""
|
||||
})
|
||||
location?: WALocation
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Location information contained in the message, if the message is type "location"',
|
||||
})
|
||||
location?: WALocation;
|
||||
|
||||
@ApiProperty({
|
||||
description: "List of vCards contained in the message."
|
||||
})
|
||||
vCards?: string[]
|
||||
@ApiProperty({
|
||||
description: 'List of vCards contained in the message.',
|
||||
})
|
||||
vCards?: string[];
|
||||
|
||||
/** Returns message in a raw format */
|
||||
@ApiProperty({
|
||||
description: "Message in a raw format that we get from WhatsApp. May be changed anytime, use it with caution! It depends a lot on the underlying backend."
|
||||
})
|
||||
_data?: any
|
||||
/** Returns message in a raw format */
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Message in a raw format that we get from WhatsApp. May be changed anytime, use it with caution! It depends a lot on the underlying backend.',
|
||||
})
|
||||
_data?: any;
|
||||
}
|
||||
|
||||
export class WAWebhook {
|
||||
event: WAEvents
|
||||
session: string
|
||||
engine: WhatsappEngine
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
payload: WAMessage | WAGroupNotification | object
|
||||
event: WAEvents;
|
||||
session: string;
|
||||
engine: WhatsappEngine;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
payload: WAMessage | WAGroupNotification | object;
|
||||
}
|
||||
@@ -1,39 +1,40 @@
|
||||
import {WhatsappStatus} from "./enums.dto";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { WhatsappStatus } from './enums.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class ListSessionsQuery {
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description: "Return all sessions, including those that are in the STOPPED state."
|
||||
})
|
||||
all: boolean
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description:
|
||||
'Return all sessions, including those that are in the STOPPED state.',
|
||||
})
|
||||
all: boolean;
|
||||
}
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
export class SessionStartRequest {
|
||||
name = "default"
|
||||
name = 'default';
|
||||
}
|
||||
|
||||
export class SessionStopRequest {
|
||||
name = "default"
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description: "Stop and logout from the session."
|
||||
})
|
||||
logout = false
|
||||
name = 'default';
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description: 'Stop and logout from the session.',
|
||||
})
|
||||
logout = false;
|
||||
}
|
||||
|
||||
export class SessionLogoutRequest {
|
||||
name = "default"
|
||||
name = 'default';
|
||||
}
|
||||
|
||||
export class SessionDTO {
|
||||
name = "default"
|
||||
status: WhatsappStatus
|
||||
name = 'default';
|
||||
status: WhatsappStatus;
|
||||
}
|
||||
+19
-19
@@ -1,34 +1,34 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
import {getBrowserExecutablePath} from "./core/abc/session.abc";
|
||||
import { getBrowserExecutablePath } from './core/abc/session.abc';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs')
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
|
||||
export enum WAHAVersion {
|
||||
PLUS = "PLUS",
|
||||
CORE = "CORE",
|
||||
PLUS = 'PLUS',
|
||||
CORE = 'CORE',
|
||||
}
|
||||
|
||||
export function getWAHAVersion(): WAHAVersion {
|
||||
// force core version if env variables set
|
||||
const waha_version = process.env.WAHA_VERSION;
|
||||
if (waha_version && waha_version === WAHAVersion.CORE) {
|
||||
return WAHAVersion.CORE
|
||||
}
|
||||
// force core version if env variables set
|
||||
const waha_version = process.env.WAHA_VERSION;
|
||||
if (waha_version && waha_version === WAHAVersion.CORE) {
|
||||
return WAHAVersion.CORE;
|
||||
}
|
||||
|
||||
// Check the plus directory exists
|
||||
const plusExists = fs.existsSync(`${__dirname}/plus`)
|
||||
if (plusExists) {
|
||||
return WAHAVersion.PLUS
|
||||
}
|
||||
// Check the plus directory exists
|
||||
const plusExists = fs.existsSync(`${__dirname}/plus`);
|
||||
if (plusExists) {
|
||||
return WAHAVersion.PLUS;
|
||||
}
|
||||
|
||||
return WAHAVersion.CORE
|
||||
return WAHAVersion.CORE;
|
||||
}
|
||||
|
||||
export const VERSION = {
|
||||
version: "2023.5.20",
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath()
|
||||
}
|
||||
version: '2023.5.20',
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath(),
|
||||
};
|
||||
Reference in new issue
Block a user