import * as plugins from './mod.plugins.js'; import * as helpers from './helpers.js'; import { ServiceConfiguration } from './classes.serviceconfiguration.js'; import { DockerContainer } from './classes.dockercontainer.js'; export class ServiceManager { private config: ServiceConfiguration; private docker: DockerContainer; constructor() { this.config = new ServiceConfiguration(); this.docker = new DockerContainer(); } /** * Initialize the service manager */ public async init(): Promise { // Check Docker availability if (!(await this.docker.checkDocker())) { helpers.printMessage('Error: Docker is not installed. Please install Docker first.', 'red'); process.exit(1); } // Load or create configuration await this.config.loadOrCreate(); helpers.printMessage(`📋 Project: ${this.config.getConfig().PROJECT_NAME}`, 'magenta'); } /** * Start MongoDB service */ public async startMongoDB(): Promise { helpers.printMessage('📦 MongoDB:', 'yellow'); const config = this.config.getConfig(); const containers = this.config.getContainerNames(); const directories = this.config.getDataDirectories(); // Ensure data directory exists await plugins.smartfile.fs.ensureDir(directories.mongo); const status = await this.docker.getStatus(containers.mongo); switch (status) { case 'running': helpers.printMessage(' Already running ✓', 'green'); break; case 'stopped': if (await this.docker.start(containers.mongo)) { helpers.printMessage(' Started ✓', 'green'); } else { helpers.printMessage(' Failed to start', 'red'); } break; case 'not_exists': helpers.printMessage(' Creating container...', 'yellow'); const success = await this.docker.run({ name: containers.mongo, image: 'mongo:7.0', ports: { [`0.0.0.0:${config.MONGODB_PORT}`]: '27017' }, volumes: { [directories.mongo]: '/data/db' }, environment: { MONGO_INITDB_ROOT_USERNAME: config.MONGODB_USER, MONGO_INITDB_ROOT_PASSWORD: config.MONGODB_PASS, MONGO_INITDB_DATABASE: config.MONGODB_NAME }, restart: 'unless-stopped' }); if (success) { helpers.printMessage(' Created and started ✓', 'green'); } else { helpers.printMessage(' Failed to create container', 'red'); } break; } helpers.printMessage(` Container: ${containers.mongo}`, 'cyan'); helpers.printMessage(` Port: ${config.MONGODB_PORT}`, 'cyan'); helpers.printMessage(` Connection: ${this.config.getMongoConnectionString()}`, 'blue'); } /** * Start MinIO service */ public async startMinIO(): Promise { helpers.printMessage('📦 S3/MinIO:', 'yellow'); const config = this.config.getConfig(); const containers = this.config.getContainerNames(); const directories = this.config.getDataDirectories(); // Ensure data directory exists await plugins.smartfile.fs.ensureDir(directories.minio); const status = await this.docker.getStatus(containers.minio); switch (status) { case 'running': helpers.printMessage(' Already running ✓', 'green'); break; case 'stopped': if (await this.docker.start(containers.minio)) { helpers.printMessage(' Started ✓', 'green'); } else { helpers.printMessage(' Failed to start', 'red'); } break; case 'not_exists': helpers.printMessage(' Creating container...', 'yellow'); const success = await this.docker.run({ name: containers.minio, image: 'minio/minio', ports: { [config.S3_PORT]: '9000', [config.S3_CONSOLE_PORT]: '9001' }, volumes: { [directories.minio]: '/data' }, environment: { MINIO_ROOT_USER: config.S3_USER, MINIO_ROOT_PASSWORD: config.S3_PASS }, restart: 'unless-stopped', command: 'server /data --console-address ":9001"' }); if (success) { helpers.printMessage(' Created and started ✓', 'green'); // Wait for MinIO to be ready await plugins.smartdelay.delayFor(3000); // Create default bucket await this.docker.exec( containers.minio, `mc alias set local http://localhost:9000 ${config.S3_USER} ${config.S3_PASS}` ); await this.docker.exec( containers.minio, `mc mb local/${config.S3_BUCKET}` ); helpers.printMessage(` Bucket '${config.S3_BUCKET}' created ✓`, 'green'); } else { helpers.printMessage(' Failed to create container', 'red'); } break; } helpers.printMessage(` Container: ${containers.minio}`, 'cyan'); helpers.printMessage(` Port: ${config.S3_PORT}`, 'cyan'); helpers.printMessage(` Bucket: ${config.S3_BUCKET}`, 'cyan'); helpers.printMessage(` API: http://${config.S3_HOST}:${config.S3_PORT}`, 'blue'); helpers.printMessage(` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_USER}/***)`, 'blue'); } /** * Stop MongoDB service */ public async stopMongoDB(): Promise { helpers.printMessage('📦 MongoDB:', 'yellow'); const containers = this.config.getContainerNames(); const status = await this.docker.getStatus(containers.mongo); if (status === 'running') { if (await this.docker.stop(containers.mongo)) { helpers.printMessage(' Stopped ✓', 'green'); } else { helpers.printMessage(' Failed to stop', 'red'); } } else { helpers.printMessage(' Not running', 'yellow'); } } /** * Stop MinIO service */ public async stopMinIO(): Promise { helpers.printMessage('📦 S3/MinIO:', 'yellow'); const containers = this.config.getContainerNames(); const status = await this.docker.getStatus(containers.minio); if (status === 'running') { if (await this.docker.stop(containers.minio)) { helpers.printMessage(' Stopped ✓', 'green'); } else { helpers.printMessage(' Failed to stop', 'red'); } } else { helpers.printMessage(' Not running', 'yellow'); } } /** * Show service status */ public async showStatus(): Promise { helpers.printHeader('Service Status'); const config = this.config.getConfig(); const containers = this.config.getContainerNames(); helpers.printMessage(`Project: ${config.PROJECT_NAME}`, 'magenta'); console.log(); // MongoDB status const mongoStatus = await this.docker.getStatus(containers.mongo); switch (mongoStatus) { case 'running': helpers.printMessage('📦 MongoDB: 🟢 Running', 'green'); helpers.printMessage(` ├─ Container: ${containers.mongo}`, 'cyan'); helpers.printMessage(` └─ ${this.config.getMongoConnectionString()}`, 'cyan'); break; case 'stopped': helpers.printMessage('📦 MongoDB: 🟡 Stopped', 'yellow'); helpers.printMessage(` └─ Container: ${containers.mongo}`, 'cyan'); break; case 'not_exists': helpers.printMessage('📦 MongoDB: ⚪ Not installed', 'magenta'); break; } // MinIO status const minioStatus = await this.docker.getStatus(containers.minio); switch (minioStatus) { case 'running': helpers.printMessage('📦 S3/MinIO: 🟢 Running', 'green'); helpers.printMessage(` ├─ Container: ${containers.minio}`, 'cyan'); helpers.printMessage(` ├─ API: http://${config.S3_HOST}:${config.S3_PORT}`, 'cyan'); helpers.printMessage(` ├─ Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`, 'cyan'); helpers.printMessage(` └─ Bucket: ${config.S3_BUCKET}`, 'cyan'); break; case 'stopped': helpers.printMessage('📦 S3/MinIO: 🟡 Stopped', 'yellow'); helpers.printMessage(` └─ Container: ${containers.minio}`, 'cyan'); break; case 'not_exists': helpers.printMessage('📦 S3/MinIO: ⚪ Not installed', 'magenta'); break; } } /** * Show configuration */ public async showConfig(): Promise { helpers.printHeader('Current Configuration'); const config = this.config.getConfig(); helpers.printMessage(`Project: ${config.PROJECT_NAME}`, 'magenta'); console.log(); helpers.printMessage('MongoDB:', 'yellow'); helpers.printMessage(` Host: ${config.MONGODB_HOST}:${config.MONGODB_PORT}`, undefined); helpers.printMessage(` Database: ${config.MONGODB_NAME}`, undefined); helpers.printMessage(` User: ${config.MONGODB_USER}`, undefined); helpers.printMessage(' Password: ***', undefined); helpers.printMessage(` Container: ${this.config.getContainerNames().mongo}`, undefined); helpers.printMessage(` Data: ${this.config.getDataDirectories().mongo}`, undefined); helpers.printMessage(` Connection: ${this.config.getMongoConnectionString()}`, 'blue'); console.log(); helpers.printMessage('S3/MinIO:', 'yellow'); helpers.printMessage(` Host: ${config.S3_HOST}`, undefined); helpers.printMessage(` API Port: ${config.S3_PORT}`, undefined); helpers.printMessage(` Console Port: ${config.S3_CONSOLE_PORT}`, undefined); helpers.printMessage(` User: ${config.S3_USER}`, undefined); helpers.printMessage(' Password: ***', undefined); helpers.printMessage(` Bucket: ${config.S3_BUCKET}`, undefined); helpers.printMessage(` Container: ${this.config.getContainerNames().minio}`, undefined); helpers.printMessage(` Data: ${this.config.getDataDirectories().minio}`, undefined); helpers.printMessage(` API URL: http://${config.S3_HOST}:${config.S3_PORT}`, 'blue'); helpers.printMessage(` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`, 'blue'); } /** * Show MongoDB Compass connection string */ public async showCompassConnection(): Promise { helpers.printHeader('MongoDB Compass Connection'); const config = this.config.getConfig(); const networkIp = await helpers.getLocalNetworkIp(); const connectionString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`; helpers.printMessage('MongoDB Compass is a GUI tool for MongoDB. To connect:', 'cyan'); console.log(); helpers.printMessage('1. Download MongoDB Compass from:', undefined); helpers.printMessage(' https://www.mongodb.com/products/compass', 'blue'); console.log(); helpers.printMessage('2. Open Compass and paste this connection string:', undefined); helpers.printMessage(` ${connectionString}`, 'green'); console.log(); helpers.printMessage('Connection Details:', 'yellow'); helpers.printMessage(` Network IP: ${networkIp}`, undefined); helpers.printMessage(` Port: ${config.MONGODB_PORT}`, undefined); helpers.printMessage(` Database: ${config.MONGODB_NAME}`, undefined); helpers.printMessage(` Username: ${config.MONGODB_USER}`, undefined); helpers.printMessage(` Auth Source: admin`, undefined); } /** * Show logs for a service */ public async showLogs(service: string, lines: number = 20): Promise { const containers = this.config.getContainerNames(); switch (service) { case 'mongo': case 'mongodb': if (await this.docker.isRunning(containers.mongo)) { helpers.printHeader(`MongoDB Logs (last ${lines} lines)`); const logs = await this.docker.logs(containers.mongo, lines); console.log(logs); } else { helpers.printMessage('MongoDB container is not running', 'yellow'); } break; case 'minio': case 's3': if (await this.docker.isRunning(containers.minio)) { helpers.printHeader(`S3/MinIO Logs (last ${lines} lines)`); const logs = await this.docker.logs(containers.minio, lines); console.log(logs); } else { helpers.printMessage('S3/MinIO container is not running', 'yellow'); } break; case 'all': case '': await this.showLogs('mongo', lines); console.log(); await this.showLogs('minio', lines); break; default: helpers.printMessage('Usage: gitzone services logs [mongo|s3|all] [lines]', 'yellow'); break; } } /** * Remove containers */ public async removeContainers(): Promise { const containers = this.config.getContainerNames(); let removed = false; if (await this.docker.exists(containers.mongo)) { if (await this.docker.remove(containers.mongo, true)) { helpers.printMessage(' MongoDB container removed ✓', 'green'); removed = true; } } if (await this.docker.exists(containers.minio)) { if (await this.docker.remove(containers.minio, true)) { helpers.printMessage(' S3/MinIO container removed ✓', 'green'); removed = true; } } if (!removed) { helpers.printMessage(' No containers to remove', 'yellow'); } } /** * Clean data directories */ public async cleanData(): Promise { const directories = this.config.getDataDirectories(); let cleaned = false; if (await plugins.smartfile.fs.fileExists(directories.mongo)) { await plugins.smartfile.fs.remove(directories.mongo); helpers.printMessage(' MongoDB data removed ✓', 'green'); cleaned = true; } if (await plugins.smartfile.fs.fileExists(directories.minio)) { await plugins.smartfile.fs.remove(directories.minio); helpers.printMessage(' S3/MinIO data removed ✓', 'green'); cleaned = true; } if (!cleaned) { helpers.printMessage(' No data to clean', 'yellow'); } } }