91 lines
No EOL
3.1 KiB
TypeScript
91 lines
No EOL
3.1 KiB
TypeScript
/**
|
|
* IB Session Operations - Browser automation for session headers
|
|
*/
|
|
import { Browser } from '@stock-bot/browser';
|
|
import { OperationContext } from '@stock-bot/di';
|
|
import type { ServiceContainer } from '@stock-bot/di';
|
|
|
|
import { IB_CONFIG } from '../shared/config';
|
|
|
|
export async function fetchSession(container: ServiceContainer): Promise<Record<string, string> | undefined> {
|
|
const ctx = OperationContext.create('ib', 'session', { container });
|
|
|
|
try {
|
|
await Browser.initialize({
|
|
headless: true,
|
|
timeout: IB_CONFIG.BROWSER_TIMEOUT,
|
|
blockResources: false
|
|
});
|
|
ctx.logger.info('✅ Browser initialized');
|
|
|
|
const { page } = await Browser.createPageWithProxy(
|
|
IB_CONFIG.BASE_URL + IB_CONFIG.PRODUCTS_PAGE,
|
|
IB_CONFIG.DEFAULT_PROXY
|
|
);
|
|
ctx.logger.info('✅ Page created with proxy');
|
|
|
|
const headersPromise = new Promise<Record<string, string> | undefined>(resolve => {
|
|
let resolved = false;
|
|
|
|
page.onNetworkEvent(event => {
|
|
if (event.url.includes('/webrest/search/product-types/summary')) {
|
|
if (event.type === 'request') {
|
|
try {
|
|
resolve(event.headers);
|
|
} catch (e) {
|
|
resolve(undefined);
|
|
ctx.logger.debug('Raw Summary Response error', { error: (e as Error).message });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Timeout fallback
|
|
setTimeout(() => {
|
|
if (!resolved) {
|
|
resolved = true;
|
|
ctx.logger.warn('Timeout waiting for headers');
|
|
resolve(undefined);
|
|
}
|
|
}, IB_CONFIG.HEADERS_TIMEOUT);
|
|
});
|
|
|
|
ctx.logger.info('⏳ Waiting for page load...');
|
|
await page.waitForLoadState('domcontentloaded', { timeout: IB_CONFIG.PAGE_LOAD_TIMEOUT });
|
|
ctx.logger.info('✅ Page loaded');
|
|
|
|
//Products tabs
|
|
ctx.logger.info('🔍 Looking for Products tab...');
|
|
const productsTab = page.locator('#productSearchTab[role=\"tab\"][href=\"#products\"]');
|
|
await productsTab.waitFor({ timeout: IB_CONFIG.ELEMENT_TIMEOUT });
|
|
ctx.logger.info('✅ Found Products tab');
|
|
ctx.logger.info('🖱️ Clicking Products tab...');
|
|
await productsTab.click();
|
|
ctx.logger.info('✅ Products tab clicked');
|
|
|
|
// New Products Checkbox
|
|
ctx.logger.info('🔍 Looking for \"New Products Only\" radio button...');
|
|
const radioButton = page.locator('span.checkbox-text:has-text(\"New Products Only\")');
|
|
await radioButton.waitFor({ timeout: IB_CONFIG.ELEMENT_TIMEOUT });
|
|
ctx.logger.info(`🎯 Found \"New Products Only\" radio button`);
|
|
await radioButton.first().click();
|
|
ctx.logger.info('✅ \"New Products Only\" radio button clicked');
|
|
|
|
// Wait for and return headers immediately when captured
|
|
ctx.logger.info('⏳ Waiting for headers to be captured...');
|
|
const headers = await headersPromise;
|
|
page.close();
|
|
if (headers) {
|
|
ctx.logger.info('✅ Headers captured successfully');
|
|
} else {
|
|
ctx.logger.warn('⚠️ No headers were captured');
|
|
}
|
|
|
|
return headers;
|
|
} catch (error) {
|
|
ctx.logger.error('Failed to fetch IB symbol summary', { error });
|
|
return;
|
|
} finally {
|
|
await ctx.dispose();
|
|
}
|
|
} |