refactored db's and browser
This commit is contained in:
parent
a0a3b26177
commit
89cbfb7848
12 changed files with 111 additions and 39 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue