scheffin-api / src /message /message.controller.ts
Rasyiq03's picture
finishing
464b662
Raw History Blame Contribute Delete
5.43 kB
import { Body, Controller, Post, Res, HttpStatus } from '@nestjs/common';
import { WhatsappService } from '../whatsapp/whatsapp.service';
import { formatJid } from '../common/utils';
class TextMessageBody {
target!: string;
message!: string;
}
class MediaMessageBody {
target!: string;
url!: string;
caption?: string;
filename?: string;
mimetype?: string;
}
class PollMessageBody {
target!: string;
question!: string;
options!: string[];
multiSelect?: boolean;
}
@Controller('send')
export class MessageController {
constructor(private readonly whatsappService: WhatsappService) {}
private handleRouteError(err: unknown, res: any): void {
const message = err instanceof Error ? err.message : 'Unknown error';
const statusCode = message.includes('belum terhubung')
? HttpStatus.SERVICE_UNAVAILABLE
: HttpStatus.INTERNAL_SERVER_ERROR;
console.error(`Error Pengiriman: ${message}`);
res.status(statusCode).json({ status: 'Error', message });
}
@Post('/')
async sendText(@Body() body: TextMessageBody, @Res() res: any) {
const { target, message } = body;
if (!target || !message) {
return res.status(HttpStatus.BAD_REQUEST).json({
status: 'Error',
message: 'Field "target" dan "message" wajib diisi.',
});
}
try {
const sock = this.whatsappService.getSocket();
const jid = formatJid(target);
if (jid.endsWith('@g.us')) {
await this.whatsappService.groupCacheReady;
}
// ⚠️ PERHATIAN: Tidak Boleh menggunakan withTimeout di sini.
// Jika disinkron ke 1000 anggota pertama kalinya dan butuh waktu 2 menit,
// kita harus rela menunggu janji Baileys terpenuhi.
// Terminate paksa promise ini hanya akan membuat mutex Baileys hang seumur hidup.
await sock.sendMessage(jid, { text: message });
console.log(`πŸ“€ [TEXT] β†’ ${jid} (Sukses)`);
res
.status(HttpStatus.OK)
.json({ status: 'Success', type: 'text', to: jid });
} catch (err) {
this.handleRouteError(err, res);
}
}
@Post('/image')
async sendImage(@Body() body: MediaMessageBody, @Res() res: any) {
const { target, url, caption } = body;
if (!target || !url) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ status: 'Error', message: 'target & url wajib.' });
}
try {
const sock = this.whatsappService.getSocket();
const jid = formatJid(target);
if (jid.endsWith('@g.us')) await this.whatsappService.groupCacheReady;
await sock.sendMessage(jid, { image: { url }, caption: caption ?? '' });
console.log(`πŸ“€ [IMAGE] β†’ ${jid}`);
res
.status(HttpStatus.OK)
.json({ status: 'Success', type: 'image', to: jid });
} catch (err) {
this.handleRouteError(err, res);
}
}
@Post('/video')
async sendVideo(@Body() body: MediaMessageBody, @Res() res: any) {
const { target, url, caption } = body;
if (!target || !url) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ status: 'Error', message: 'target & url wajib.' });
}
try {
const sock = this.whatsappService.getSocket();
const jid = formatJid(target);
if (jid.endsWith('@g.us')) await this.whatsappService.groupCacheReady;
await sock.sendMessage(jid, { video: { url }, caption: caption ?? '' });
console.log(`πŸ“€ [VIDEO] β†’ ${jid}`);
res
.status(HttpStatus.OK)
.json({ status: 'Success', type: 'video', to: jid });
} catch (err) {
this.handleRouteError(err, res);
}
}
@Post('/document')
async sendDocument(@Body() body: MediaMessageBody, @Res() res: any) {
const { target, url, filename, mimetype } = body;
if (!target || !url || !filename) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ status: 'Error', message: 'target, url & filename wajib.' });
}
try {
const sock = this.whatsappService.getSocket();
const jid = formatJid(target);
if (jid.endsWith('@g.us')) await this.whatsappService.groupCacheReady;
await sock.sendMessage(jid, {
document: { url },
fileName: filename,
mimetype: mimetype ?? 'application/octet-stream',
});
console.log(`πŸ“€ [DOC] β†’ ${jid}`);
res
.status(HttpStatus.OK)
.json({ status: 'Success', type: 'document', to: jid });
} catch (err) {
this.handleRouteError(err, res);
}
}
@Post('/poll')
async sendPoll(@Body() body: PollMessageBody, @Res() res: any) {
const { target, question, options, multiSelect } = body;
if (!target || !question || !options || options.length < 2) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ status: 'Error', message: 'Opsi poll minimal 2' });
}
try {
const sock = this.whatsappService.getSocket();
const jid = formatJid(target);
if (jid.endsWith('@g.us')) await this.whatsappService.groupCacheReady;
await sock.sendMessage(jid, {
poll: {
name: question,
values: options,
selectableCount: multiSelect ? options.length : 1,
},
});
console.log(`πŸ“€ [POLL] β†’ ${jid}`);
res
.status(HttpStatus.OK)
.json({ status: 'Success', type: 'poll', to: jid });
} catch (err) {
this.handleRouteError(err, res);
}
}
}