228 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			8.6 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('🔄 Starting polling process...');
 | 
						|
 | 
						|
            await page.evaluateHandle(
 | 
						|
                (apiUrl, interval) => {
 | 
						|
                    if (window._autoBidPollingStarted) {
 | 
						|
                        console.log('✅ Polling is already running. Skipping initialization.');
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
 | 
						|
                    console.log('🚀 Initializing polling...');
 | 
						|
                    window._autoBidPollingStarted = true;
 | 
						|
 | 
						|
                    function sendRequest() {
 | 
						|
                        console.log('📡 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(`✅ Response received: ${response.status}`))
 | 
						|
                            .catch((err) => console.error('⚠️ 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,
 | 
						|
            );
 | 
						|
 | 
						|
            console.log('✅ Polling successfully started!');
 | 
						|
        } catch (error) {
 | 
						|
            if (error.message.includes('Execution context was destroyed')) {
 | 
						|
                console.log('⚠️ Page reload detected, restarting polling...');
 | 
						|
                await page.waitForNavigation({ waitUntil: 'networkidle2' }).catch(() => {});
 | 
						|
                return await this.polling(page);
 | 
						|
            }
 | 
						|
 | 
						|
            console.error('🚨 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("❌ 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;
 | 
						|
 | 
						|
        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('✅ Already logged in, skipping login.');
 | 
						|
 | 
						|
            this.retry_login = 0; // Reset retry count
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        console.log('🔑 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('✅ 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(`⚠️ Login error: ${error.message}. Retrying attempt ${this.retry_login + 1} ❌`);
 | 
						|
 | 
						|
            this.retry_login++;
 | 
						|
            if (this.retry_login > this.retry_login_count) {
 | 
						|
                console.log('🚨 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
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    action = async () => {
 | 
						|
        try {
 | 
						|
            const page = this.page_context;
 | 
						|
 | 
						|
            await page.goto(this.url, { waitUntil: 'networkidle2' });
 | 
						|
 | 
						|
            await page.bringToFront();
 | 
						|
 | 
						|
            // 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');
 | 
						|
 | 
						|
            // await takeSnapshot(this.page_context, this, 'working', CONSTANTS.TYPE_IMAGE.WORK);
 | 
						|
 | 
						|
            page.on('response', async (response) => {
 | 
						|
                if (response.request().url().includes('api/Notifications/GetOutBidLots')) {
 | 
						|
                    console.log('🚀 API POST:', response.url());
 | 
						|
 | 
						|
                    try {
 | 
						|
                        const responseBody = await response.json();
 | 
						|
 | 
						|
                        await this.listen_out_bids(responseBody.AuctionOutBidLots || []);
 | 
						|
                    } catch (error) {
 | 
						|
                        console.error('❌ Error get response', error?.message);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            });
 | 
						|
 | 
						|
            page.on('load', async () => {
 | 
						|
                console.log('🔄 The page has reloaded, restarting polling...');
 | 
						|
 | 
						|
                // await takeSnapshot(this.page_context, this, 'working', CONSTANTS.TYPE_IMAGE.WORK);
 | 
						|
 | 
						|
                await this.polling(page);
 | 
						|
 | 
						|
                await this.handleLogin();
 | 
						|
            });
 | 
						|
 | 
						|
            await this.polling(page); // Call when fist load
 | 
						|
 | 
						|
            await this.handleLogin();
 | 
						|
        } catch (error) {
 | 
						|
            console.log(error.message);
 | 
						|
        }
 | 
						|
    };
 | 
						|
}
 |