fixed up more type issues
This commit is contained in:
parent
3a10560de4
commit
87037e013f
9 changed files with 210 additions and 52 deletions
|
|
@ -4,7 +4,8 @@
|
|||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { MasterExchange } from '@stock-bot/mongodb-client';
|
||||
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
import { handlerRegistry } from '@stock-bot/queue';
|
||||
import { createJobHandler, handlerRegistry } from '@stock-bot/queue';
|
||||
import type { IBExchange } from '../types/exchange.types';
|
||||
|
||||
const logger = getLogger('exchange-sync');
|
||||
|
||||
|
|
@ -15,16 +16,16 @@ export function initializeExchangeSyncProvider() {
|
|||
name: 'exchange-sync',
|
||||
|
||||
operations: {
|
||||
'sync-ib-exchanges': async _payload => {
|
||||
'sync-ib-exchanges': createJobHandler(async () => {
|
||||
logger.info('Syncing IB exchanges to master table');
|
||||
return await syncIBExchanges();
|
||||
},
|
||||
}),
|
||||
|
||||
'get-master-exchange': async (payload: { masterExchangeId: string }) => {
|
||||
'get-master-exchange': createJobHandler(async (payload: { masterExchangeId: string }) => {
|
||||
logger.debug('Getting master exchange details', payload);
|
||||
const exchange = await getMasterExchangeDetails(payload.masterExchangeId);
|
||||
return { exchange, ...payload };
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
scheduledJobs: [
|
||||
|
|
@ -60,7 +61,7 @@ async function syncIBExchanges(): Promise<{ syncedCount: number; totalExchanges:
|
|||
|
||||
// Filter by country code US and CA
|
||||
const ibExchanges = await db
|
||||
.collection('ibExchanges')
|
||||
.collection<IBExchange>('ibExchanges')
|
||||
.find({
|
||||
country_code: { $in: ['US', 'CA'] },
|
||||
})
|
||||
|
|
@ -99,14 +100,7 @@ async function syncIBExchanges(): Promise<{ syncedCount: number; totalExchanges:
|
|||
/**
|
||||
* Create or update master exchange record 1:1 from IB exchange
|
||||
*/
|
||||
async function createOrUpdateMasterExchange(ibExchange: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
code?: string;
|
||||
country_code?: string;
|
||||
currency?: string;
|
||||
_id?: unknown;
|
||||
}): Promise<void> {
|
||||
async function createOrUpdateMasterExchange(ibExchange: IBExchange): Promise<void> {
|
||||
const { connectMongoDB, getDatabase } = await import('@stock-bot/mongodb-client');
|
||||
|
||||
await connectMongoDB();
|
||||
|
|
@ -191,11 +185,7 @@ async function getMasterExchangeDetails(masterExchangeId: string): Promise<Maste
|
|||
/**
|
||||
* Generate master exchange ID from IB exchange
|
||||
*/
|
||||
function generateMasterExchangeId(ibExchange: {
|
||||
name?: string;
|
||||
code?: string;
|
||||
id?: string;
|
||||
}): string {
|
||||
function generateMasterExchangeId(ibExchange: IBExchange): string {
|
||||
// Use code if available, otherwise use ID, otherwise generate from name
|
||||
if (ibExchange.code) {
|
||||
return ibExchange.code.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
||||
|
|
@ -220,7 +210,7 @@ function generateMasterExchangeId(ibExchange: {
|
|||
/**
|
||||
* Generate aliases for the exchange
|
||||
*/
|
||||
function generateAliases(ibExchange: { name?: string; code?: string }): string[] {
|
||||
function generateAliases(ibExchange: IBExchange): string[] {
|
||||
const aliases: string[] = [];
|
||||
|
||||
if (ibExchange.name && ibExchange.name.includes(' ')) {
|
||||
|
|
@ -244,7 +234,7 @@ function generateAliases(ibExchange: { name?: string; code?: string }): string[]
|
|||
/**
|
||||
* Infer timezone from exchange name/location
|
||||
*/
|
||||
function inferTimezone(ibExchange: { name?: string }): string {
|
||||
function inferTimezone(ibExchange: IBExchange): string {
|
||||
if (!ibExchange.name) {
|
||||
return 'UTC';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@
|
|||
* Interactive Brokers Provider for new queue system
|
||||
*/
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
import { handlerRegistry } from '@stock-bot/queue';
|
||||
import {
|
||||
createJobHandler,
|
||||
handlerRegistry,
|
||||
type HandlerConfigWithSchedule,
|
||||
} from '@stock-bot/queue';
|
||||
|
||||
const logger = getLogger('ib-provider');
|
||||
|
||||
|
|
@ -14,14 +17,14 @@ export function initializeIBProvider() {
|
|||
const ibProviderConfig: HandlerConfigWithSchedule = {
|
||||
name: 'ib',
|
||||
operations: {
|
||||
'fetch-session': async _payload => {
|
||||
'fetch-session': createJobHandler(async () => {
|
||||
// payload contains session configuration (not used in current implementation)
|
||||
logger.debug('Processing session fetch request');
|
||||
const { fetchSession } = await import('./ib.tasks');
|
||||
return fetchSession();
|
||||
},
|
||||
}),
|
||||
|
||||
'fetch-exchanges': async _payload => {
|
||||
'fetch-exchanges': createJobHandler(async () => {
|
||||
// payload should contain session headers
|
||||
logger.debug('Processing exchanges fetch request');
|
||||
const { fetchSession, fetchExchanges } = await import('./ib.tasks');
|
||||
|
|
@ -30,9 +33,9 @@ export function initializeIBProvider() {
|
|||
return fetchExchanges(sessionHeaders);
|
||||
}
|
||||
throw new Error('Failed to get session headers');
|
||||
},
|
||||
}),
|
||||
|
||||
'fetch-symbols': async _payload => {
|
||||
'fetch-symbols': createJobHandler(async () => {
|
||||
// payload should contain session headers
|
||||
logger.debug('Processing symbols fetch request');
|
||||
const { fetchSession, fetchSymbols } = await import('./ib.tasks');
|
||||
|
|
@ -41,9 +44,9 @@ export function initializeIBProvider() {
|
|||
return fetchSymbols(sessionHeaders);
|
||||
}
|
||||
throw new Error('Failed to get session headers');
|
||||
},
|
||||
}),
|
||||
|
||||
'ib-exchanges-and-symbols': async _payload => {
|
||||
'ib-exchanges-and-symbols': createJobHandler(async () => {
|
||||
// Legacy operation for scheduled jobs
|
||||
logger.info('Fetching symbol summary from IB');
|
||||
const { fetchSession, fetchExchanges, fetchSymbols } = await import('./ib.tasks');
|
||||
|
|
@ -62,7 +65,8 @@ export function initializeIBProvider() {
|
|||
|
||||
return { exchangesCount: exchanges?.length, symbolsCount: symbols?.length };
|
||||
}
|
||||
},
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
scheduledJobs: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
*/
|
||||
import { ProxyInfo } from '@stock-bot/http';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
import { handlerRegistry } from '@stock-bot/queue';
|
||||
import { handlerRegistry, createJobHandler, type HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
|
||||
const logger = getLogger('proxy-provider');
|
||||
|
||||
|
|
@ -16,7 +15,7 @@ export function initializeProxyProvider() {
|
|||
name: 'proxy',
|
||||
|
||||
operations: {
|
||||
'fetch-from-sources': async _payload => {
|
||||
'fetch-from-sources': createJobHandler(async () => {
|
||||
// Fetch proxies from all configured sources
|
||||
logger.info('Processing fetch proxies from sources request');
|
||||
const { fetchProxiesFromSources } = await import('./proxy.tasks');
|
||||
|
|
@ -59,16 +58,16 @@ export function initializeProxyProvider() {
|
|||
batchesCreated: batchResult.batchesCreated,
|
||||
mode: batchResult.mode,
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
'check-proxy': async (payload: ProxyInfo) => {
|
||||
'check-proxy': createJobHandler(async (payload: ProxyInfo) => {
|
||||
// payload is now the raw proxy info object
|
||||
logger.debug('Processing proxy check request', {
|
||||
proxy: `${payload.host}:${payload.port}`,
|
||||
});
|
||||
const { checkProxy } = await import('./proxy.tasks');
|
||||
return checkProxy(payload);
|
||||
},
|
||||
}),
|
||||
},
|
||||
scheduledJobs: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,24 +1,28 @@
|
|||
import { getLogger } from '@stock-bot/logger';
|
||||
import { handlerRegistry, type HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
import {
|
||||
handlerRegistry,
|
||||
createJobHandler,
|
||||
type HandlerConfigWithSchedule
|
||||
} from '@stock-bot/queue';
|
||||
import type { SymbolSpiderJob } from './qm.tasks';
|
||||
|
||||
const logger = getLogger('qm-provider');
|
||||
|
||||
// Initialize and register the IB provider
|
||||
// Initialize and register the QM provider
|
||||
export function initializeQMProvider() {
|
||||
logger.debug('Registering IB provider with scheduled jobs...');
|
||||
logger.debug('Registering QM provider with scheduled jobs...');
|
||||
|
||||
const qmProviderConfig: HandlerConfigWithSchedule = {
|
||||
name: 'qm',
|
||||
operations: {
|
||||
'create-sessions': async () => {
|
||||
'create-sessions': createJobHandler(async () => {
|
||||
logger.debug('Creating QM sessions...');
|
||||
const { createSessions } = await import('./qm.tasks');
|
||||
await createSessions();
|
||||
logger.debug('QM sessions created successfully');
|
||||
return { success: true, message: 'QM sessions created successfully' };
|
||||
},
|
||||
'search-symbols': async () => {
|
||||
}),
|
||||
'search-symbols': createJobHandler(async () => {
|
||||
logger.info('Starting QM symbol search...');
|
||||
const { fetchSymbols } = await import('./qm.tasks');
|
||||
const symbols = await fetchSymbols();
|
||||
|
|
@ -39,8 +43,8 @@ export function initializeQMProvider() {
|
|||
count: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
'spider-symbol-search': async (payload: SymbolSpiderJob) => {
|
||||
}),
|
||||
'spider-symbol-search': createJobHandler(async (payload: SymbolSpiderJob) => {
|
||||
logger.debug('Processing spider symbol search job', { payload });
|
||||
const { spiderSymbolSearch } = await import('./qm.tasks');
|
||||
const result = await spiderSymbolSearch(payload);
|
||||
|
|
@ -48,12 +52,10 @@ export function initializeQMProvider() {
|
|||
logger.debug('Spider search job completed', {
|
||||
success: result.success,
|
||||
symbolsFound: result.symbolsFound,
|
||||
jobsCreated: result.jobsCreated,
|
||||
payload,
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
scheduledJobs: [
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
* WebShare Provider for proxy management
|
||||
*/
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
import { handlerRegistry } from '@stock-bot/queue';
|
||||
import { handlerRegistry, createJobHandler, type HandlerConfigWithSchedule } from '@stock-bot/queue';
|
||||
|
||||
const logger = getLogger('webshare-provider');
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ export function initializeWebShareProvider() {
|
|||
name: 'webshare',
|
||||
|
||||
operations: {
|
||||
'fetch-proxies': async _payload => {
|
||||
'fetch-proxies': createJobHandler(async () => {
|
||||
logger.debug('Fetching proxies from WebShare API');
|
||||
|
||||
try {
|
||||
|
|
@ -66,7 +65,7 @@ export function initializeWebShareProvider() {
|
|||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
};
|
||||
}
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
scheduledJobs: [
|
||||
|
|
|
|||
40
apps/data-service/src/types/exchange.types.ts
Normal file
40
apps/data-service/src/types/exchange.types.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Type definitions for exchange data structures
|
||||
*/
|
||||
|
||||
export interface IBExchange {
|
||||
id: string;
|
||||
country_code: string;
|
||||
name: string;
|
||||
code?: string;
|
||||
exchange_code?: string;
|
||||
currency?: string;
|
||||
timezone?: string;
|
||||
_id?: unknown; // MongoDB ObjectId
|
||||
// Add other properties as needed
|
||||
}
|
||||
|
||||
export interface MasterExchangeData {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
country: string;
|
||||
currency: string;
|
||||
// Add other properties as needed
|
||||
}
|
||||
|
||||
export interface QMSymbol {
|
||||
symbol: string;
|
||||
exchange?: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
// Add other properties as needed
|
||||
}
|
||||
|
||||
export interface IBSymbol {
|
||||
symbol: string;
|
||||
exchange: string;
|
||||
name?: string;
|
||||
currency?: string;
|
||||
// Add other properties as needed
|
||||
}
|
||||
93
apps/data-service/src/types/job-payloads.ts
Normal file
93
apps/data-service/src/types/job-payloads.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Type definitions for all job payloads across data service providers
|
||||
*/
|
||||
|
||||
// Common result types
|
||||
export interface JobResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface CountableJobResult extends JobResult {
|
||||
count: number;
|
||||
}
|
||||
|
||||
// QM Provider Types
|
||||
export interface SymbolSpiderJob {
|
||||
prefix: string | null; // null = root job (A-Z)
|
||||
depth: number; // 1=A, 2=AA, 3=AAA, etc.
|
||||
source: string; // 'qm'
|
||||
maxDepth?: number; // optional max depth limit
|
||||
}
|
||||
|
||||
export interface CreateSessionsResult extends JobResult {
|
||||
// No additional fields needed
|
||||
}
|
||||
|
||||
export interface SearchSymbolsResult extends CountableJobResult {
|
||||
symbols?: unknown[]; // First 10 symbols as sample
|
||||
}
|
||||
|
||||
export interface SpiderSymbolSearchResult extends JobResult {
|
||||
symbolsFound: number;
|
||||
newSymbolsAdded: number;
|
||||
duplicatesSkipped: number;
|
||||
errors: number;
|
||||
depth: number;
|
||||
prefix: string | null;
|
||||
}
|
||||
|
||||
// IB Provider Types
|
||||
export interface FetchSessionResult extends JobResult {
|
||||
sessionData?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface FetchExchangesResult extends CountableJobResult {
|
||||
exchanges?: unknown[];
|
||||
}
|
||||
|
||||
export interface FetchSymbolsResult extends CountableJobResult {
|
||||
symbols?: unknown[];
|
||||
}
|
||||
|
||||
export interface IBExchangesAndSymbolsResult extends JobResult {
|
||||
exchanges: FetchExchangesResult;
|
||||
symbols: FetchSymbolsResult;
|
||||
}
|
||||
|
||||
// Proxy Provider Types
|
||||
export interface ProxyInfo {
|
||||
host: string;
|
||||
port: number;
|
||||
protocol: 'http' | 'https' | 'socks4' | 'socks5';
|
||||
username?: string;
|
||||
password?: string;
|
||||
country?: string;
|
||||
city?: string;
|
||||
isValid?: boolean;
|
||||
lastChecked?: Date;
|
||||
}
|
||||
|
||||
export interface FetchProxiesFromSourcesResult extends CountableJobResult {
|
||||
proxies?: ProxyInfo[];
|
||||
sources: string[];
|
||||
}
|
||||
|
||||
export interface CheckProxyResult extends JobResult {
|
||||
proxy: ProxyInfo;
|
||||
responseTime?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// WebShare Provider Types
|
||||
export interface FetchWebShareProxiesResult extends CountableJobResult {
|
||||
proxies?: ProxyInfo[];
|
||||
activeProxies: number;
|
||||
totalQuota: number;
|
||||
remainingQuota: number;
|
||||
}
|
||||
|
||||
// No payload job types (for operations that don't need input)
|
||||
export interface NoPayload {
|
||||
// Empty interface for operations that don't need payload
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
export { Queue, type QueueWorkerConfig } from './queue';
|
||||
export { QueueManager } from './queue-manager';
|
||||
export { handlerRegistry } from './handler-registry';
|
||||
export { createJobHandler } from './types';
|
||||
|
||||
// Batch processing
|
||||
export { processBatchJob, processItems } from './batch-processor';
|
||||
|
|
@ -34,8 +35,11 @@ export type {
|
|||
|
||||
// Handler types
|
||||
JobHandler,
|
||||
TypedJobHandler,
|
||||
HandlerConfig,
|
||||
TypedHandlerConfig,
|
||||
HandlerConfigWithSchedule,
|
||||
TypedHandlerConfigWithSchedule,
|
||||
HandlerInitializer,
|
||||
|
||||
// Configuration types
|
||||
|
|
|
|||
|
|
@ -104,6 +104,18 @@ export interface JobHandler<TPayload = unknown, TResult = unknown> {
|
|||
(payload: TPayload): Promise<TResult>;
|
||||
}
|
||||
|
||||
// Type-safe wrapper for creating job handlers
|
||||
export type TypedJobHandler<TPayload, TResult = unknown> = (payload: TPayload) => Promise<TResult>;
|
||||
|
||||
// Helper to create type-safe job handlers
|
||||
export function createJobHandler<TPayload = unknown, TResult = unknown>(
|
||||
handler: TypedJobHandler<TPayload, TResult>
|
||||
): JobHandler<unknown, TResult> {
|
||||
return async (payload: unknown): Promise<TResult> => {
|
||||
return handler(payload as TPayload);
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScheduledJob<T = unknown> {
|
||||
type: string;
|
||||
operation: string;
|
||||
|
|
@ -119,6 +131,11 @@ export interface HandlerConfig {
|
|||
[operation: string]: JobHandler;
|
||||
}
|
||||
|
||||
// Type-safe handler configuration
|
||||
export type TypedHandlerConfig<T extends Record<string, JobHandler> = Record<string, JobHandler>> = {
|
||||
[K in keyof T]: T[K];
|
||||
};
|
||||
|
||||
export interface HandlerConfigWithSchedule {
|
||||
name: string;
|
||||
operations: Record<string, JobHandler>;
|
||||
|
|
@ -128,6 +145,16 @@ export interface HandlerConfigWithSchedule {
|
|||
operationLimits?: Record<string, RateLimitConfig>;
|
||||
}
|
||||
|
||||
// Type-safe version of HandlerConfigWithSchedule
|
||||
export interface TypedHandlerConfigWithSchedule<T extends Record<string, JobHandler> = Record<string, JobHandler>> {
|
||||
name: string;
|
||||
operations: T;
|
||||
scheduledJobs?: ScheduledJob[];
|
||||
// Rate limiting
|
||||
rateLimit?: RateLimitConfig;
|
||||
operationLimits?: Record<string, RateLimitConfig>;
|
||||
}
|
||||
|
||||
export interface BatchJobData {
|
||||
payloadKey: string;
|
||||
batchIndex: number;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue