173 lines
4.5 KiB
TypeScript
173 lines
4.5 KiB
TypeScript
import { readFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import chokidar from 'chokidar';
|
|
import { EventEmitter } from 'events';
|
|
|
|
export interface Repository {
|
|
owner: string;
|
|
name: string;
|
|
token?: string;
|
|
}
|
|
|
|
export interface Config {
|
|
github: {
|
|
token: string;
|
|
repositories: Repository[];
|
|
};
|
|
server: {
|
|
port: number;
|
|
host: string;
|
|
};
|
|
cache?: {
|
|
timeoutSeconds?: number;
|
|
};
|
|
}
|
|
|
|
const defaultConfig: Config = {
|
|
github: {
|
|
token: process.env.GITHUB_TOKEN || '',
|
|
repositories: []
|
|
},
|
|
server: {
|
|
port: parseInt(process.env.PORT || '3001'),
|
|
host: process.env.HOST || '0.0.0.0'
|
|
},
|
|
cache: {
|
|
timeoutSeconds: 300
|
|
}
|
|
};
|
|
|
|
export function loadConfig(): Config {
|
|
const configPath = join(process.cwd(), 'config.json');
|
|
|
|
try {
|
|
const configFile = readFileSync(configPath, 'utf8');
|
|
const fileConfig = JSON.parse(configFile);
|
|
|
|
return {
|
|
github: {
|
|
token: fileConfig.github?.token || process.env.GITHUB_TOKEN || '',
|
|
repositories: fileConfig.github?.repositories || []
|
|
},
|
|
server: {
|
|
port: fileConfig.server?.port || parseInt(process.env.PORT || '3001'),
|
|
host: fileConfig.server?.host || process.env.HOST || '0.0.0.0'
|
|
},
|
|
cache: {
|
|
timeoutSeconds: fileConfig.cache?.timeoutSeconds || 300
|
|
}
|
|
};
|
|
} catch (error) {
|
|
console.log('Config file not found, using environment variables and defaults');
|
|
return defaultConfig;
|
|
}
|
|
}
|
|
|
|
// Legacy function for backward compatibility
|
|
export function createConfigWatcher(): ConfigWatcher {
|
|
return new ConfigWatcher();
|
|
}
|
|
|
|
export function validateConfig(config: Config): void {
|
|
if (!config.github.token) {
|
|
throw new Error('GitHub token is required. Set GITHUB_TOKEN environment variable or add it to config.json');
|
|
}
|
|
|
|
if (!config.github.repositories.length) {
|
|
throw new Error('At least one repository is required in config.json');
|
|
}
|
|
|
|
for (const repo of config.github.repositories) {
|
|
if (!repo.owner || !repo.name) {
|
|
throw new Error(`Invalid repository configuration: ${JSON.stringify(repo)}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class ConfigWatcher extends EventEmitter {
|
|
private config: Config;
|
|
private configPath: string;
|
|
private watcher?: chokidar.FSWatcher;
|
|
|
|
constructor() {
|
|
super();
|
|
this.configPath = join(process.cwd(), 'config.json');
|
|
this.config = this.loadConfigSync();
|
|
this.startWatching();
|
|
}
|
|
|
|
private loadConfigSync(): Config {
|
|
try {
|
|
const configFile = readFileSync(this.configPath, 'utf8');
|
|
const fileConfig = JSON.parse(configFile);
|
|
|
|
const config = {
|
|
github: {
|
|
token: fileConfig.github?.token || process.env.GITHUB_TOKEN || '',
|
|
repositories: fileConfig.github?.repositories || []
|
|
},
|
|
server: {
|
|
port: fileConfig.server?.port || parseInt(process.env.PORT || '3001'),
|
|
host: fileConfig.server?.host || process.env.HOST || '0.0.0.0'
|
|
},
|
|
cache: {
|
|
timeoutSeconds: fileConfig.cache?.timeoutSeconds || 300
|
|
}
|
|
};
|
|
|
|
validateConfig(config);
|
|
return config;
|
|
} catch (error) {
|
|
console.log('Config file not found or invalid, using environment variables and defaults');
|
|
const config = {
|
|
github: {
|
|
token: process.env.GITHUB_TOKEN || '',
|
|
repositories: []
|
|
},
|
|
server: {
|
|
port: parseInt(process.env.PORT || '3001'),
|
|
host: process.env.HOST || '0.0.0.0'
|
|
},
|
|
cache: {
|
|
timeoutSeconds: 300
|
|
}
|
|
};
|
|
return config;
|
|
}
|
|
}
|
|
|
|
private startWatching(): void {
|
|
this.watcher = chokidar.watch(this.configPath, {
|
|
ignored: /(^|[/\\])\../, // ignore dotfiles
|
|
persistent: true
|
|
});
|
|
|
|
this.watcher.on('change', () => {
|
|
console.log('📁 Config file changed, reloading...');
|
|
try {
|
|
const newConfig = this.loadConfigSync();
|
|
this.config = newConfig;
|
|
this.emit('configChanged', newConfig);
|
|
console.log('✅ Config reloaded successfully');
|
|
console.log(`📊 Now monitoring ${newConfig.github.repositories.length} repositories`);
|
|
} catch (error) {
|
|
console.error('❌ Failed to reload config:', error);
|
|
this.emit('configError', error);
|
|
}
|
|
});
|
|
|
|
this.watcher.on('error', (error) => {
|
|
console.error('❌ Config watcher error:', error);
|
|
});
|
|
}
|
|
|
|
public getConfig(): Config {
|
|
return this.config;
|
|
}
|
|
|
|
public close(): void {
|
|
if (this.watcher) {
|
|
this.watcher.close();
|
|
}
|
|
}
|
|
} |