bid-tool/auto-bid-tool/models/grays.com/grays-api-bid.js

227 lines
9.0 KiB
JavaScript

import path from 'path';
import { createOutBidLog } from '../../system/apis/out-bid-log.js';
import configs from '../../system/config.js';
import { delay, extractNumber, getPathProfile, isTimeReached, safeClosePage } from '../../system/utils.js';
import { ApiBid } from '../api-bid.js';
import fs from 'fs';
export class GrayApiBid extends ApiBid {
retry_login = 0;
retry_login_count = 3;
constructor({ ...prev }) {
super(prev);
}
async polling(page) {
try {
// // 🔥 Xóa tất cả event chặn request trước khi thêm mới
// page.removeAllListeners('request');
// await page.setRequestInterception(true);
// page.on('request', (request) => {
// if (request.url().includes('api/Notifications/GetOutBidLots')) {
// console.log('🚀 Fake response cho request:', request.url());
// const fakeData = fs.readFileSync('./data/fake-out-lots.json', 'utf8');
// request.respond({
// status: 200,
// contentType: 'application/json',
// body: fakeData,
// });
// } else {
// try {
// request.continue(); // ⚠️ Chỉ tiếp tục nếu request chưa bị chặn
// } catch (error) {
// console.error('⚠️ Lỗi khi tiếp tục request:', error.message);
// }
// }
// });
console.log(`🔄 [${this.id}] Starting polling process...`);
await page.evaluateHandle(
(apiUrl, interval, bidId) => {
if (window._autoBidPollingStarted) {
console.log(`✅ [${bidId}] Polling is already running. Skipping initialization.`);
return;
}
console.log(`🚀 [${bidId}] Initializing polling...`);
window._autoBidPollingStarted = true;
function sendRequest() {
console.log(`📡 [${bidId}] Sending request to track out-bid lots...`);
fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: JSON.stringify({ timeStamp: new Date().getTime() }),
})
.then((response) => console.log(`✅ [${bidId}] Response received: ${response.status}`))
.catch((err) => console.error(`⚠️ [${bidId}] Request error:`, err));
}
window._pollingInterval = setInterval(sendRequest, interval);
},
configs.WEB_CONFIGS.GRAYS.API_CALL_TO_TRACKING,
configs.WEB_CONFIGS.GRAYS.AUTO_CALL_API_TO_TRACKING,
this.id,
);
} catch (error) {
if (error.message.includes('Execution context was destroyed')) {
console.log(`⚠️ [${this.id}] Page reload detected, restarting polling...`);
await page.waitForNavigation({ waitUntil: 'networkidle2' }).catch(() => {});
return await this.polling(page);
}
console.error(`🚨 [${this.id}] Unexpected polling error:`, error);
throw error;
}
}
async handleCreateLogsOnServer(data) {
if (!Array.isArray(data)) return;
const values = data.map((item) => {
return {
model: item.Sku,
lot_id: item.Id,
out_price: extractNumber(item.Bid) || 0,
raw_data: JSON.stringify(item),
};
});
await createOutBidLog(values);
}
listen_out_bids = async (data) => {
if (this.children.length <= 0 || data.length <= 0) return;
// SAVE LOGS ON SERVER
this.handleCreateLogsOnServer(data);
const bidOutLots = data.filter((bid) => !this.children_processing.some((item) => item.model === bid.Sku));
const handleChildren = this.children.filter((item) => bidOutLots.some((i) => i.Sku === item.model));
console.log({ handleChildren, children_processing: this.children_processing, data, bidOutLots });
for (const product_tab of handleChildren) {
if (!isTimeReached(product_tab.start_bid_time)) {
console.log(`❌ [${this.id}] It's not time yet ID: ${product_tab.id} continue waiting...`);
return;
}
this.children_processing.push(product_tab);
if (!product_tab.page_context) {
await product_tab.puppeteer_connect();
}
await product_tab.action();
this.children_processing = this.children_processing.filter((item) => item.id !== product_tab.id);
}
};
async handleLogin() {
const page = this.page_context;
global.IS_CLEANING = false;
const filePath = getPathProfile(this.origin_url);
// 🔍 Check if already logged in (login input should not be visible)
if (!(await page.$('input[name="username"]')) || fs.existsSync(filePath)) {
console.log(`✅ [${this.id}] Already logged in, skipping login.`);
global.IS_CLEANING = true;
this.retry_login = 0; // Reset retry count
return;
}
console.log(`🔑 [${this.id}] Starting login process...`);
try {
await page.type('input[name="username"]', this.username, { delay: 100 });
await page.type('input[name="password"]', this.password, { delay: 150 });
await page.click('#loginButton');
await Promise.race([
page.waitForNavigation({ timeout: 8000, waitUntil: 'domcontentloaded' }),
page.waitForFunction(() => !document.querySelector('input[name="username"]'), { timeout: 8000 }), // Check if login input disappears
]);
if (!(await page.$('input[name="username"]'))) {
console.log(`✅ [${this.id}] Login successful!`);
this.retry_login = 0; // Reset retry count after success
return;
}
throw new Error('Login failed, login input is still visible.');
} catch (error) {
console.log(`⚠️ [${this.id}] Login error: ${error.message}. Retrying attempt ${this.retry_login + 1}`);
this.retry_login++;
if (this.retry_login > this.retry_login_count) {
console.log(`🚨 [${this.id}] Maximum login attempts reached. Stopping login process.`);
safeClosePage(this);
this.retry_login = 0; // Reset retry count
return;
}
safeClosePage(this); // Close the current page
await delay(1000);
if (!this.page_context) {
await this.puppeteer_connect(); // Reconnect if page is closed
}
return await this.action(); // Retry login
} finally {
global.IS_CLEANING = true;
}
}
action = async () => {
try {
const page = this.page_context;
await page.goto(this.url, { waitUntil: 'networkidle2' });
console.log(`🌍 [${this.id}] Navigated to URL: ${this.url}`);
await page.bringToFront();
console.log(`🎯 [${this.id}] Brought page to front.`);
// Set userAgent
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
console.log(`🛠️ [${this.id}] UserAgent set.`);
page.on('response', async (response) => {
if (response.request().url().includes('api/Notifications/GetOutBidLots')) {
console.log(`🚀 [${this.id}] API POST detected: ${response.url()}`);
try {
const responseBody = await response.json();
await this.listen_out_bids(responseBody.AuctionOutBidLots || []);
} catch (error) {
console.error(`❌ [${this.id}] Error processing response:`, error?.message);
}
}
});
page.on('load', async () => {
console.log(`🔄 [${this.id}] Page has reloaded, restarting polling...`);
await this.polling(page);
await this.handleLogin();
});
await this.polling(page); // Call when first load
await this.handleLogin();
} catch (error) {
console.log(`❌ [${this.id}] Action error: ${error.message}`);
}
};
}