-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
148 lines (129 loc) · 5.63 KB
/
main.js
File metadata and controls
148 lines (129 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Global timestamp prefix for all console output
function tsPrefix() {
const d = new Date();
const pad = n => String(n).padStart(2, '0');
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
const origLog = console.log;
console.log = (...args) => {
const t = tsPrefix();
if (typeof args[0] === 'string') {
origLog(`${t} ${args[0]}`, ...args.slice(1));
} else {
origLog(t, ...args);
}
};
const origErr = console.error;
console.error = (...args) => {
const t = tsPrefix();
if (typeof args[0] === 'string') {
origErr(`${t} ${args[0]}`, ...args.slice(1));
} else {
origErr(t, ...args);
}
};
const Config = require('./src/core/config');
const Auth = require('./src/core/auth');
const KeyRotator = require('./src/core/keyRotator');
const GeminiClient = require('./src/providers/gemini');
const OpenAIClient = require('./src/providers/openai');
const ProxyServer = require('./src/server');
const KeyVault = require('./src/core/keyVault');
const SettingsManager = require('./src/core/settingsManager');
function main() {
try {
// Create SettingsManager before Config — it's the settings data source
const settingsManager = new SettingsManager();
// First-time migration: if settings.json doesn't exist, migrate from .env
if (settingsManager.needsMigration()) {
console.log('[INIT] Settings file not found, running first-time migration from .env...');
const localEnvPath = require('path').join(process.cwd(), '.env');
const fs = require('fs');
let envVars = {};
if (fs.existsSync(localEnvPath)) {
const Config = require('./src/core/config');
envVars = Config.prototype.parseEnvFile ? {} : {};
// Parse .env manually for migration
const content = fs.readFileSync(localEnvPath, 'utf8');
for (const line of content.split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const eqIdx = trimmed.indexOf('=');
if (eqIdx === -1) continue;
const key = trimmed.substring(0, eqIdx).trim();
const val = trimmed.substring(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
envVars[key] = val;
}
}
settingsManager.runMigrationFromEnv(envVars);
}
// Create KeyVault before Config — it's the key data source
const vault = new KeyVault();
// First-time migration: if vault is empty, do a preliminary Config load from env,
// migrate to vault, then let Config read from vault.
if (vault.needsMigration()) {
console.log('[INIT] Vault is empty, running first-time migration from .env files...');
const tempConfig = new Config(); // Load from env for migration source
const knownDefaults = tempConfig.knownDefaults || {};
vault.runMigration(tempConfig, knownDefaults);
}
const config = new Config({ keyVault: vault, settingsManager });
// Config constructor already called loadConfig(), which reads from vault
// Migrate admin password from .env to hash file if needed
const envPassword = config.envVars.ADMIN_PASSWORD;
if (envPassword && !Auth.loadHashFromFile()) {
Auth.migrateFromEnv(envPassword);
Auth.removePasswordFromEnv(require('path').join(process.cwd(), '.env'));
console.log('[INIT] Admin password migrated from .env to secure hash file');
}
// Initialize Destination Manager
const destMgr = require('./src/destinations/manager');
if (process.platform === 'win32') {
const WindowsEnv = require('./src/destinations/windowsEnv');
destMgr.register(WindowsEnv);
}
console.log(`[INIT] Destination Manager initialized with ${destMgr.destinations.length} targets`);
// Initialize Key Exclusion Manager
const KeyExclusionManager = require('./src/core/exclusions');
const exclusionManager = new KeyExclusionManager();
// Initialize Environment Source Manager (legacy, kept for migration only)
// Import sources are now managed by KeyVault
// Initialize legacy clients for backward compatibility
let geminiClient = null;
let openaiClient = null;
if (config.hasGeminiKeys()) {
const geminiKeyRotator = new KeyRotator(config.getGeminiApiKeys(), 'gemini');
geminiClient = new GeminiClient(geminiKeyRotator, config.getGeminiBaseUrl());
console.log('[INIT] Legacy Gemini client initialized');
} else if (config.hasAdminPassword()) {
console.log('[INIT] No legacy Gemini keys found - can be configured via admin panel');
}
if (config.hasOpenaiKeys()) {
const openaiKeyRotator = new KeyRotator(config.getOpenaiApiKeys(), 'openai');
openaiClient = new OpenAIClient(openaiKeyRotator, config.getOpenaiBaseUrl());
console.log('[INIT] Legacy OpenAI client initialized');
} else if (config.hasAdminPassword()) {
console.log('[INIT] No legacy OpenAI keys found - can be configured via admin panel');
}
const server = new ProxyServer(config, geminiClient, openaiClient);
server.exclusionManager = exclusionManager;
server.keyVault = vault;
server.settingsManager = settingsManager;
server.start();
process.on('SIGINT', () => {
console.log('\nShutting down server...');
server.stop();
vault.flushSync();
settingsManager.flushSync();
process.exit(0);
});
} catch (error) {
console.error('Failed to start server:', error.message);
process.exit(1);
}
}
if (require.main === module) {
main();
}
const TelegramBot = require('./src/core/telegramBot');
module.exports = { Config, KeyRotator, GeminiClient, OpenAIClient, ProxyServer, TelegramBot };