432 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			432 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as plugins from './mod.plugins.js';
 | 
						|
import * as helpers from './helpers.js';
 | 
						|
import { logger } from '../gitzone.logging.js';
 | 
						|
import { DockerContainer } from './classes.dockercontainer.js';
 | 
						|
 | 
						|
export interface IServiceConfig {
 | 
						|
  PROJECT_NAME: string;
 | 
						|
  MONGODB_HOST: string;
 | 
						|
  MONGODB_NAME: string;
 | 
						|
  MONGODB_PORT: string;
 | 
						|
  MONGODB_USER: string;
 | 
						|
  MONGODB_PASS: string;
 | 
						|
  MONGODB_URL: string;
 | 
						|
  S3_HOST: string;
 | 
						|
  S3_PORT: string;
 | 
						|
  S3_CONSOLE_PORT: string;
 | 
						|
  S3_ACCESSKEY: string;
 | 
						|
  S3_SECRETKEY: string;
 | 
						|
  S3_BUCKET: string;
 | 
						|
  S3_ENDPOINT: string;
 | 
						|
  S3_USESSL: boolean;
 | 
						|
}
 | 
						|
 | 
						|
export class ServiceConfiguration {
 | 
						|
  private configPath: string;
 | 
						|
  private config: IServiceConfig;
 | 
						|
  private docker: DockerContainer;
 | 
						|
  
 | 
						|
  constructor() {
 | 
						|
    this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json');
 | 
						|
    this.docker = new DockerContainer();
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Load or create the configuration
 | 
						|
   */
 | 
						|
  public async loadOrCreate(): Promise<IServiceConfig> {
 | 
						|
    await this.ensureNogitDirectory();
 | 
						|
    
 | 
						|
    if (await this.configExists()) {
 | 
						|
      await this.loadConfig();
 | 
						|
      await this.updateMissingFields();
 | 
						|
    } else {
 | 
						|
      await this.createDefaultConfig();
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Sync ports from existing Docker containers if they exist
 | 
						|
    await this.syncPortsFromDocker();
 | 
						|
    
 | 
						|
    return this.config;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Get the current configuration
 | 
						|
   */
 | 
						|
  public getConfig(): IServiceConfig {
 | 
						|
    return this.config;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Save the configuration to file
 | 
						|
   */
 | 
						|
  public async saveConfig(): Promise<void> {
 | 
						|
    await plugins.smartfile.memory.toFs(
 | 
						|
      JSON.stringify(this.config, null, 2),
 | 
						|
      this.configPath
 | 
						|
    );
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Ensure .nogit directory exists
 | 
						|
   */
 | 
						|
  private async ensureNogitDirectory(): Promise<void> {
 | 
						|
    const nogitPath = plugins.path.join(process.cwd(), '.nogit');
 | 
						|
    await plugins.smartfile.fs.ensureDir(nogitPath);
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Check if configuration file exists
 | 
						|
   */
 | 
						|
  private async configExists(): Promise<boolean> {
 | 
						|
    return plugins.smartfile.fs.fileExists(this.configPath);
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Load configuration from file
 | 
						|
   */
 | 
						|
  private async loadConfig(): Promise<void> {
 | 
						|
    const configContent = plugins.smartfile.fs.toStringSync(this.configPath);
 | 
						|
    this.config = JSON.parse(configContent);
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Create default configuration
 | 
						|
   */
 | 
						|
  private async createDefaultConfig(): Promise<void> {
 | 
						|
    const projectName = helpers.getProjectName();
 | 
						|
    const mongoPort = await helpers.getRandomAvailablePort();
 | 
						|
    const s3Port = await helpers.getRandomAvailablePort();
 | 
						|
    let s3ConsolePort = s3Port + 1;
 | 
						|
    
 | 
						|
    // Ensure console port is also available
 | 
						|
    while (!(await helpers.isPortAvailable(s3ConsolePort))) {
 | 
						|
      s3ConsolePort++;
 | 
						|
    }
 | 
						|
    
 | 
						|
    const mongoUser = 'defaultadmin';
 | 
						|
    const mongoPass = 'defaultpass';
 | 
						|
    const mongoHost = 'localhost';
 | 
						|
    const mongoName = projectName;
 | 
						|
    const mongoPortStr = mongoPort.toString();
 | 
						|
    const s3Host = 'localhost';
 | 
						|
    const s3PortStr = s3Port.toString();
 | 
						|
    
 | 
						|
    this.config = {
 | 
						|
      PROJECT_NAME: projectName,
 | 
						|
      MONGODB_HOST: mongoHost,
 | 
						|
      MONGODB_NAME: mongoName,
 | 
						|
      MONGODB_PORT: mongoPortStr,
 | 
						|
      MONGODB_USER: mongoUser,
 | 
						|
      MONGODB_PASS: mongoPass,
 | 
						|
      MONGODB_URL: `mongodb://${mongoUser}:${mongoPass}@${mongoHost}:${mongoPortStr}/${mongoName}?authSource=admin`,
 | 
						|
      S3_HOST: s3Host,
 | 
						|
      S3_PORT: s3PortStr,
 | 
						|
      S3_CONSOLE_PORT: s3ConsolePort.toString(),
 | 
						|
      S3_ACCESSKEY: 'defaultadmin',
 | 
						|
      S3_SECRETKEY: 'defaultpass',
 | 
						|
      S3_BUCKET: `${projectName}-documents`,
 | 
						|
      S3_ENDPOINT: s3Host,
 | 
						|
      S3_USESSL: false
 | 
						|
    };
 | 
						|
    
 | 
						|
    await this.saveConfig();
 | 
						|
    
 | 
						|
    logger.log('ok', '✅ Created .nogit/env.json with project defaults');
 | 
						|
    logger.log('info', `📍 MongoDB port: ${mongoPort}`);
 | 
						|
    logger.log('info', `📍 S3 API port: ${s3Port}`);
 | 
						|
    logger.log('info', `📍 S3 Console port: ${s3ConsolePort}`);
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Update missing fields in existing configuration
 | 
						|
   */
 | 
						|
  private async updateMissingFields(): Promise<void> {
 | 
						|
    const projectName = helpers.getProjectName();
 | 
						|
    let updated = false;
 | 
						|
    const fieldsAdded: string[] = [];
 | 
						|
    
 | 
						|
    // Check and add missing fields
 | 
						|
    if (!this.config.PROJECT_NAME) {
 | 
						|
      this.config.PROJECT_NAME = projectName;
 | 
						|
      fieldsAdded.push('PROJECT_NAME');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.MONGODB_HOST) {
 | 
						|
      this.config.MONGODB_HOST = 'localhost';
 | 
						|
      fieldsAdded.push('MONGODB_HOST');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.MONGODB_NAME) {
 | 
						|
      this.config.MONGODB_NAME = projectName;
 | 
						|
      fieldsAdded.push('MONGODB_NAME');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.MONGODB_PORT) {
 | 
						|
      const port = await helpers.getRandomAvailablePort();
 | 
						|
      this.config.MONGODB_PORT = port.toString();
 | 
						|
      fieldsAdded.push(`MONGODB_PORT(${port})`);
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.MONGODB_USER) {
 | 
						|
      this.config.MONGODB_USER = 'defaultadmin';
 | 
						|
      fieldsAdded.push('MONGODB_USER');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.MONGODB_PASS) {
 | 
						|
      this.config.MONGODB_PASS = 'defaultpass';
 | 
						|
      fieldsAdded.push('MONGODB_PASS');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Always update MONGODB_URL based on current settings
 | 
						|
    const oldUrl = this.config.MONGODB_URL;
 | 
						|
    this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
 | 
						|
    if (oldUrl !== this.config.MONGODB_URL) {
 | 
						|
      fieldsAdded.push('MONGODB_URL');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_HOST) {
 | 
						|
      this.config.S3_HOST = 'localhost';
 | 
						|
      fieldsAdded.push('S3_HOST');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_PORT) {
 | 
						|
      const port = await helpers.getRandomAvailablePort();
 | 
						|
      this.config.S3_PORT = port.toString();
 | 
						|
      fieldsAdded.push(`S3_PORT(${port})`);
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_CONSOLE_PORT) {
 | 
						|
      const s3Port = parseInt(this.config.S3_PORT);
 | 
						|
      let consolePort = s3Port + 1;
 | 
						|
      
 | 
						|
      while (!(await helpers.isPortAvailable(consolePort))) {
 | 
						|
        consolePort++;
 | 
						|
      }
 | 
						|
      
 | 
						|
      this.config.S3_CONSOLE_PORT = consolePort.toString();
 | 
						|
      fieldsAdded.push(`S3_CONSOLE_PORT(${consolePort})`);
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_ACCESSKEY) {
 | 
						|
      this.config.S3_ACCESSKEY = 'defaultadmin';
 | 
						|
      fieldsAdded.push('S3_ACCESSKEY');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_SECRETKEY) {
 | 
						|
      this.config.S3_SECRETKEY = 'defaultpass';
 | 
						|
      fieldsAdded.push('S3_SECRETKEY');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_BUCKET) {
 | 
						|
      this.config.S3_BUCKET = `${projectName}-documents`;
 | 
						|
      fieldsAdded.push('S3_BUCKET');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!this.config.S3_USESSL) {
 | 
						|
      this.config.S3_USESSL = false;
 | 
						|
      fieldsAdded.push('S3_USESSL');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Always update S3_ENDPOINT based on current settings
 | 
						|
    const oldEndpoint = this.config.S3_ENDPOINT;
 | 
						|
    this.config.S3_ENDPOINT = this.config.S3_HOST;
 | 
						|
    if (oldEndpoint !== this.config.S3_ENDPOINT) {
 | 
						|
      fieldsAdded.push('S3_ENDPOINT');
 | 
						|
      updated = true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (updated) {
 | 
						|
      await this.saveConfig();
 | 
						|
      logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`);
 | 
						|
    } else {
 | 
						|
      logger.log('ok', '✅ Configuration complete');
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Get MongoDB connection string
 | 
						|
   */
 | 
						|
  public getMongoConnectionString(useNetworkIp: boolean = false): string {
 | 
						|
    const host = useNetworkIp ? '${networkIp}' : this.config.MONGODB_HOST;
 | 
						|
    return `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${host}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Get container names
 | 
						|
   */
 | 
						|
  public getContainerNames() {
 | 
						|
    return {
 | 
						|
      mongo: `${this.config.PROJECT_NAME}-mongodb`,
 | 
						|
      minio: `${this.config.PROJECT_NAME}-minio`
 | 
						|
    };
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Get data directories
 | 
						|
   */
 | 
						|
  public getDataDirectories() {
 | 
						|
    return {
 | 
						|
      mongo: plugins.path.join(process.cwd(), '.nogit', 'mongodata'),
 | 
						|
      minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata')
 | 
						|
    };
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Sync port configuration from existing Docker containers
 | 
						|
   */
 | 
						|
  private async syncPortsFromDocker(): Promise<void> {
 | 
						|
    const containers = this.getContainerNames();
 | 
						|
    let updated = false;
 | 
						|
    
 | 
						|
    // Check MongoDB container
 | 
						|
    const mongoStatus = await this.docker.getStatus(containers.mongo);
 | 
						|
    if (mongoStatus !== 'not_exists') {
 | 
						|
      const portMappings = await this.docker.getPortMappings(containers.mongo);
 | 
						|
      if (portMappings && portMappings['27017']) {
 | 
						|
        const dockerPort = portMappings['27017'];
 | 
						|
        if (this.config.MONGODB_PORT !== dockerPort) {
 | 
						|
          logger.log('note', `📍 Syncing MongoDB port from Docker: ${dockerPort}`);
 | 
						|
          this.config.MONGODB_PORT = dockerPort;
 | 
						|
          updated = true;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Check MinIO container
 | 
						|
    const minioStatus = await this.docker.getStatus(containers.minio);
 | 
						|
    if (minioStatus !== 'not_exists') {
 | 
						|
      const portMappings = await this.docker.getPortMappings(containers.minio);
 | 
						|
      if (portMappings) {
 | 
						|
        if (portMappings['9000']) {
 | 
						|
          const dockerPort = portMappings['9000'];
 | 
						|
          if (this.config.S3_PORT !== dockerPort) {
 | 
						|
            logger.log('note', `📍 Syncing S3 API port from Docker: ${dockerPort}`);
 | 
						|
            this.config.S3_PORT = dockerPort;
 | 
						|
            updated = true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (portMappings['9001']) {
 | 
						|
          const dockerPort = portMappings['9001'];
 | 
						|
          if (this.config.S3_CONSOLE_PORT !== dockerPort) {
 | 
						|
            logger.log('note', `📍 Syncing S3 Console port from Docker: ${dockerPort}`);
 | 
						|
            this.config.S3_CONSOLE_PORT = dockerPort;
 | 
						|
            updated = true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (updated) {
 | 
						|
      // Update derived fields
 | 
						|
      this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
 | 
						|
      this.config.S3_ENDPOINT = this.config.S3_HOST;
 | 
						|
      
 | 
						|
      await this.saveConfig();
 | 
						|
      logger.log('ok', '✅ Configuration synced with Docker containers');
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Validate and update ports if they're not available
 | 
						|
   */
 | 
						|
  public async validateAndUpdatePorts(): Promise<boolean> {
 | 
						|
    let updated = false;
 | 
						|
    const containers = this.getContainerNames();
 | 
						|
    
 | 
						|
    // Check if containers exist - if they do, ports are fine
 | 
						|
    const mongoExists = await this.docker.exists(containers.mongo);
 | 
						|
    const minioExists = await this.docker.exists(containers.minio);
 | 
						|
    
 | 
						|
    // Only check port availability if containers don't exist
 | 
						|
    if (!mongoExists) {
 | 
						|
      const mongoPort = parseInt(this.config.MONGODB_PORT);
 | 
						|
      if (!(await helpers.isPortAvailable(mongoPort))) {
 | 
						|
        logger.log('note', `⚠️  MongoDB port ${mongoPort} is in use, finding new port...`);
 | 
						|
        const newPort = await helpers.getRandomAvailablePort();
 | 
						|
        this.config.MONGODB_PORT = newPort.toString();
 | 
						|
        logger.log('ok', `✅ New MongoDB port: ${newPort}`);
 | 
						|
        updated = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (!minioExists) {
 | 
						|
      const s3Port = parseInt(this.config.S3_PORT);
 | 
						|
      const s3ConsolePort = parseInt(this.config.S3_CONSOLE_PORT);
 | 
						|
      
 | 
						|
      if (!(await helpers.isPortAvailable(s3Port))) {
 | 
						|
        logger.log('note', `⚠️  S3 API port ${s3Port} is in use, finding new port...`);
 | 
						|
        const newPort = await helpers.getRandomAvailablePort();
 | 
						|
        this.config.S3_PORT = newPort.toString();
 | 
						|
        logger.log('ok', `✅ New S3 API port: ${newPort}`);
 | 
						|
        updated = true;
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (!(await helpers.isPortAvailable(s3ConsolePort))) {
 | 
						|
        logger.log('note', `⚠️  S3 Console port ${s3ConsolePort} is in use, finding new port...`);
 | 
						|
        let newPort = parseInt(this.config.S3_PORT) + 1;
 | 
						|
        while (!(await helpers.isPortAvailable(newPort))) {
 | 
						|
          newPort++;
 | 
						|
        }
 | 
						|
        this.config.S3_CONSOLE_PORT = newPort.toString();
 | 
						|
        logger.log('ok', `✅ New S3 Console port: ${newPort}`);
 | 
						|
        updated = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (updated) {
 | 
						|
      // Update derived fields
 | 
						|
      this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
 | 
						|
      this.config.S3_ENDPOINT = this.config.S3_HOST;
 | 
						|
      
 | 
						|
      await this.saveConfig();
 | 
						|
    }
 | 
						|
    
 | 
						|
    return updated;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /**
 | 
						|
   * Force reconfigure all ports with new available ones
 | 
						|
   */
 | 
						|
  public async reconfigurePorts(): Promise<void> {
 | 
						|
    logger.log('note', '🔄 Finding new available ports...');
 | 
						|
    
 | 
						|
    const mongoPort = await helpers.getRandomAvailablePort();
 | 
						|
    const s3Port = await helpers.getRandomAvailablePort();
 | 
						|
    let s3ConsolePort = s3Port + 1;
 | 
						|
    
 | 
						|
    // Ensure console port is also available
 | 
						|
    while (!(await helpers.isPortAvailable(s3ConsolePort))) {
 | 
						|
      s3ConsolePort++;
 | 
						|
    }
 | 
						|
    
 | 
						|
    this.config.MONGODB_PORT = mongoPort.toString();
 | 
						|
    this.config.S3_PORT = s3Port.toString();
 | 
						|
    this.config.S3_CONSOLE_PORT = s3ConsolePort.toString();
 | 
						|
    
 | 
						|
    // Update derived fields
 | 
						|
    this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
 | 
						|
    this.config.S3_ENDPOINT = this.config.S3_HOST;
 | 
						|
    
 | 
						|
    await this.saveConfig();
 | 
						|
    
 | 
						|
    logger.log('ok', '✅ New port configuration:');
 | 
						|
    logger.log('info', `  📍 MongoDB: ${mongoPort}`);
 | 
						|
    logger.log('info', `  📍 S3 API: ${s3Port}`);
 | 
						|
    logger.log('info', `  📍 S3 Console: ${s3ConsolePort}`);
 | 
						|
  }
 | 
						|
} |