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 { createCache, type CacheProvider } from '@stock-bot/cache';
|
||||||
import { ProxyManager } from '@stock-bot/proxy';
|
import { ProxyManager } from '@stock-bot/proxy';
|
||||||
import { getLogger } from '@stock-bot/logger';
|
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';
|
import type { IServiceContainer } from '@stock-bot/handlers';
|
||||||
|
|
||||||
// Configuration types
|
// Configuration types
|
||||||
|
|
@ -37,6 +41,10 @@ export interface AppConfig {
|
||||||
cachePrefix?: string;
|
cachePrefix?: string;
|
||||||
ttl?: number;
|
ttl?: number;
|
||||||
};
|
};
|
||||||
|
browser?: {
|
||||||
|
headless?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,20 +95,45 @@ export function createServiceContainer(config: AppConfig): AwilixContainer {
|
||||||
return null;
|
return null;
|
||||||
}).singleton(),
|
}).singleton(),
|
||||||
|
|
||||||
// Database clients - placeholders for now
|
// MongoDB client with injected logger
|
||||||
mongoClient: asFunction(() => {
|
mongoClient: asFunction(({ mongoConfig, logger }) => {
|
||||||
// TODO: Create MongoDB client
|
// Parse MongoDB URI to extract host and port
|
||||||
return null;
|
const url = new URL(mongoConfig.uri);
|
||||||
|
return createMongoDBClient(
|
||||||
|
{
|
||||||
|
uri: mongoConfig.uri,
|
||||||
|
host: url.hostname,
|
||||||
|
port: parseInt(url.port || '27017'),
|
||||||
|
database: mongoConfig.database,
|
||||||
|
},
|
||||||
|
logger
|
||||||
|
);
|
||||||
}).singleton(),
|
}).singleton(),
|
||||||
|
|
||||||
postgresClient: asFunction(() => {
|
postgresClient: asFunction(({ postgresConfig, logger }) => {
|
||||||
// TODO: Create PostgreSQL client
|
return createPostgreSQLClient(
|
||||||
return null;
|
{
|
||||||
|
host: postgresConfig.host,
|
||||||
|
port: postgresConfig.port,
|
||||||
|
database: postgresConfig.database,
|
||||||
|
username: postgresConfig.user,
|
||||||
|
password: postgresConfig.password,
|
||||||
|
},
|
||||||
|
logger
|
||||||
|
);
|
||||||
}).singleton(),
|
}).singleton(),
|
||||||
|
|
||||||
questdbClient: asFunction(() => {
|
questdbClient: asFunction(({ questdbConfig, logger }) => {
|
||||||
// TODO: Create QuestDB client
|
return createQuestDBClient(
|
||||||
return null;
|
{
|
||||||
|
host: questdbConfig.host,
|
||||||
|
httpPort: 9000,
|
||||||
|
pgPort: questdbConfig.port || 8812,
|
||||||
|
influxPort: 9009,
|
||||||
|
database: 'questdb',
|
||||||
|
},
|
||||||
|
logger
|
||||||
|
);
|
||||||
}).singleton(),
|
}).singleton(),
|
||||||
|
|
||||||
// Queue manager - placeholder
|
// Queue manager - placeholder
|
||||||
|
|
@ -109,12 +142,18 @@ export function createServiceContainer(config: AppConfig): AwilixContainer {
|
||||||
return null;
|
return null;
|
||||||
}).singleton(),
|
}).singleton(),
|
||||||
|
|
||||||
|
// Browser automation
|
||||||
|
browser: asFunction(({ config, logger }) => {
|
||||||
|
return new Browser(logger, config.browser);
|
||||||
|
}).singleton(),
|
||||||
|
|
||||||
// Build the IServiceContainer for handlers
|
// Build the IServiceContainer for handlers
|
||||||
serviceContainer: asFunction((cradle) => ({
|
serviceContainer: asFunction((cradle) => ({
|
||||||
logger: cradle.logger,
|
logger: cradle.logger,
|
||||||
cache: cradle.cache,
|
cache: cradle.cache,
|
||||||
proxy: cradle.proxyManager,
|
proxy: cradle.proxyManager,
|
||||||
http: cradle.httpClient,
|
http: cradle.httpClient,
|
||||||
|
browser: cradle.browser,
|
||||||
mongodb: cradle.mongoClient,
|
mongodb: cradle.mongoClient,
|
||||||
postgres: cradle.postgresClient,
|
postgres: cradle.postgresClient,
|
||||||
questdb: cradle.questdbClient,
|
questdb: cradle.questdbClient,
|
||||||
|
|
@ -146,8 +185,31 @@ export async function initializeServices(container: AwilixContainer): Promise<vo
|
||||||
logger.info('Proxy manager initialized');
|
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');
|
logger.info('All services initialized successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -163,6 +225,7 @@ export interface ServiceCradle {
|
||||||
cache: CacheProvider;
|
cache: CacheProvider;
|
||||||
proxyManager: ProxyManager;
|
proxyManager: ProxyManager;
|
||||||
httpClient: any;
|
httpClient: any;
|
||||||
|
browser: any;
|
||||||
mongoClient: any;
|
mongoClient: any;
|
||||||
postgresClient: any;
|
postgresClient: any;
|
||||||
questdbClient: any;
|
questdbClient: any;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ export abstract class BaseHandler implements IHandler {
|
||||||
readonly queue;
|
readonly queue;
|
||||||
readonly http;
|
readonly http;
|
||||||
readonly proxy;
|
readonly proxy;
|
||||||
|
readonly browser;
|
||||||
readonly mongodb;
|
readonly mongodb;
|
||||||
readonly postgres;
|
readonly postgres;
|
||||||
readonly questdb;
|
readonly questdb;
|
||||||
|
|
@ -27,6 +28,7 @@ export abstract class BaseHandler implements IHandler {
|
||||||
this.queue = services.queue;
|
this.queue = services.queue;
|
||||||
this.http = services.http;
|
this.http = services.http;
|
||||||
this.proxy = services.proxy;
|
this.proxy = services.proxy;
|
||||||
|
this.browser = services.browser;
|
||||||
this.mongodb = services.mongodb;
|
this.mongodb = services.mongodb;
|
||||||
this.postgres = services.postgres;
|
this.postgres = services.postgres;
|
||||||
this.questdb = services.questdb;
|
this.questdb = services.questdb;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export interface IServiceContainer {
|
||||||
readonly queue: any; // Queue manager (BullMQ)
|
readonly queue: any; // Queue manager (BullMQ)
|
||||||
readonly http: any; // HTTP client with proxy support
|
readonly http: any; // HTTP client with proxy support
|
||||||
readonly proxy: ProxyManager; // Proxy manager service
|
readonly proxy: ProxyManager; // Proxy manager service
|
||||||
|
readonly browser?: any; // Browser automation (Playwright)
|
||||||
|
|
||||||
// Database clients
|
// Database clients
|
||||||
readonly mongodb: any; // MongoDB client
|
readonly mongodb: any; // MongoDB client
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { getLogger } from '@stock-bot/logger';
|
|
||||||
import { Collection, Db, MongoClient, OptionalUnlessRequiredId } from 'mongodb';
|
import { Collection, Db, MongoClient, OptionalUnlessRequiredId } from 'mongodb';
|
||||||
import type { DocumentBase, MongoDBClientConfig, PoolMetrics, ConnectionEvents, DynamicPoolConfig } from './types';
|
import type { DocumentBase, MongoDBClientConfig, PoolMetrics, ConnectionEvents, DynamicPoolConfig } from './types';
|
||||||
|
|
||||||
|
|
@ -13,16 +12,17 @@ export class MongoDBClient {
|
||||||
private db: Db | null = null;
|
private db: Db | null = null;
|
||||||
private readonly config: MongoDBClientConfig;
|
private readonly config: MongoDBClientConfig;
|
||||||
private defaultDatabase: string;
|
private defaultDatabase: string;
|
||||||
private readonly logger = getLogger('mongodb-client');
|
private readonly logger: any;
|
||||||
private isConnected = false;
|
private isConnected = false;
|
||||||
private readonly metrics: PoolMetrics;
|
private readonly metrics: PoolMetrics;
|
||||||
private readonly events?: ConnectionEvents;
|
private readonly events?: ConnectionEvents;
|
||||||
private dynamicPoolConfig?: DynamicPoolConfig;
|
private dynamicPoolConfig?: DynamicPoolConfig;
|
||||||
private poolMonitorInterval?: Timer;
|
private poolMonitorInterval?: Timer;
|
||||||
|
|
||||||
constructor(config: MongoDBClientConfig, events?: ConnectionEvents) {
|
constructor(config: MongoDBClientConfig, logger?: any, events?: ConnectionEvents) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.defaultDatabase = config.database || 'stock';
|
this.defaultDatabase = config.database || 'stock';
|
||||||
|
this.logger = logger || console;
|
||||||
this.events = events;
|
this.events = events;
|
||||||
this.metrics = {
|
this.metrics = {
|
||||||
totalConnections: 0,
|
totalConnections: 0,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import type { MongoDBClientConfig, ConnectionEvents } from './types';
|
||||||
/**
|
/**
|
||||||
* Factory function to create a MongoDB client instance
|
* Factory function to create a MongoDB client instance
|
||||||
*/
|
*/
|
||||||
export function createMongoDBClient(config: MongoDBClientConfig, events?: ConnectionEvents): MongoDBClient {
|
export function createMongoDBClient(config: MongoDBClientConfig, logger?: any, events?: ConnectionEvents): MongoDBClient {
|
||||||
return new MongoDBClient(config, events);
|
return new MongoDBClient(config, logger, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -13,9 +13,10 @@ export function createMongoDBClient(config: MongoDBClientConfig, events?: Connec
|
||||||
*/
|
*/
|
||||||
export async function createAndConnectMongoDBClient(
|
export async function createAndConnectMongoDBClient(
|
||||||
config: MongoDBClientConfig,
|
config: MongoDBClientConfig,
|
||||||
|
logger?: any,
|
||||||
events?: ConnectionEvents
|
events?: ConnectionEvents
|
||||||
): Promise<MongoDBClient> {
|
): Promise<MongoDBClient> {
|
||||||
const client = createMongoDBClient(config, events);
|
const client = createMongoDBClient(config, logger, events);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Pool, QueryResultRow } from 'pg';
|
import { Pool, QueryResultRow } from 'pg';
|
||||||
import { getLogger } from '@stock-bot/logger';
|
|
||||||
import { PostgreSQLHealthMonitor } from './health';
|
import { PostgreSQLHealthMonitor } from './health';
|
||||||
import { PostgreSQLQueryBuilder } from './query-builder';
|
import { PostgreSQLQueryBuilder } from './query-builder';
|
||||||
import { PostgreSQLTransactionManager } from './transactions';
|
import { PostgreSQLTransactionManager } from './transactions';
|
||||||
|
|
@ -23,7 +22,7 @@ export class PostgreSQLClient {
|
||||||
private pool: Pool | null = null;
|
private pool: Pool | null = null;
|
||||||
private readonly config: PostgreSQLClientConfig;
|
private readonly config: PostgreSQLClientConfig;
|
||||||
private readonly options: PostgreSQLConnectionOptions;
|
private readonly options: PostgreSQLConnectionOptions;
|
||||||
private readonly logger: ReturnType<typeof getLogger>;
|
private readonly logger: any;
|
||||||
private readonly healthMonitor: PostgreSQLHealthMonitor;
|
private readonly healthMonitor: PostgreSQLHealthMonitor;
|
||||||
private readonly transactionManager: PostgreSQLTransactionManager;
|
private readonly transactionManager: PostgreSQLTransactionManager;
|
||||||
private isConnected = false;
|
private isConnected = false;
|
||||||
|
|
@ -32,7 +31,7 @@ export class PostgreSQLClient {
|
||||||
private dynamicPoolConfig?: DynamicPoolConfig;
|
private dynamicPoolConfig?: DynamicPoolConfig;
|
||||||
private poolMonitorInterval?: NodeJS.Timeout;
|
private poolMonitorInterval?: NodeJS.Timeout;
|
||||||
|
|
||||||
constructor(config: PostgreSQLClientConfig, options?: PostgreSQLConnectionOptions, events?: ConnectionEvents) {
|
constructor(config: PostgreSQLClientConfig, logger?: any, options?: PostgreSQLConnectionOptions, events?: ConnectionEvents) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.options = {
|
this.options = {
|
||||||
retryAttempts: 3,
|
retryAttempts: 3,
|
||||||
|
|
@ -42,7 +41,7 @@ export class PostgreSQLClient {
|
||||||
};
|
};
|
||||||
this.events = events;
|
this.events = events;
|
||||||
|
|
||||||
this.logger = getLogger('postgres-client');
|
this.logger = logger || console;
|
||||||
this.healthMonitor = new PostgreSQLHealthMonitor(this);
|
this.healthMonitor = new PostgreSQLHealthMonitor(this);
|
||||||
this.transactionManager = new PostgreSQLTransactionManager(this);
|
this.transactionManager = new PostgreSQLTransactionManager(this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@ import type { PostgreSQLClientConfig, PostgreSQLConnectionOptions, ConnectionEve
|
||||||
*/
|
*/
|
||||||
export function createPostgreSQLClient(
|
export function createPostgreSQLClient(
|
||||||
config: PostgreSQLClientConfig,
|
config: PostgreSQLClientConfig,
|
||||||
|
logger?: any,
|
||||||
options?: PostgreSQLConnectionOptions,
|
options?: PostgreSQLConnectionOptions,
|
||||||
events?: ConnectionEvents
|
events?: ConnectionEvents
|
||||||
): PostgreSQLClient {
|
): 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(
|
export async function createAndConnectPostgreSQLClient(
|
||||||
config: PostgreSQLClientConfig,
|
config: PostgreSQLClientConfig,
|
||||||
|
logger?: any,
|
||||||
options?: PostgreSQLConnectionOptions,
|
options?: PostgreSQLConnectionOptions,
|
||||||
events?: ConnectionEvents
|
events?: ConnectionEvents
|
||||||
): Promise<PostgreSQLClient> {
|
): Promise<PostgreSQLClient> {
|
||||||
const client = createPostgreSQLClient(config, options, events);
|
const client = createPostgreSQLClient(config, logger, options, events);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Pool } from 'pg';
|
import { Pool } from 'pg';
|
||||||
import { getLogger } from '@stock-bot/logger';
|
|
||||||
import { QuestDBHealthMonitor } from './health';
|
import { QuestDBHealthMonitor } from './health';
|
||||||
import { QuestDBInfluxWriter } from './influx-writer';
|
import { QuestDBInfluxWriter } from './influx-writer';
|
||||||
import { QuestDBQueryBuilder } from './query-builder';
|
import { QuestDBQueryBuilder } from './query-builder';
|
||||||
|
|
@ -21,14 +20,15 @@ export class QuestDBClient {
|
||||||
private pgPool: Pool | null = null;
|
private pgPool: Pool | null = null;
|
||||||
private readonly config: QuestDBClientConfig;
|
private readonly config: QuestDBClientConfig;
|
||||||
private readonly options: QuestDBConnectionOptions;
|
private readonly options: QuestDBConnectionOptions;
|
||||||
private readonly logger = getLogger('QuestDBClient');
|
private readonly logger: any;
|
||||||
private readonly healthMonitor: QuestDBHealthMonitor;
|
private readonly healthMonitor: QuestDBHealthMonitor;
|
||||||
private readonly influxWriter: QuestDBInfluxWriter;
|
private readonly influxWriter: QuestDBInfluxWriter;
|
||||||
private readonly schemaManager: QuestDBSchemaManager;
|
private readonly schemaManager: QuestDBSchemaManager;
|
||||||
private isConnected = false;
|
private isConnected = false;
|
||||||
|
|
||||||
constructor(config: QuestDBClientConfig, options?: QuestDBConnectionOptions) {
|
constructor(config: QuestDBClientConfig, logger?: any, options?: QuestDBConnectionOptions) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.logger = logger || console;
|
||||||
this.options = {
|
this.options = {
|
||||||
protocol: 'pg',
|
protocol: 'pg',
|
||||||
retryAttempts: 3,
|
retryAttempts: 3,
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ import type { QuestDBClientConfig, QuestDBConnectionOptions } from './types';
|
||||||
*/
|
*/
|
||||||
export function createQuestDBClient(
|
export function createQuestDBClient(
|
||||||
config: QuestDBClientConfig,
|
config: QuestDBClientConfig,
|
||||||
|
logger?: any,
|
||||||
options?: QuestDBConnectionOptions
|
options?: QuestDBConnectionOptions
|
||||||
): QuestDBClient {
|
): QuestDBClient {
|
||||||
return new QuestDBClient(config, options);
|
return new QuestDBClient(config, logger, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -16,9 +17,10 @@ export function createQuestDBClient(
|
||||||
*/
|
*/
|
||||||
export async function createAndConnectQuestDBClient(
|
export async function createAndConnectQuestDBClient(
|
||||||
config: QuestDBClientConfig,
|
config: QuestDBClientConfig,
|
||||||
|
logger?: any,
|
||||||
options?: QuestDBConnectionOptions
|
options?: QuestDBConnectionOptions
|
||||||
): Promise<QuestDBClient> {
|
): Promise<QuestDBClient> {
|
||||||
const client = createQuestDBClient(config, options);
|
const client = createQuestDBClient(config, logger, options);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
import { BrowserContext, chromium, Page, Browser as PlaywrightBrowser } from 'playwright';
|
import { BrowserContext, chromium, Page, Browser as PlaywrightBrowser } from 'playwright';
|
||||||
import { getLogger } from '@stock-bot/logger';
|
|
||||||
import type { BrowserOptions, NetworkEvent, NetworkEventHandler } from './types';
|
import type { BrowserOptions, NetworkEvent, NetworkEventHandler } from './types';
|
||||||
|
|
||||||
class BrowserSingleton {
|
export class Browser {
|
||||||
private browser?: PlaywrightBrowser;
|
private browser?: PlaywrightBrowser;
|
||||||
private contexts: Map<string, BrowserContext> = new Map();
|
private contexts: Map<string, BrowserContext> = new Map();
|
||||||
private logger = getLogger('browser');
|
private logger: any;
|
||||||
private options: BrowserOptions;
|
private options: BrowserOptions;
|
||||||
private initialized = false;
|
private initialized = false;
|
||||||
|
|
||||||
constructor() {
|
constructor(logger?: any, defaultOptions?: BrowserOptions) {
|
||||||
|
this.logger = logger || console;
|
||||||
this.options = {
|
this.options = {
|
||||||
headless: true,
|
headless: true,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
blockResources: false,
|
blockResources: false,
|
||||||
enableNetworkLogging: false,
|
enableNetworkLogging: false,
|
||||||
|
...defaultOptions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,8 +360,5 @@ class BrowserSingleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export singleton instance
|
// Export default for backward compatibility
|
||||||
export const Browser = new BrowserSingleton();
|
export default Browser;
|
||||||
|
|
||||||
// Also export the class for typing if needed
|
|
||||||
export { BrowserSingleton as BrowserClass };
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
export { Browser } from './browser';
|
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';
|
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