diff --git a/src/api/sessions.controller.ts b/src/api/sessions.controller.ts index 0e3ed2f5..6b2f2350 100644 --- a/src/api/sessions.controller.ts +++ b/src/api/sessions.controller.ts @@ -15,17 +15,20 @@ 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 { SessionManager } from '../core/abc/manager.abc'; import { WhatsappSession } from '../core/abc/session.abc'; import { ListSessionsQuery, MeInfo, + SessionCreateRequest, SessionDTO, SessionInfo, } from '../structures/sessions.dto'; @@ -62,6 +65,34 @@ class SessionsController { getMe(@SessionParam session: WhatsappSession): MeInfo | null { return session.getSessionMeInfo(); } + + @Post('') + @ApiOperation({ + summary: 'Create a session', + description: + 'Create session a new session (and start it at the same time if required).', + }) + @UsePipes(new WAHAValidationPipe()) + async create(@Body() request: SessionCreateRequest): Promise { + const name = request.name || generatePrefixedId('session'); + if (this.manager.isRunning(name)) { + const msg = `Session '${name}' is already started.`; + throw new UnprocessableEntityException(msg); + } + + if (await this.manager.exists(name)) { + const msg = `Session '${name}' already exists. Use PUT to update it.`; + throw new UnprocessableEntityException(msg); + } + + const config = request.config; + const start = request.start || false; + await this.manager.upsert(name, config); + if (start) { + await this.manager.start(name); + } + return await this.manager.getSessionInfo(name); + } } @ApiSecurity('api_key') diff --git a/src/core/abc/manager.abc.ts b/src/core/abc/manager.abc.ts index 3a1fe7e1..1cbff34e 100644 --- a/src/core/abc/manager.abc.ts +++ b/src/core/abc/manager.abc.ts @@ -34,6 +34,8 @@ export abstract class SessionManager implements BeforeApplicationShutdown { /** * Either create or update */ + abstract exists(name: string): Promise; + abstract isRunning(name: string): boolean; abstract upsert(name: string, config?: SessionConfig): Promise; diff --git a/src/core/manager.core.ts b/src/core/manager.core.ts index e6fb51f9..58def3de 100644 --- a/src/core/manager.core.ts +++ b/src/core/manager.core.ts @@ -109,6 +109,11 @@ export class SessionManagerCore extends SessionManager { // // API Methods // + async exists(name: string): Promise { + this.onlyDefault(name); + return !!this.session; + } + isRunning(name: string): boolean { this.onlyDefault(name); return !!this.session; diff --git a/src/structures/sessions.dto.ts b/src/structures/sessions.dto.ts index 44088c66..06ee6cfa 100644 --- a/src/structures/sessions.dto.ts +++ b/src/structures/sessions.dto.ts @@ -135,3 +135,28 @@ export class SessionInfo extends SessionDTO { me?: MeInfo; engine?: any; } + +export class SessionCreateRequest { + @ApiProperty({ + example: 'default', + description: 'Session name (id)', + required: false, + }) + @IsString() + @IsOptional() + name: string | undefined; + + @ValidateNested() + @Type(() => SessionConfig) + @IsOptional() + config?: SessionConfig; + + @ApiProperty({ + description: 'Start session after creation', + example: true, + default: true, + }) + @IsBoolean() + @IsOptional() + start?: boolean; +} diff --git a/src/utils/ids.ts b/src/utils/ids.ts new file mode 100644 index 00000000..e1634744 --- /dev/null +++ b/src/utils/ids.ts @@ -0,0 +1,4 @@ +export function generatePrefixedId(prefix: string) { + const id = Math.random().toString(36).substring(7); + return `${prefix}_${id}`; +}