190 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
import _ from 'lodash';
 | 
						|
import { io } from 'socket.io-client';
 | 
						|
import { GrayApiBid } from './models/grays.com/grays-api-bid.js';
 | 
						|
import { GraysProductBid } from './models/grays.com/grays-product-bid.js';
 | 
						|
import configs from './system/config.js';
 | 
						|
import { isTimeReached, safeClosePage } from './system/utils.js';
 | 
						|
import browser from './system/browser.js';
 | 
						|
 | 
						|
let MANAGER_BIDS = [];
 | 
						|
 | 
						|
let _INTERVAL_TRACKING_ID = null;
 | 
						|
let _CLEAR_LAZY_TAB_ID = null;
 | 
						|
let _WORK_TRACKING_ID = null;
 | 
						|
 | 
						|
const handleCloseRemoveProduct = (data) => {
 | 
						|
    if (!Array.isArray(data)) return;
 | 
						|
 | 
						|
    data.forEach(async (item) => {
 | 
						|
        if (item.page_context) {
 | 
						|
            safeClosePage(item);
 | 
						|
        }
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
const createBidProduct = (web, data) => {
 | 
						|
    switch (web.origin_url) {
 | 
						|
        case configs.WEB_URLS.GRAYS: {
 | 
						|
            return new GraysProductBid({ ...data });
 | 
						|
        }
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
const createApiBid = (web) => {
 | 
						|
    switch (web.origin_url) {
 | 
						|
        case configs.WEB_URLS.GRAYS: {
 | 
						|
            return new GrayApiBid({ ...web });
 | 
						|
        }
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
const handleUpdateProductTabs = (data) => {
 | 
						|
    if (!Array.isArray(data)) {
 | 
						|
        console.log('Data must be array');
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    const managerBidMap = new Map(MANAGER_BIDS.map((bid) => [bid.id, bid]));
 | 
						|
 | 
						|
    const newDataManager = data.map(({ children, ...web }) => {
 | 
						|
        const prevApiBid = managerBidMap.get(web.id);
 | 
						|
 | 
						|
        const newChildren = children.map((item) => {
 | 
						|
            const prevProductTab = prevApiBid?.children.find((i) => i.id === item.id);
 | 
						|
 | 
						|
            if (prevProductTab) {
 | 
						|
                prevProductTab.setNewData(item);
 | 
						|
 | 
						|
                return prevProductTab;
 | 
						|
            }
 | 
						|
 | 
						|
            return createBidProduct(web, item);
 | 
						|
        });
 | 
						|
 | 
						|
        if (prevApiBid) {
 | 
						|
            prevApiBid.setNewData({ children: newChildren, ...web });
 | 
						|
            return prevApiBid;
 | 
						|
        }
 | 
						|
 | 
						|
        return createApiBid({ ...web, children: newChildren });
 | 
						|
    });
 | 
						|
 | 
						|
    MANAGER_BIDS = newDataManager;
 | 
						|
};
 | 
						|
 | 
						|
const tracking = async () => {
 | 
						|
    if (_INTERVAL_TRACKING_ID) {
 | 
						|
        clearInterval(_INTERVAL_TRACKING_ID);
 | 
						|
    }
 | 
						|
 | 
						|
    _INTERVAL_TRACKING_ID = setInterval(async () => {
 | 
						|
        const productTabs = _.flatMap(MANAGER_BIDS, 'children');
 | 
						|
 | 
						|
        for (const productTab of productTabs) {
 | 
						|
            if (!productTab.parent_browser_context) {
 | 
						|
                const parent = _.find(MANAGER_BIDS, { id: productTab.web_bid.id });
 | 
						|
 | 
						|
                productTab.parent_browser_context = parent.browser_context;
 | 
						|
 | 
						|
                if (!productTab.parent_browser_context) {
 | 
						|
                    console.log(`🔄 Waiting for parent process to start... (Product ID: ${productTab.id})`);
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (!productTab.first_bid) {
 | 
						|
                console.log(`🎯 Tracking out-bid event for Product ID: ${productTab.id}`);
 | 
						|
 | 
						|
                if (!productTab.page_context) {
 | 
						|
                    console.log(`🔌 Establishing connection for Product ID: ${productTab.id}`);
 | 
						|
                    await productTab.puppeteer_connect();
 | 
						|
 | 
						|
                    await productTab.handleTakeWorkSnapshot();
 | 
						|
                }
 | 
						|
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (productTab.start_bid_time && !isTimeReached(productTab.start_bid_time)) {
 | 
						|
                console.log(`⏳ Not yet time to bid. Skipping Product ID: ${productTab.id}`);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (!productTab.page_context) {
 | 
						|
                console.log(`🔌 Connecting to page for Product ID: ${productTab.id}`);
 | 
						|
                await productTab.puppeteer_connect();
 | 
						|
            }
 | 
						|
 | 
						|
            console.log(`🚀 Executing action for Product ID: ${productTab.id}`);
 | 
						|
            await productTab.action();
 | 
						|
        }
 | 
						|
    }, configs.AUTO_TRACKING_DELAY);
 | 
						|
};
 | 
						|
 | 
						|
const clearLazyTab = async () => {
 | 
						|
    if (_CLEAR_LAZY_TAB_ID) {
 | 
						|
        clearInterval(_CLEAR_LAZY_TAB_ID);
 | 
						|
    }
 | 
						|
 | 
						|
    _CLEAR_LAZY_TAB_ID = setInterval(async () => {
 | 
						|
        const pages = await browser.pages();
 | 
						|
 | 
						|
        // Lấy danh sách URL từ flattenedArray
 | 
						|
        const activeUrls = _.flatMap(MANAGER_BIDS, (item) => [item.url, ...item.children.map((child) => child.url)]).filter(Boolean); // Lọc bỏ null hoặc undefined
 | 
						|
 | 
						|
        console.log({ activeUrls });
 | 
						|
 | 
						|
        for (const page of pages) {
 | 
						|
            const pageUrl = page.url();
 | 
						|
 | 
						|
            if (!activeUrls.includes(pageUrl)) {
 | 
						|
                console.log(`Closing unused tab: ${pageUrl}`);
 | 
						|
                await page.close();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }, configs.AUTO_TRACKING_CLEANING);
 | 
						|
};
 | 
						|
 | 
						|
const workTracking = () => {
 | 
						|
    if (_WORK_TRACKING_ID) {
 | 
						|
        clearInterval(_WORK_TRACKING_ID);
 | 
						|
    }
 | 
						|
 | 
						|
    _WORK_TRACKING_ID = setInterval(() => {
 | 
						|
        const activeData = _.flatMap(MANAGER_BIDS, (item) => [item, ...item.children]);
 | 
						|
 | 
						|
        for (const item of activeData) {
 | 
						|
            item.handleTakeWorkSnapshot();
 | 
						|
        }
 | 
						|
    }, 10000);
 | 
						|
};
 | 
						|
 | 
						|
(async () => {
 | 
						|
    const socket = io(configs.SOCKET_URL, {
 | 
						|
        transports: ['websocket'],
 | 
						|
        reconnection: true,
 | 
						|
    });
 | 
						|
 | 
						|
    // listen connect
 | 
						|
    socket.on('connect', () => {
 | 
						|
        console.log('✅ Connected to WebSocket server');
 | 
						|
        console.log('🔗 Socket ID:', socket.id);
 | 
						|
    });
 | 
						|
 | 
						|
    // listen event
 | 
						|
    socket.on('bidsUpdated', async (data) => {
 | 
						|
        console.log('📢 Bids Data:', data);
 | 
						|
 | 
						|
        handleUpdateProductTabs(data);
 | 
						|
 | 
						|
        await Promise.all(MANAGER_BIDS.map((apiBid) => apiBid.listen_events()));
 | 
						|
    });
 | 
						|
 | 
						|
    // AUTO TRACKING
 | 
						|
    tracking();
 | 
						|
 | 
						|
    clearLazyTab();
 | 
						|
 | 
						|
    workTracking();
 | 
						|
})();
 |