150 lines
4.9 KiB
TypeScript
150 lines
4.9 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import axios from 'axios';
|
|
import * as dayjs from 'dayjs';
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import { Bid } from '../entities/bid.entity';
|
|
import { Constant } from '../utils/constant';
|
|
|
|
@Injectable()
|
|
export class BotTelegramApi {
|
|
private readonly botToken: string;
|
|
private readonly apiUrl: string;
|
|
|
|
constructor(private readonly configService: ConfigService) {
|
|
this.botToken = this.configService.get<string>('TELEGRAM_BOT_TOKEN');
|
|
this.apiUrl = `https://api.telegram.org/bot${this.botToken}`;
|
|
}
|
|
|
|
formatBidMessage(bid: Bid) {
|
|
return `<b>📢 New Bid Alert!</b>\n
|
|
<b>📌 Product:</b> ${bid.name ? `<b>${bid.name}</b>` : '_No name_'}\n
|
|
<b>💰 Current Price:</b> <code>${bid.current_price.toLocaleString()}${bid.plus_price ? ` (+${bid.plus_price.toLocaleString()})` : ''}</code>\n
|
|
<b>🏆 Max Price:</b> <code>${bid.max_price.toLocaleString()}</code>\n
|
|
<b>🔖 Starting Price:</b> <code>${bid.reserve_price.toLocaleString()}</code>\n\n
|
|
<b>📦 Model:</b> <code>${bid.model || 'None'}</code>\n
|
|
<b>🔢 Quantity:</b> <code>${bid.quantity}</code>\n
|
|
<b>🆔 Lot ID:</b> <code>${bid.lot_id ? bid.lot_id.toString() : 'None'}</code>\n\n
|
|
<b>⏳ Closing Time:</b> ${bid.close_time ? `<code>${dayjs(bid.close_time).format('HH:mm:ss DD/MM/YYYY')}</code>` : '_Not available_'}\n
|
|
<b>🚀 Start Time:</b> ${bid.start_bid_time ? `<code>${dayjs(bid.start_bid_time).format('HH:mm:ss DD/MM/YYYY')}</code>` : '_Not available_'}\n\n
|
|
<b>📈 Bid History:</b>\n${
|
|
bid.histories.length > 0
|
|
? bid.histories
|
|
.map(
|
|
(h, index) =>
|
|
` ${index + 1}. 💵 <code>${index === 0 ? '🔴' : ''}${h.price.toLocaleString()}</code> 🕒 <code>${dayjs(h.updated_at).format('HH:mm:ss DD/MM/YYYY')}</code>`,
|
|
)
|
|
.join('\n')
|
|
: '_No bid history yet_'
|
|
}\n\n
|
|
<b>📝 Status:</b> <code>${bid.status.replace('-', ' ')}</code>\n\n
|
|
⬇️ <b>View Details:</b> <a href="${bid.url}">Click here</a>`;
|
|
}
|
|
|
|
async sendMessage(
|
|
text: string,
|
|
bonusBody: Record<string, any> = {},
|
|
chatId: string = this.configService.get<string>('CHAT_ID'),
|
|
): Promise<void> {
|
|
try {
|
|
const url = `${this.apiUrl}/sendMessage`;
|
|
const response = await axios.post(
|
|
url,
|
|
{
|
|
chat_id: chatId,
|
|
text: text,
|
|
...bonusBody,
|
|
},
|
|
{
|
|
family: 4,
|
|
},
|
|
);
|
|
} catch (error) {
|
|
console.error('Error sending message:', error || error.message);
|
|
}
|
|
}
|
|
|
|
async createFolderPath(): Promise<string> {
|
|
const rootDir = process.cwd();
|
|
const folderPath = join(rootDir, `${Constant.BOT_TELEGRAM_PATH}`);
|
|
|
|
if (!existsSync(folderPath)) {
|
|
mkdirSync(folderPath, { recursive: true, mode: 0o777 });
|
|
|
|
// ✅ Lưu metadata lần đầu
|
|
const metadataPath = join(folderPath, 'metadata.json');
|
|
writeFileSync(
|
|
metadataPath,
|
|
JSON.stringify({ createdAt: Date.now() }),
|
|
'utf-8',
|
|
);
|
|
}
|
|
|
|
return folderPath;
|
|
}
|
|
|
|
async getGroupInfo(
|
|
chatId: string = this.configService.get<string>('CHAT_ID'),
|
|
): Promise<any> {
|
|
try {
|
|
const folderPath = await this.createFolderPath();
|
|
const metadataPath = join(folderPath, 'metadata.json');
|
|
const dataFilePath = join(folderPath, `group_${chatId}.json`);
|
|
|
|
// 10 minute
|
|
const TIME_TO_REFRESH_DATA = 10;
|
|
|
|
if (existsSync(metadataPath)) {
|
|
const metadata = JSON.parse(readFileSync(metadataPath, 'utf-8'));
|
|
const createdAt = metadata?.createdAt || 0;
|
|
const now = Date.now();
|
|
const diffMinutes = (now - createdAt) / 60000;
|
|
|
|
if (diffMinutes < TIME_TO_REFRESH_DATA && existsSync(dataFilePath)) {
|
|
return JSON.parse(readFileSync(dataFilePath, 'utf-8'));
|
|
}
|
|
}
|
|
|
|
const url = `${this.apiUrl}/getChat`;
|
|
const { data } = await axios({
|
|
url,
|
|
params: { chat_id: chatId },
|
|
family: 4,
|
|
});
|
|
|
|
if (data?.ok) {
|
|
writeFileSync(
|
|
dataFilePath,
|
|
JSON.stringify(data.result, null, 2),
|
|
'utf-8',
|
|
);
|
|
writeFileSync(
|
|
metadataPath,
|
|
JSON.stringify({ createdAt: Date.now() }),
|
|
'utf-8',
|
|
);
|
|
|
|
return data.result;
|
|
}
|
|
} catch (error) {
|
|
console.error(error || error.message);
|
|
}
|
|
}
|
|
|
|
async sendBidInfo(bid: Bid): Promise<boolean> {
|
|
try {
|
|
const text = this.formatBidMessage(bid);
|
|
|
|
await this.sendMessage(text, {
|
|
parse_mode: 'HTML',
|
|
});
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.log('SEND MESSAGE FAILURE');
|
|
return false;
|
|
}
|
|
}
|
|
}
|