fixed webshare

This commit is contained in:
Boki 2025-06-20 00:04:38 -04:00
parent 9413d6588d
commit b501d7a2da
5 changed files with 67 additions and 5 deletions

View file

@ -16,7 +16,7 @@
"redis": { "redis": {
"host": "localhost", "host": "localhost",
"port": 6379, "port": 6379,
"db": 1 "db": 0
}, },
"defaultJobOptions": { "defaultJobOptions": {
"attempts": 3, "attempts": 3,
@ -27,5 +27,9 @@
"removeOnComplete": true, "removeOnComplete": true,
"removeOnFail": false "removeOnFail": false
} }
},
"webshare": {
"apiKey": "",
"apiUrl": "https://proxy.webshare.io/api/v2/"
} }
} }

View file

@ -95,9 +95,13 @@ export const webShareProvider = {
async function fetchProxiesFromWebShare(): Promise<string[] | null> { async function fetchProxiesFromWebShare(): Promise<string[] | null> {
try { try {
// Get configuration from config system
const { getConfig } = await import('@stock-bot/config');
const config = getConfig();
// Try environment variables first, then fall back to config // Try environment variables first, then fall back to config
const apiKey = process.env.WEBSHARE_API_KEY; const apiKey = process.env.WEBSHARE_API_KEY || config.webshare?.apiKey;
const apiUrl = process.env.WEBSHARE_API_URL; const apiUrl = process.env.WEBSHARE_API_URL || config.webshare?.apiUrl;
if (!apiKey || !apiUrl) { if (!apiKey || !apiUrl) {
logger.error('Missing WebShare configuration', { logger.error('Missing WebShare configuration', {
@ -105,6 +109,8 @@ async function fetchProxiesFromWebShare(): Promise<string[] | null> {
hasApiUrl: !!apiUrl, hasApiUrl: !!apiUrl,
envApiKey: process.env.WEBSHARE_API_KEY?.substring(0, 10) + '...', envApiKey: process.env.WEBSHARE_API_KEY?.substring(0, 10) + '...',
envApiUrl: process.env.WEBSHARE_API_URL, envApiUrl: process.env.WEBSHARE_API_URL,
configApiKey: config.webshare?.apiKey?.substring(0, 10) + '...',
configApiUrl: config.webshare?.apiUrl,
}); });
return null; return null;
} }

View file

@ -1,5 +1,6 @@
import { ConfigLoader } from '../types'; import { ConfigLoader } from '../types';
import { ConfigLoaderError } from '../errors'; import { ConfigLoaderError } from '../errors';
import { readFileSync } from 'fs';
export interface EnvLoaderOptions { export interface EnvLoaderOptions {
convertCase?: boolean; convertCase?: boolean;
@ -26,6 +27,9 @@ export class EnvLoader implements ConfigLoader {
async load(): Promise<Record<string, unknown>> { async load(): Promise<Record<string, unknown>> {
try { try {
// Load root .env file only
this.loadEnvFile('../../.env'); // Root .env
const config: Record<string, unknown> = {}; const config: Record<string, unknown> = {};
const envVars = process.env; const envVars = process.env;
@ -137,4 +141,42 @@ export class EnvLoader implements ConfigLoader {
// Return as string // Return as string
return value; return value;
} }
private loadEnvFile(filePath: string): void {
try {
const envContent = readFileSync(filePath, 'utf-8');
const lines = envContent.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) {
continue; // Skip empty lines and comments
}
const equalIndex = trimmed.indexOf('=');
if (equalIndex === -1) {
continue; // Skip lines without =
}
const key = trimmed.substring(0, equalIndex).trim();
let value = trimmed.substring(equalIndex + 1).trim();
// Remove surrounding quotes if present
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
// Only set if not already set (allows override precedence)
if (!(key in process.env)) {
process.env[key] = value;
}
}
} catch (error: any) {
// File not found is not an error (env files are optional)
if (error.code !== 'ENOENT') {
console.warn(`Warning: Could not load env file ${filePath}:`, error.message);
}
}
}
} }

View file

@ -7,7 +7,7 @@ import { z } from 'zod';
import { baseConfigSchema, environmentSchema } from './base.schema'; import { baseConfigSchema, environmentSchema } from './base.schema';
import { databaseConfigSchema } from './database.schema'; import { databaseConfigSchema } from './database.schema';
import { serviceConfigSchema, loggingConfigSchema, queueConfigSchema, httpConfigSchema } from './service.schema'; import { serviceConfigSchema, loggingConfigSchema, queueConfigSchema, httpConfigSchema } from './service.schema';
import { providerConfigSchema } from './provider.schema'; import { providerConfigSchema, webshareProviderConfigSchema } from './provider.schema';
// Complete application configuration schema // Complete application configuration schema
export const appConfigSchema = baseConfigSchema.extend({ export const appConfigSchema = baseConfigSchema.extend({
@ -18,6 +18,7 @@ export const appConfigSchema = baseConfigSchema.extend({
queue: queueConfigSchema.optional(), queue: queueConfigSchema.optional(),
http: httpConfigSchema.optional(), http: httpConfigSchema.optional(),
providers: providerConfigSchema.optional(), providers: providerConfigSchema.optional(),
webshare: webshareProviderConfigSchema.optional(),
}); });
export type AppConfig = z.infer<typeof appConfigSchema>; export type AppConfig = z.infer<typeof appConfigSchema>;

View file

@ -46,20 +46,29 @@ export const yahooProviderConfigSchema = baseProviderConfigSchema.extend({
crumb: z.string().optional(), crumb: z.string().optional(),
}); });
// WebShare proxy provider
export const webshareProviderConfigSchema = z.object({
apiKey: z.string().optional(),
apiUrl: z.string().default('https://proxy.webshare.io/api/v2/'),
enabled: z.boolean().default(true),
});
// Combined provider configuration // Combined provider configuration
export const providerConfigSchema = z.object({ export const providerConfigSchema = z.object({
eod: eodProviderConfigSchema.optional(), eod: eodProviderConfigSchema.optional(),
ib: ibProviderConfigSchema.optional(), ib: ibProviderConfigSchema.optional(),
qm: qmProviderConfigSchema.optional(), qm: qmProviderConfigSchema.optional(),
yahoo: yahooProviderConfigSchema.optional(), yahoo: yahooProviderConfigSchema.optional(),
webshare: webshareProviderConfigSchema.optional(),
}); });
// Dynamic provider configuration type // Dynamic provider configuration type
export type ProviderName = 'eod' | 'ib' | 'qm' | 'yahoo'; export type ProviderName = 'eod' | 'ib' | 'qm' | 'yahoo' | 'webshare';
export const providerSchemas = { export const providerSchemas = {
eod: eodProviderConfigSchema, eod: eodProviderConfigSchema,
ib: ibProviderConfigSchema, ib: ibProviderConfigSchema,
qm: qmProviderConfigSchema, qm: qmProviderConfigSchema,
yahoo: yahooProviderConfigSchema, yahoo: yahooProviderConfigSchema,
webshare: webshareProviderConfigSchema,
} as const; } as const;