bid-tool/auto-bid-server/src/modules/bids/services/mail/imap.service.ts

132 lines
3.7 KiB
TypeScript

import { extractVerifyCodeLANGTONS, verifyCode } from '@/ultils';
import { ConfigService } from '@nestjs/config';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { WebSocketGateway } from '@nestjs/websockets';
import * as Imap from 'imap';
import { Server, Socket } from 'socket.io';
import { WebBidsService } from '../web-bids.service';
import { Like } from 'typeorm';
import { Event } from '../../utils/events';
import { plainToClass } from 'class-transformer';
import { WebBid } from '../../entities/wed-bid.entity';
@WebSocketGateway({
namespace: 'admin-bid-ws',
cors: {
origin: '*',
methods: ['GET', 'POST'],
credentials: true,
},
})
export class ImapService {
private imap: Imap;
server: Server;
constructor(
private readonly configService: ConfigService,
private readonly webBidsService: WebBidsService,
private eventEmitter: EventEmitter2,
) {
this.imap = new Imap({
user: this.configService.get<string>('MAIL_USER'),
password: this.configService.get<string>('MAIL_PASSWORD'),
host: this.configService.get<string>('MAIL_SERVER'),
port: 993,
tls: true,
tlsOptions: { rejectUnauthorized: false },
});
}
async connectIMAP() {
this.imap.once('ready', () => {
console.log('📥 IMAP Connected. Listening for new emails...');
this.openInbox();
});
this.imap.on('error', (err) => {
console.error('❌ IMAP Error:', err);
});
this.imap.on('end', () => {
console.log('📴 IMAP Connection Ended');
setTimeout(() => this.connectIMAP(), 5000);
});
this.imap.connect();
}
private openInbox() {
this.imap.openBox('INBOX', false, (err, box) => {
if (err) {
console.error('❌ Error opening inbox:', err);
return;
}
console.log('📬 INBOX opened, waiting for new emails...');
// Lắng nghe email mới
this.imap.on('mail', (numNewMsgs: number) => {
console.log(`📩 New email received! (${numNewMsgs} new messages)`);
this.fetchLatestEmail();
});
});
}
private fetchLatestEmail() {
this.imap.search(['UNSEEN'], (err, results) => {
if (err || !results.length) {
console.log('📭 No new unread emails.');
return;
}
const fetchOptions = { bodies: '', struct: true };
const f = this.imap.fetch(results.slice(-1), fetchOptions); // Lấy email mới nhất
f.on('message', (msg, seqno) => {
console.log(`📥 Fetching email #${seqno}`);
let emailContent = '';
let header = '';
msg.on('body', (stream) => {
stream.on('data', (chunk) => {
emailContent += chunk.toString();
});
stream.on('end', async () => {
const result = verifyCode(emailContent);
if (!result) {
throw new Error('fetchLatestEmail: Name or Code is empty');
}
const { code, name } = result;
const webBid = await this.webBidsService.webBidRepo.findOne({
where: { origin_url: Like(`%${name.toLocaleLowerCase()}%`) },
});
if (!webBid) {
throw new Error('Not found web bid');
}
// send message event
this.eventEmitter.emit(Event.verifyCode(webBid), {
code,
name,
web_bid: plainToClass(WebBid, webBid),
});
});
});
});
f.on('error', (err) => {
console.error('❌ Fetch error:', err);
});
f.on('end', () => {
console.log('✅ Done fetching emails.');
});
});
}
}