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'; import { logger } from '../gitzone.logging.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())) { logger.log('error', 'Error: Docker is not installed. Please install Docker first.'); process.exit(1); } // Load or create configuration await this.config.loadOrCreate(); logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`); } /** * Start MongoDB service */ public async startMongoDB(): Promise { logger.log('note', '📦 MongoDB:'); 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': logger.log('ok', ' Already running ✓'); break; case 'stopped': if (await this.docker.start(containers.mongo)) { logger.log('ok', ' Started ✓'); } else { logger.log('error', ' Failed to start'); } break; case 'not_exists': logger.log('note', ' Creating container...'); 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) { logger.log('ok', ' Created and started ✓'); } else { logger.log('error', ' Failed to create container'); } break; } logger.log('info', ` Container: ${containers.mongo}`); logger.log('info', ` Port: ${config.MONGODB_PORT}`); logger.log('info', ` Connection: ${this.config.getMongoConnectionString()}`); // Show Compass connection string const networkIp = await helpers.getLocalNetworkIp(); const compassString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`; logger.log('ok', ` Compass: ${compassString}`); } /** * Start MinIO service */ public async startMinIO(): Promise { logger.log('note', '📦 S3/MinIO:'); 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': logger.log('ok', ' Already running ✓'); break; case 'stopped': if (await this.docker.start(containers.minio)) { logger.log('ok', ' Started ✓'); } else { logger.log('error', ' Failed to start'); } break; case 'not_exists': logger.log('note', ' Creating container...'); 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) { logger.log('ok', ' Created and started ✓'); // 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}` ); logger.log('ok', ` Bucket '${config.S3_BUCKET}' created ✓`); } else { logger.log('error', ' Failed to create container'); } break; } logger.log('info', ` Container: ${containers.minio}`); logger.log('info', ` Port: ${config.S3_PORT}`); logger.log('info', ` Bucket: ${config.S3_BUCKET}`); logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`); logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_USER}/***)`); } /** * Stop MongoDB service */ public async stopMongoDB(): Promise { logger.log('note', '📦 MongoDB:'); const containers = this.config.getContainerNames(); const status = await this.docker.getStatus(containers.mongo); if (status === 'running') { if (await this.docker.stop(containers.mongo)) { logger.log('ok', ' Stopped ✓'); } else { logger.log('error', ' Failed to stop'); } } else { logger.log('note', ' Not running'); } } /** * Stop MinIO service */ public async stopMinIO(): Promise { logger.log('note', '📦 S3/MinIO:'); const containers = this.config.getContainerNames(); const status = await this.docker.getStatus(containers.minio); if (status === 'running') { if (await this.docker.stop(containers.minio)) { logger.log('ok', ' Stopped ✓'); } else { logger.log('error', ' Failed to stop'); } } else { logger.log('note', ' Not running'); } } /** * Show service status */ public async showStatus(): Promise { helpers.printHeader('Service Status'); const config = this.config.getConfig(); const containers = this.config.getContainerNames(); logger.log('info', `Project: ${config.PROJECT_NAME}`); console.log(); // MongoDB status const mongoStatus = await this.docker.getStatus(containers.mongo); switch (mongoStatus) { case 'running': logger.log('ok', '📦 MongoDB: 🟢 Running'); logger.log('info', ` ├─ Container: ${containers.mongo}`); logger.log('info', ` ├─ Connection: ${this.config.getMongoConnectionString()}`); // Show Compass connection string const networkIp = await helpers.getLocalNetworkIp(); const compassString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`; logger.log('ok', ` └─ Compass: ${compassString}`); break; case 'stopped': logger.log('note', '📦 MongoDB: 🟡 Stopped'); logger.log('info', ` └─ Container: ${containers.mongo}`); break; case 'not_exists': logger.log('info', '📦 MongoDB: ⚪ Not installed'); break; } // MinIO status const minioStatus = await this.docker.getStatus(containers.minio); switch (minioStatus) { case 'running': logger.log('ok', '📦 S3/MinIO: 🟢 Running'); logger.log('info', ` ├─ Container: ${containers.minio}`); logger.log('info', ` ├─ API: http://${config.S3_HOST}:${config.S3_PORT}`); logger.log('info', ` ├─ Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`); logger.log('info', ` └─ Bucket: ${config.S3_BUCKET}`); break; case 'stopped': logger.log('note', '📦 S3/MinIO: 🟡 Stopped'); logger.log('info', ` └─ Container: ${containers.minio}`); break; case 'not_exists': logger.log('info', '📦 S3/MinIO: ⚪ Not installed'); break; } } /** * Show configuration */ public async showConfig(): Promise { helpers.printHeader('Current Configuration'); const config = this.config.getConfig(); logger.log('info', `Project: ${config.PROJECT_NAME}`); console.log(); logger.log('note', 'MongoDB:'); logger.log('info', ` Host: ${config.MONGODB_HOST}:${config.MONGODB_PORT}`); logger.log('info', ` Database: ${config.MONGODB_NAME}`); logger.log('info', ` User: ${config.MONGODB_USER}`); logger.log('info', ' Password: ***'); logger.log('info', ` Container: ${this.config.getContainerNames().mongo}`); logger.log('info', ` Data: ${this.config.getDataDirectories().mongo}`); logger.log('info', ` Connection: ${this.config.getMongoConnectionString()}`); console.log(); logger.log('note', 'S3/MinIO:'); logger.log('info', ` Host: ${config.S3_HOST}`); logger.log('info', ` API Port: ${config.S3_PORT}`); logger.log('info', ` Console Port: ${config.S3_CONSOLE_PORT}`); logger.log('info', ` User: ${config.S3_USER}`); logger.log('info', ' Password: ***'); logger.log('info', ` Bucket: ${config.S3_BUCKET}`); logger.log('info', ` Container: ${this.config.getContainerNames().minio}`); logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`); logger.log('info', ` API URL: http://${config.S3_HOST}:${config.S3_PORT}`); logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`); } /** * 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`; logger.log('info', 'MongoDB Compass is a GUI tool for MongoDB. To connect:'); console.log(); logger.log('info', '1. Download MongoDB Compass from:'); logger.log('info', ' https://www.mongodb.com/products/compass'); console.log(); logger.log('info', '2. Open Compass and paste this connection string:'); logger.log('ok', ` ${connectionString}`); console.log(); logger.log('note', 'Connection Details:'); logger.log('info', ` Network IP: ${networkIp}`); logger.log('info', ` Port: ${config.MONGODB_PORT}`); logger.log('info', ` Database: ${config.MONGODB_NAME}`); logger.log('info', ` Username: ${config.MONGODB_USER}`); logger.log('info', ` Auth Source: admin`); } /** * 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 { logger.log('note', 'MongoDB container is not running'); } 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 { logger.log('note', 'S3/MinIO container is not running'); } break; case 'all': case '': await this.showLogs('mongo', lines); console.log(); await this.showLogs('minio', lines); break; default: logger.log('note', 'Usage: gitzone services logs [mongo|s3|all] [lines]'); 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)) { logger.log('ok', ' MongoDB container removed ✓'); removed = true; } } if (await this.docker.exists(containers.minio)) { if (await this.docker.remove(containers.minio, true)) { logger.log('ok', ' S3/MinIO container removed ✓'); removed = true; } } if (!removed) { logger.log('note', ' No containers to remove'); } } /** * 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); logger.log('ok', ' MongoDB data removed ✓'); cleaned = true; } if (await plugins.smartfile.fs.fileExists(directories.minio)) { await plugins.smartfile.fs.remove(directories.minio); logger.log('ok', ' S3/MinIO data removed ✓'); cleaned = true; } if (!cleaned) { logger.log('note', ' No data to clean'); } } }