293 lines
8.8 KiB
JavaScript
293 lines
8.8 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
|
|
// );
|
|
// }
|
|
};
|
|
|
|
isLogin = async () => {
|
|
if (!this.page_context) return false;
|
|
|
|
const filePath = getPathProfile(this.origin_url);
|
|
if (
|
|
!(await this.page_context.$('input[name="username"]')) ||
|
|
fs.existsSync(filePath)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
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}`);
|
|
}
|
|
};
|
|
}
|