refactored db's and browser

This commit is contained in:
Boki 2025-06-22 08:45:14 -04:00
parent a0a3b26177
commit 89cbfb7848
12 changed files with 111 additions and 39 deletions

View file

@ -7,6 +7,10 @@ import { createContainer, asFunction, asValue, InjectionMode, type AwilixContain
import { createCache, type CacheProvider } from '@stock-bot/cache';
import { ProxyManager } from '@stock-bot/proxy';
import { getLogger } from '@stock-bot/logger';
import { createMongoDBClient } from '@stock-bot/mongodb';
import { createPostgreSQLClient } from '@stock-bot/postgres';
import { createQuestDBClient } from '@stock-bot/questdb';
import { Browser } from '@stock-bot/browser';
import type { IServiceContainer } from '@stock-bot/handlers';
// Configuration types
@ -37,6 +41,10 @@ export interface AppConfig {
cachePrefix?: string;
ttl?: number;
};
browser?: {
headless?: boolean;
timeout?: number;
};
}
/**
@ -87,20 +95,45 @@ export function createServiceContainer(config: AppConfig): AwilixContainer {
return null;
}).singleton(),
// Database clients - placeholders for now
mongoClient: asFunction(() => {
// TODO: Create MongoDB client
return null;
// MongoDB client with injected logger
mongoClient: asFunction(({ mongoConfig, logger }) => {
// Parse MongoDB URI to extract host and port
const url = new URL(mongoConfig.uri);
return createMongoDBClient(
{
uri: mongoConfig.uri,
host: url.hostname,
port: parseInt(url.port || '27017'),
database: mongoConfig.database,
},
logger
);
}).singleton(),
postgresClient: asFunction(() => {
// TODO: Create PostgreSQL client
return null;
postgresClient: asFunction(({ postgresConfig, logger }) => {
return createPostgreSQLClient(
{
host: postgresConfig.host,
port: postgresConfig.port,
database: postgresConfig.database,
username: postgresConfig.user,
password: postgresConfig.password,
},
logger
);
}).singleton(),
questdbClient: asFunction(() => {
// TODO: Create QuestDB client
return null;
questdbClient: asFunction(({ questdbConfig, logger }) => {
return createQuestDBClient(
{
host: questdbConfig.host,
httpPort: 9000,
pgPort: questdbConfig.port || 8812,
influxPort: 9009,
database: 'questdb',
},
logger
);
}).singleton(),
// Queue manager - placeholder
@ -109,12 +142,18 @@ export function createServiceContainer(config: AppConfig): AwilixContainer {
return null;
}).singleton(),
// Browser automation
browser: asFunction(({ config, logger }) => {
return new Browser(logger, config.browser);
}).singleton(),
// Build the IServiceContainer for handlers
serviceContainer: asFunction((cradle) => ({
logger: cradle.logger,
cache: cradle.cache,
proxy: cradle.proxyManager,
http: cradle.httpClient,
browser: cradle.browser,
mongodb: cradle.mongoClient,
postgres: cradle.postgresClient,
questdb: cradle.questdbClient,
@ -146,8 +185,31 @@ export async function initializeServices(container: AwilixContainer): Promise<vo
logger.info('Proxy manager initialized');
}
// Initialize other async services as needed
// ...
// Connect database clients
const mongoClient = container.resolve('mongoClient');
if (mongoClient && typeof mongoClient.connect === 'function') {
await mongoClient.connect();
logger.info('MongoDB connected');
}
const postgresClient = container.resolve('postgresClient');
if (postgresClient && typeof postgresClient.connect === 'function') {
await postgresClient.connect();
logger.info('PostgreSQL connected');
}
const questdbClient = container.resolve('questdbClient');
if (questdbClient && typeof questdbClient.connect === 'function') {
await questdbClient.connect();
logger.info('QuestDB connected');
}
// Initialize browser if configured
const browser = container.resolve('browser');
if (browser && typeof browser.initialize === 'function') {
await browser.initialize();
logger.info('Browser initialized');
}
logger.info('All services initialized successfully');
} catch (error) {
@ -163,6 +225,7 @@ export interface ServiceCradle {
cache: CacheProvider;
proxyManager: ProxyManager;
httpClient: any;
browser: any;
mongoClient: any;
postgresClient: any;
questdbClient: any;

View file

@ -14,6 +14,7 @@ export abstract class BaseHandler implements IHandler {
readonly queue;
readonly http;
readonly proxy;
readonly browser;
readonly mongodb;
readonly postgres;
readonly questdb;
@ -27,6 +28,7 @@ export abstract class BaseHandler implements IHandler {
this.queue = services.queue;
this.http = services.http;
this.proxy = services.proxy;
this.browser = services.browser;
this.mongodb = services.mongodb;
this.postgres = services.postgres;
this.questdb = services.questdb;

View file

@ -16,6 +16,7 @@ export interface IServiceContainer {
readonly queue: any; // Queue manager (BullMQ)
readonly http: any; // HTTP client with proxy support
readonly proxy: ProxyManager; // Proxy manager service
readonly browser?: any; // Browser automation (Playwright)
// Database clients
readonly mongodb: any; // MongoDB client

View file

@ -1,4 +1,3 @@
import { getLogger } from '@stock-bot/logger';
import { Collection, Db, MongoClient, OptionalUnlessRequiredId } from 'mongodb';
import type { DocumentBase, MongoDBClientConfig, PoolMetrics, ConnectionEvents, DynamicPoolConfig } from './types';
@ -13,16 +12,17 @@ export class MongoDBClient {
private db: Db | null = null;
private readonly config: MongoDBClientConfig;
private defaultDatabase: string;
private readonly logger = getLogger('mongodb-client');
private readonly logger: any;
private isConnected = false;
private readonly metrics: PoolMetrics;
private readonly events?: ConnectionEvents;
private dynamicPoolConfig?: DynamicPoolConfig;
private poolMonitorInterval?: Timer;
constructor(config: MongoDBClientConfig, events?: ConnectionEvents) {
constructor(config: MongoDBClientConfig, logger?: any, events?: ConnectionEvents) {
this.config = config;
this.defaultDatabase = config.database || 'stock';
this.logger = logger || console;
this.events = events;
this.metrics = {
totalConnections: 0,

View file

@ -4,8 +4,8 @@ import type { MongoDBClientConfig, ConnectionEvents } from './types';
/**
* Factory function to create a MongoDB client instance
*/
export function createMongoDBClient(config: MongoDBClientConfig, events?: ConnectionEvents): MongoDBClient {
return new MongoDBClient(config, events);
export function createMongoDBClient(config: MongoDBClientConfig, logger?: any, events?: ConnectionEvents): MongoDBClient {
return new MongoDBClient(config, logger, events);
}
/**
@ -13,9 +13,10 @@ export function createMongoDBClient(config: MongoDBClientConfig, events?: Connec
*/
export async function createAndConnectMongoDBClient(
config: MongoDBClientConfig,
logger?: any,
events?: ConnectionEvents
): Promise<MongoDBClient> {
const client = createMongoDBClient(config, events);
const client = createMongoDBClient(config, logger, events);
await client.connect();
return client;
}

View file

@ -1,5 +1,4 @@
import { Pool, QueryResultRow } from 'pg';
import { getLogger } from '@stock-bot/logger';
import { PostgreSQLHealthMonitor } from './health';
import { PostgreSQLQueryBuilder } from './query-builder';
import { PostgreSQLTransactionManager } from './transactions';
@ -23,7 +22,7 @@ export class PostgreSQLClient {
private pool: Pool | null = null;
private readonly config: PostgreSQLClientConfig;
private readonly options: PostgreSQLConnectionOptions;
private readonly logger: ReturnType<typeof getLogger>;
private readonly logger: any;
private readonly healthMonitor: PostgreSQLHealthMonitor;
private readonly transactionManager: PostgreSQLTransactionManager;
private isConnected = false;
@ -32,7 +31,7 @@ export class PostgreSQLClient {
private dynamicPoolConfig?: DynamicPoolConfig;
private poolMonitorInterval?: NodeJS.Timeout;
constructor(config: PostgreSQLClientConfig, options?: PostgreSQLConnectionOptions, events?: ConnectionEvents) {
constructor(config: PostgreSQLClientConfig, logger?: any, options?: PostgreSQLConnectionOptions, events?: ConnectionEvents) {
this.config = config;
this.options = {
retryAttempts: 3,
@ -42,7 +41,7 @@ export class PostgreSQLClient {
};
this.events = events;
this.logger = getLogger('postgres-client');
this.logger = logger || console;
this.healthMonitor = new PostgreSQLHealthMonitor(this);
this.transactionManager = new PostgreSQLTransactionManager(this);

View file

@ -6,10 +6,11 @@ import type { PostgreSQLClientConfig, PostgreSQLConnectionOptions, ConnectionEve
*/
export function createPostgreSQLClient(
config: PostgreSQLClientConfig,
logger?: any,
options?: PostgreSQLConnectionOptions,
events?: ConnectionEvents
): PostgreSQLClient {
return new PostgreSQLClient(config, options, events);
return new PostgreSQLClient(config, logger, options, events);
}
/**
@ -17,10 +18,11 @@ export function createPostgreSQLClient(
*/
export async function createAndConnectPostgreSQLClient(
config: PostgreSQLClientConfig,
logger?: any,
options?: PostgreSQLConnectionOptions,
events?: ConnectionEvents
): Promise<PostgreSQLClient> {
const client = createPostgreSQLClient(config, options, events);
const client = createPostgreSQLClient(config, logger, options, events);
await client.connect();
return client;
}

View file

@ -1,5 +1,4 @@
import { Pool } from 'pg';
import { getLogger } from '@stock-bot/logger';
import { QuestDBHealthMonitor } from './health';
import { QuestDBInfluxWriter } from './influx-writer';
import { QuestDBQueryBuilder } from './query-builder';
@ -21,14 +20,15 @@ export class QuestDBClient {
private pgPool: Pool | null = null;
private readonly config: QuestDBClientConfig;
private readonly options: QuestDBConnectionOptions;
private readonly logger = getLogger('QuestDBClient');
private readonly logger: any;
private readonly healthMonitor: QuestDBHealthMonitor;
private readonly influxWriter: QuestDBInfluxWriter;
private readonly schemaManager: QuestDBSchemaManager;
private isConnected = false;
constructor(config: QuestDBClientConfig, options?: QuestDBConnectionOptions) {
constructor(config: QuestDBClientConfig, logger?: any, options?: QuestDBConnectionOptions) {
this.config = config;
this.logger = logger || console;
this.options = {
protocol: 'pg',
retryAttempts: 3,

View file

@ -6,9 +6,10 @@ import type { QuestDBClientConfig, QuestDBConnectionOptions } from './types';
*/
export function createQuestDBClient(
config: QuestDBClientConfig,
logger?: any,
options?: QuestDBConnectionOptions
): QuestDBClient {
return new QuestDBClient(config, options);
return new QuestDBClient(config, logger, options);
}
/**
@ -16,9 +17,10 @@ export function createQuestDBClient(
*/
export async function createAndConnectQuestDBClient(
config: QuestDBClientConfig,
logger?: any,
options?: QuestDBConnectionOptions
): Promise<QuestDBClient> {
const client = createQuestDBClient(config, options);
const client = createQuestDBClient(config, logger, options);
await client.connect();
return client;
}

View file

@ -1,20 +1,21 @@
import { BrowserContext, chromium, Page, Browser as PlaywrightBrowser } from 'playwright';
import { getLogger } from '@stock-bot/logger';
import type { BrowserOptions, NetworkEvent, NetworkEventHandler } from './types';
class BrowserSingleton {
export class Browser {
private browser?: PlaywrightBrowser;
private contexts: Map<string, BrowserContext> = new Map();
private logger = getLogger('browser');
private logger: any;
private options: BrowserOptions;
private initialized = false;
constructor() {
constructor(logger?: any, defaultOptions?: BrowserOptions) {
this.logger = logger || console;
this.options = {
headless: true,
timeout: 30000,
blockResources: false,
enableNetworkLogging: false,
...defaultOptions,
};
}
@ -359,8 +360,5 @@ class BrowserSingleton {
}
}
// Export singleton instance
export const Browser = new BrowserSingleton();
// Also export the class for typing if needed
export { BrowserSingleton as BrowserClass };
// Export default for backward compatibility
export default Browser;

View file

@ -1,3 +1,7 @@
export { Browser } from './browser';
export { BrowserTabManager } from './tab-manager';
// TODO: Update BrowserTabManager to work with non-singleton Browser
// export { BrowserTabManager } from './tab-manager';
export type { BrowserOptions, ScrapingResult } from './types';
// Default export for the class
export { default as BrowserClass } from './browser';