diff --git a/src/api/auth.controller.ts b/src/api/auth.controller.ts index d6f0cfc9..86a0f847 100644 --- a/src/api/auth.controller.ts +++ b/src/api/auth.controller.ts @@ -10,6 +10,7 @@ import { UnprocessableEntityException } from '@nestjs/common/exceptions/unproces import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { ApiFileAcceptHeader } from '@waha/nestjs/ApiFileAcceptHeader'; import { + QRCodeSessionParam, SessionApiParam, SessionParam, } from '@waha/nestjs/params/SessionApiParam'; @@ -25,7 +26,6 @@ import { QRCodeValue, RequestCodeRequest, } from '../structures/auth.dto'; -import { WAHASessionStatus } from '../structures/enums.dto'; import { Base64File } from '../structures/files.dto'; @ApiSecurity('api_key') @@ -42,13 +42,9 @@ class AuthController { @ApiFileAcceptHeader(Base64File, QRCodeValue) @UseInterceptors(new BufferResponseInterceptor()) async getQR( - @SessionParam session: WhatsappSession, + @QRCodeSessionParam session: WhatsappSession, @Query() query: QRCodeQuery, ): Promise { - if (session.status != WAHASessionStatus.SCAN_QR_CODE) { - const err = `Can get QR code only in SCAN_QR_CODE status. The current status is '${session.status}'`; - throw new UnprocessableEntityException(err); - } const qr = session.getQR(); if (query.format == QRCodeFormat.RAW) { return { value: qr.raw }; diff --git a/src/api/channels.controller.ts b/src/api/channels.controller.ts index a5651cc7..6d9b8d3d 100644 --- a/src/api/channels.controller.ts +++ b/src/api/channels.controller.ts @@ -10,7 +10,7 @@ import { import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { Channel, @@ -33,7 +33,7 @@ export class ChannelsController { @SessionApiParam @ApiOperation({ summary: 'Get list of know channels' }) async list( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Query() query: ListChannelsQuery, ): Promise { return session.channelsList(query); @@ -43,7 +43,7 @@ export class ChannelsController { @SessionApiParam @ApiOperation({ summary: 'Create a new channel.' }) create( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() request: CreateChannelRequest, ): Promise { return session.channelsCreateChannel(request); @@ -53,7 +53,10 @@ export class ChannelsController { @SessionApiParam @NewsletterIdApiParam @ApiOperation({ summary: 'Delete the channel.' }) - delete(@SessionParam session: WhatsappSession, @Param('id') id: string) { + delete( + @WorkingSessionParam session: WhatsappSession, + @Param('id') id: string, + ) { return session.channelsDeleteChannel(id); } @@ -67,7 +70,7 @@ export class ChannelsController { 'OR invite code (https://www.whatsapp.com/channel/123)', }) get( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { if (isNewsletter(id)) { @@ -84,7 +87,7 @@ export class ChannelsController { @NewsletterIdApiParam @ApiOperation({ summary: 'Follow the channel.' }) follow( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.channelsFollowChannel(id); @@ -95,7 +98,7 @@ export class ChannelsController { @NewsletterIdApiParam @ApiOperation({ summary: 'Unfollow the channel.' }) unfollow( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.channelsUnfollowChannel(id); @@ -106,7 +109,7 @@ export class ChannelsController { @NewsletterIdApiParam @ApiOperation({ summary: 'Mute the channel.' }) mute( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.channelsMuteChannel(id); @@ -117,7 +120,7 @@ export class ChannelsController { @NewsletterIdApiParam @ApiOperation({ summary: 'Unmute the channel.' }) unmute( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.channelsUnmuteChannel(id); diff --git a/src/api/chats.controller.ts b/src/api/chats.controller.ts index 9b0ccab3..a2c7e287 100644 --- a/src/api/chats.controller.ts +++ b/src/api/chats.controller.ts @@ -15,7 +15,7 @@ import { ChatIdApiParam } from '@waha/nestjs/params/ChatIdApiParam'; import { MessageIdApiParam } from '@waha/nestjs/params/MessageIdApiParam'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { SessionManager } from '../core/abc/manager.abc'; @@ -35,7 +35,7 @@ class ChatsController { @SessionApiParam @ApiOperation({ summary: 'Get chats' }) getChats( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Query() query: GetChatsQuery, ) { return session.getChats(query); @@ -46,7 +46,7 @@ class ChatsController { @ApiOperation({ summary: 'Deletes the chat' }) @ChatIdApiParam deleteChat( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ) { return session.deleteChat(chatId); @@ -58,7 +58,7 @@ class ChatsController { @ChatIdApiParam getChatMessages( @Query() query: GetChatMessagesQuery, - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ) { const downloadMedia = parseBool(query.downloadMedia); @@ -70,7 +70,7 @@ class ChatsController { @ApiOperation({ summary: 'Clears all messages from the chat' }) @ChatIdApiParam clearMessages( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ) { return session.clearMessages(chatId); @@ -82,7 +82,7 @@ class ChatsController { @MessageIdApiParam @ApiOperation({ summary: 'Deletes a message from the chat' }) deleteMessage( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, @Param('messageId') messageId: string, ) { @@ -95,7 +95,7 @@ class ChatsController { @MessageIdApiParam @ApiOperation({ summary: 'Edits a message in the chat' }) editMessage( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, @Param('messageId') messageId: string, @Body() body: EditMessageRequest, @@ -108,7 +108,7 @@ class ChatsController { @ChatIdApiParam @ApiOperation({ summary: 'Archive the chat' }) archiveChat( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ) { return session.chatsArchiveChat(chatId); @@ -119,7 +119,7 @@ class ChatsController { @ChatIdApiParam @ApiOperation({ summary: 'Unarchive the chat' }) unarchiveChat( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ) { return session.chatsUnarchiveChat(chatId); diff --git a/src/api/chatting.controller.ts b/src/api/chatting.controller.ts index 99935f61..da7b47a9 100644 --- a/src/api/chatting.controller.ts +++ b/src/api/chatting.controller.ts @@ -32,8 +32,8 @@ export class ChattingController { @Post('/sendText') @ApiOperation({ summary: 'Send a text message' }) - sendText(@Body() request: MessageTextRequest): Promise { - const whatsapp = this.manager.getSession(request.session); + async sendText(@Body() request: MessageTextRequest): Promise { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendText(request); } @@ -43,8 +43,8 @@ export class ChattingController { description: '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); + async sendImage(@Body() request: MessageImageRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendImage(request); } @@ -54,8 +54,8 @@ export class ChattingController { description: '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); + async sendFile(@Body() request: MessageFileRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendFile(request); } @@ -65,8 +65,8 @@ export class ChattingController { description: '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); + async sendVoice(@Body() request: MessageVoiceRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendVoice(request); } @@ -76,43 +76,43 @@ export class ChattingController { description: 'Either from an URL or base64 data - look at the request schemas for details.', }) - sendVideo(@Body() request: MessageVideoRequest) { - const whatsapp = this.manager.getSession(request.session); + async sendVideo(@Body() request: MessageVideoRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendVideo(request); } @Post('/sendSeen') - sendSeen(@Body() chat: SendSeenRequest) { - const whatsapp = this.manager.getSession(chat.session); + async sendSeen(@Body() chat: SendSeenRequest) { + const whatsapp = await this.manager.getWorkingSession(chat.session); return whatsapp.sendSeen(chat); } @Post('/startTyping') async startTyping(@Body() chat: ChatRequest) { // It's infinitive action - const whatsapp = this.manager.getSession(chat.session); + const whatsapp = await this.manager.getWorkingSession(chat.session); await whatsapp.startTyping(chat); return { result: true }; } @Post('/stopTyping') async stopTyping(@Body() chat: ChatRequest) { - const whatsapp = this.manager.getSession(chat.session); + const whatsapp = await this.manager.getWorkingSession(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); + async setReaction(@Body() request: MessageReactionRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.setReaction(request); } @Put('/star') @ApiOperation({ summary: 'Star or unstar a message' }) async setStar(@Body() request: MessageStarRequest) { - const whatsapp = this.manager.getSession(request.session); + const whatsapp = await this.manager.getWorkingSession(request.session); await whatsapp.setStar(request); return; } @@ -122,34 +122,34 @@ export class ChattingController { summary: 'Send a poll with options', description: 'You can use it as buttons or list replacement', }) - sendPoll(@Body() request: MessagePollRequest) { - const whatsapp = this.manager.getSession(request.session); + async sendPoll(@Body() request: MessagePollRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendPoll(request); } @Post('/sendLocation') - sendLocation(@Body() request: MessageLocationRequest) { - const whatsapp = this.manager.getSession(request.session); + async sendLocation(@Body() request: MessageLocationRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendLocation(request); } @Post('/sendLinkPreview') - sendLinkPreview(@Body() request: MessageLinkPreviewRequest) { - const whatsapp = this.manager.getSession(request.session); + async sendLinkPreview(@Body() request: MessageLinkPreviewRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendLinkPreview(request); } @Get('/messages') @ApiOperation({ summary: 'Get messages in a chat' }) - getMessages(@Query() query: GetMessageQuery) { - const whatsapp = this.manager.getSession(query.session); + async getMessages(@Query() query: GetMessageQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); return whatsapp.getMessages(query); } @Get('/sendText') @ApiOperation({ summary: 'Send a text message', deprecated: true }) - sendTextGet(@Query() query: MessageTextQuery) { - const whatsapp = this.manager.getSession(query.session); + async sendTextGet(@Query() query: MessageTextQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); const msg = new MessageTextRequest(); msg.chatId = query.phone; msg.text = query.text; @@ -157,8 +157,8 @@ export class ChattingController { } @Post('/sendContactVcard') - sendContactVcard(@Body() request: MessageContactVcardRequest) { - const whatsapp = this.manager.getSession(request.session); + async sendContactVcard(@Body() request: MessageContactVcardRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.sendContactVCard(request); } @@ -171,7 +171,7 @@ export class ChattingController { async DEPRECATED_checkNumberStatus( @Query() request: CheckNumberStatusQuery, ): Promise { - const whatsapp = this.manager.getSession(request.session); + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.checkNumberStatus(request); } @@ -181,8 +181,8 @@ export class ChattingController { 'DEPRECATED - you can set "reply_to" field when sending text, image, etc', deprecated: true, }) - reply(@Body() request: MessageReplyRequest) { - const whatsapp = this.manager.getSession(request.session); + async reply(@Body() request: MessageReplyRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.reply(request); } } diff --git a/src/api/contacts.controller.ts b/src/api/contacts.controller.ts index c5c4cf7b..c8bf28f8 100644 --- a/src/api/contacts.controller.ts +++ b/src/api/contacts.controller.ts @@ -21,15 +21,15 @@ export class ContactsController { description: 'The method always return result, even if the phone number is not registered in WhatsApp. For that - use /contacts/check-exists endpoint below.', }) - get(@Query() query: ContactQuery) { - const whatsapp = this.manager.getSession(query.session); + async get(@Query() query: ContactQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); return whatsapp.getContact(query); } @Get('/all') @ApiOperation({ summary: 'Get all contacts' }) - getAll(@Query() query: SessionQuery) { - const whatsapp = this.manager.getSession(query.session); + async getAll(@Query() query: SessionQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); return whatsapp.getContacts(); } @@ -38,7 +38,7 @@ export class ContactsController { async checkExists( @Query() request: CheckNumberStatusQuery, ): Promise { - const whatsapp = this.manager.getSession(request.session); + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.checkNumberStatus(request); } @@ -48,8 +48,8 @@ export class ContactsController { description: 'Returns null if you do not have permission to read their status.', }) - getAbout(@Query() query: ContactQuery) { - const whatsapp = this.manager.getSession(query.session); + async getAbout(@Query() query: ContactQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); return whatsapp.getContactAbout(query); } @@ -59,22 +59,22 @@ export class ContactsController { description: 'If privacy settings do not allow to get the picture, the method will return null.', }) - getProfilePicture(@Query() query: ContactQuery) { - const whatsapp = this.manager.getSession(query.session); + async getProfilePicture(@Query() query: ContactQuery) { + const whatsapp = await this.manager.getWorkingSession(query.session); return whatsapp.getContactProfilePicture(query); } @Post('/block') @ApiOperation({ summary: 'Block contact' }) - block(@Body() request: ContactRequest) { - const whatsapp = this.manager.getSession(request.session); + async block(@Body() request: ContactRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.blockContact(request); } @Post('/unblock') @ApiOperation({ summary: 'Unblock contact' }) - unblock(@Body() request: ContactRequest) { - const whatsapp = this.manager.getSession(request.session); + async unblock(@Body() request: ContactRequest) { + const whatsapp = await this.manager.getWorkingSession(request.session); return whatsapp.unblockContact(request); } } diff --git a/src/api/groups.controller.ts b/src/api/groups.controller.ts index a083059f..dc0fe543 100644 --- a/src/api/groups.controller.ts +++ b/src/api/groups.controller.ts @@ -11,7 +11,7 @@ import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { GroupIdApiParam } from '@waha/nestjs/params/ChatIdApiParam'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { SessionManager } from '../core/abc/manager.abc'; @@ -34,7 +34,7 @@ export class GroupsController { @SessionApiParam @ApiOperation({ summary: 'Create a new group.' }) createGroup( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() request: CreateGroupRequest, ) { return session.createGroup(request); @@ -43,7 +43,7 @@ export class GroupsController { @Get('') @SessionApiParam @ApiOperation({ summary: 'Get all groups.' }) - getGroups(@SessionParam session: WhatsappSession) { + getGroups(@WorkingSessionParam session: WhatsappSession) { return session.getGroups(); } @@ -51,7 +51,10 @@ export class GroupsController { @GroupIdApiParam @SessionApiParam @ApiOperation({ summary: 'Get the group.' }) - getGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) { + getGroup( + @WorkingSessionParam session: WhatsappSession, + @Param('id') id: string, + ) { return session.getGroup(id); } @@ -64,7 +67,7 @@ export class GroupsController { 'You can allow only admins to edit group info (title, description, photo).', }) setInfoAdminOnly( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: SettingsSecurityChangeInfo, ) { @@ -80,7 +83,7 @@ export class GroupsController { 'You can allow only admins to edit group info (title, description, photo).', }) getInfoAdminOnly( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.getInfoAdminsOnly(id); @@ -95,7 +98,7 @@ export class GroupsController { 'Updates the group settings to only allow admins to send messages.', }) setMessagesAdminOnly( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: SettingsSecurityChangeInfo, ) { @@ -110,7 +113,7 @@ export class GroupsController { description: 'The group settings to only allow admins to send messages.', }) getMessagesAdminOnly( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.getMessagesAdminsOnly(id); @@ -120,7 +123,10 @@ export class GroupsController { @SessionApiParam @GroupIdApiParam @ApiOperation({ summary: 'Delete the group.' }) - deleteGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) { + deleteGroup( + @WorkingSessionParam session: WhatsappSession, + @Param('id') id: string, + ) { return session.deleteGroup(id); } @@ -128,7 +134,10 @@ export class GroupsController { @SessionApiParam @GroupIdApiParam @ApiOperation({ summary: 'Leave the group.' }) - leaveGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) { + leaveGroup( + @WorkingSessionParam session: WhatsappSession, + @Param('id') id: string, + ) { return session.leaveGroup(id); } @@ -141,7 +150,7 @@ export class GroupsController { @SessionApiParam @GroupIdApiParam setDescription( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: DescriptionRequest, ) { @@ -157,7 +166,7 @@ export class GroupsController { 'Returns "true" if the subject was properly updated. This can return "false" if the user does not have the necessary permissions.', }) setSubject( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: SubjectRequest, ) { @@ -169,7 +178,7 @@ export class GroupsController { @GroupIdApiParam @ApiOperation({ summary: 'Gets the invite code for the group.' }) getInviteCode( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.getInviteCode(id); @@ -183,7 +192,7 @@ export class GroupsController { 'Invalidates the current group invite code and generates a new one.', }) revokeInviteCode( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ): Promise { return session.revokeInviteCode(id); @@ -194,7 +203,7 @@ export class GroupsController { @GroupIdApiParam @ApiOperation({ summary: 'Get participants' }) getParticipants( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, ) { return session.getParticipants(id); @@ -205,7 +214,7 @@ export class GroupsController { @GroupIdApiParam @ApiOperation({ summary: 'Add participants' }) addParticipants( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: ParticipantsRequest, ) { @@ -219,7 +228,7 @@ export class GroupsController { summary: 'Remove participants', }) removeParticipants( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: ParticipantsRequest, ) { @@ -231,7 +240,7 @@ export class GroupsController { @GroupIdApiParam @ApiOperation({ summary: 'Promote participants to admin users.' }) promoteToAdmin( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: ParticipantsRequest, ) { @@ -243,7 +252,7 @@ export class GroupsController { @GroupIdApiParam @ApiOperation({ summary: 'Demotes participants to regular users.' }) demoteToAdmin( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('id') id: string, @Body() request: ParticipantsRequest, ) { diff --git a/src/api/labels.controller.ts b/src/api/labels.controller.ts index 1c39ad38..bfa74020 100644 --- a/src/api/labels.controller.ts +++ b/src/api/labels.controller.ts @@ -4,7 +4,7 @@ import { WhatsappSession } from '@waha/core/abc/session.abc'; import { ChatIdApiParam } from '@waha/nestjs/params/ChatIdApiParam'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { Label, SetLabelsRequest } from '@waha/structures/labels.dto'; @@ -19,7 +19,7 @@ export class LabelsController { @Get('/') @SessionApiParam @ApiOperation({ summary: 'Get all labels' }) - getAll(@SessionParam session: WhatsappSession): Promise { + getAll(@WorkingSessionParam session: WhatsappSession): Promise { return session.getLabels(); } @@ -28,7 +28,7 @@ export class LabelsController { @ChatIdApiParam @ApiOperation({ summary: 'Get labels for the chat' }) getChatLabels( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ): Promise { return session.getChatLabels(chatId); @@ -39,7 +39,7 @@ export class LabelsController { @ChatIdApiParam @ApiOperation({ summary: 'Save labels for the chat' }) putChatLabels( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, @Body() request: SetLabelsRequest, ) { @@ -50,7 +50,7 @@ export class LabelsController { @SessionApiParam @ApiOperation({ summary: 'Get chats by label' }) getChatsByLabel( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('labelId') labelId: string, ) { return session.getChatsByLabelId(labelId); diff --git a/src/api/presence.controller.ts b/src/api/presence.controller.ts index a6d001a1..7af7e775 100644 --- a/src/api/presence.controller.ts +++ b/src/api/presence.controller.ts @@ -10,7 +10,7 @@ import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { ChatIdApiParam } from '@waha/nestjs/params/ChatIdApiParam'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { SessionManager } from '../core/abc/manager.abc'; @@ -31,7 +31,7 @@ export class PresenceController { @SessionApiParam @ApiOperation({ summary: 'Set session presence' }) setPresence( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() request: WAHASessionPresence, ) { // Validate request @@ -61,7 +61,7 @@ export class PresenceController { @SessionApiParam @ApiOperation({ summary: 'Get all subscribed presence information.' }) getPresenceAll( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, ): Promise { return session.getPresences(); } @@ -74,7 +74,7 @@ export class PresenceController { "Get the presence for the chat id. If it hasn't been subscribed - it also subscribes to it.", }) getPresence( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ): Promise { return session.getPresence(chatId); @@ -87,7 +87,7 @@ export class PresenceController { summary: 'Subscribe to presence events for the chat.', }) subscribe( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Param('chatId') chatId: string, ): Promise { return session.subscribePresence(chatId); diff --git a/src/api/sessions.controller.ts b/src/api/sessions.controller.ts index eba2ad3f..67986386 100644 --- a/src/api/sessions.controller.ts +++ b/src/api/sessions.controller.ts @@ -17,14 +17,12 @@ import { SessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe'; -import { WAHASessionStatus } from '@waha/structures/enums.dto'; import { SessionLogoutDeprecatedRequest, SessionStartDeprecatedRequest, SessionStopDeprecatedRequest, } from '@waha/structures/sessions.deprecated.dto'; import { generatePrefixedId } from '@waha/utils/ids'; -import { sleep } from '@waha/utils/promiseTimeout'; import { SessionManager } from '../core/abc/manager.abc'; import { WhatsappSession } from '../core/abc/session.abc'; diff --git a/src/api/status.controller.ts b/src/api/status.controller.ts index 5de52abf..46a4d517 100644 --- a/src/api/status.controller.ts +++ b/src/api/status.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Post } from '@nestjs/common'; import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { SessionApiParam, - SessionParam, + WorkingSessionParam, } from '@waha/nestjs/params/SessionApiParam'; import { SessionManager } from '../core/abc/manager.abc'; @@ -25,7 +25,7 @@ class StatusController { @SessionApiParam @ApiOperation({ summary: 'Send text status' }) sendTextStatus( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() status: TextStatus, ) { return session.sendTextStatus(status); @@ -35,7 +35,7 @@ class StatusController { @SessionApiParam @ApiOperation({ summary: 'Send image status' }) sendImageStatus( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() status: ImageStatus, ) { return session.sendImageStatus(status); @@ -45,7 +45,7 @@ class StatusController { @SessionApiParam @ApiOperation({ summary: 'Send voice status' }) sendVoiceStatus( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() status: VoiceStatus, ) { return session.sendVoiceStatus(status); @@ -55,7 +55,7 @@ class StatusController { @SessionApiParam @ApiOperation({ summary: 'Send video status' }) sendVideoStatus( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() status: VideoStatus, ) { return session.sendVideoStatus(status); @@ -65,7 +65,7 @@ class StatusController { @SessionApiParam @ApiOperation({ summary: 'DELETE sent status' }) deleteStatus( - @SessionParam session: WhatsappSession, + @WorkingSessionParam session: WhatsappSession, @Body() status: DeleteStatusRequest, ) { return session.deleteStatus(status); diff --git a/src/core/abc/manager.abc.ts b/src/core/abc/manager.abc.ts index 92093ad8..24ab4c5a 100644 --- a/src/core/abc/manager.abc.ts +++ b/src/core/abc/manager.abc.ts @@ -1,9 +1,17 @@ -import { BeforeApplicationShutdown } from '@nestjs/common'; +import { + BeforeApplicationShutdown, + UnprocessableEntityException, +} from '@nestjs/common'; import { WAHAWebhook } from '@waha/structures/webhooks.dto'; +import { waitUntil } from '@waha/utils/promiseTimeout'; import { VERSION } from '@waha/version'; import { EventEmitter } from 'events'; -import { WAHAEngine, WAHAEvents } from '../../structures/enums.dto'; +import { + WAHAEngine, + WAHAEvents, + WAHASessionStatus, +} from '../../structures/enums.dto'; import { SessionConfig, SessionDetailedInfo, @@ -20,6 +28,8 @@ export abstract class SessionManager implements BeforeApplicationShutdown { public sessionAuthRepository: ISessionAuthRepository; public sessionConfigRepository: ISessionConfigRepository; public events: EventEmitter; + WAIT_STATUS_INTERVAL = 500; + WAIT_STATUS_TIMEOUT = 5_000; protected abstract getEngine(engine: WAHAEngine): typeof WhatsappSession; @@ -70,4 +80,34 @@ export abstract class SessionManager implements BeforeApplicationShutdown { this.events.emit(event, data); }; } + + async getWorkingSession(sessionName: string): Promise { + return this.waitUntilStatus(sessionName, [WAHASessionStatus.WORKING]); + } + + /** + * Wait until session is in expected status + */ + async waitUntilStatus( + sessionName: string, + expected: WAHASessionStatus[], + ): Promise { + const session = this.getSession(sessionName); + const valid = await waitUntil( + async () => expected.includes(session.status), + this.WAIT_STATUS_INTERVAL, + this.WAIT_STATUS_TIMEOUT, + ); + if (!valid) { + const msg = { + error: + 'Session status is not as expected. Try again later or restart the session', + session: sessionName, + status: session.status, + expected: expected, + }; + throw new UnprocessableEntityException(msg); + } + return session; + } } diff --git a/src/core/engines/webjs/session.webjs.core.ts b/src/core/engines/webjs/session.webjs.core.ts index 623a1cce..e3085442 100644 --- a/src/core/engines/webjs/session.webjs.core.ts +++ b/src/core/engines/webjs/session.webjs.core.ts @@ -327,11 +327,6 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { } async getScreenshot(): Promise { - if (this.status === WAHASessionStatus.FAILED) { - throw new UnprocessableEntityException( - `The session under FAILED status. Please try to restart it.`, - ); - } const screenshot = await this.whatsapp.pupPage.screenshot({ encoding: 'binary', }); diff --git a/src/nestjs/params/SessionApiParam.ts b/src/nestjs/params/SessionApiParam.ts index 91c178ea..8dcd73e9 100644 --- a/src/nestjs/params/SessionApiParam.ts +++ b/src/nestjs/params/SessionApiParam.ts @@ -1,6 +1,10 @@ import { Param } from '@nestjs/common'; import { ApiParam } from '@nestjs/swagger'; -import { SessionPipe } from '@waha/nestjs/pipes/SessionPipe'; +import { + QRCodeSessionPipe, + SessionPipe, + WorkingSessionPipe, +} from '@waha/nestjs/pipes/SessionPipe'; /** * Decorator for a method that uses SessionPipe above @@ -18,3 +22,7 @@ export const SessionApiParam = ApiParam({ * Session param */ export const SessionParam = Param('session', SessionPipe); + +export const WorkingSessionParam = Param('session', WorkingSessionPipe); + +export const QRCodeSessionParam = Param('session', QRCodeSessionPipe); diff --git a/src/nestjs/pipes/SessionPipe.ts b/src/nestjs/pipes/SessionPipe.ts index 10af7138..92d3684f 100644 --- a/src/nestjs/pipes/SessionPipe.ts +++ b/src/nestjs/pipes/SessionPipe.ts @@ -1,6 +1,7 @@ import { Injectable, PipeTransform } from '@nestjs/common'; import { SessionManager } from '@waha/core/abc/manager.abc'; import { WhatsappSession } from '@waha/core/abc/session.abc'; +import { WAHASessionStatus } from '@waha/structures/enums.dto'; /** * Get session name and return Whatsapp session back (if exists) @@ -15,3 +16,24 @@ export class SessionPipe implements PipeTransform { return this.manager.getSession(value); } } + +@Injectable() +class StatusSessionPipe implements PipeTransform { + STATUSES: WAHASessionStatus[]; + + constructor(private manager: SessionManager) {} + + async transform(value: any) { + return this.manager.waitUntilStatus(value, this.STATUSES); + } +} + +@Injectable() +export class WorkingSessionPipe extends StatusSessionPipe { + STATUSES = [WAHASessionStatus.WORKING]; +} + +@Injectable() +export class QRCodeSessionPipe extends StatusSessionPipe { + STATUSES = [WAHASessionStatus.SCAN_QR_CODE]; +}