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}`);
|
|
}
|
|
} |