import * as plugins from '../plugins.js'; import { DockerContainer } from './classes.dockercontainer.js'; import { logger } from '../gitzone.logging.js'; export interface IRegisteredProject { projectPath: string; projectName: string; containers: { mongo?: string; minio?: string; elasticsearch?: string; }; ports: { mongo?: number; s3?: number; s3Console?: number; elasticsearch?: number; }; enabledServices: string[]; lastActive: number; } export interface IGlobalRegistryData { projects: { [projectPath: string]: IRegisteredProject }; } export class GlobalRegistry { private static instance: GlobalRegistry | null = null; private kvStore: plugins.npmextra.KeyValueStore; private docker: DockerContainer; private constructor() { this.kvStore = new plugins.npmextra.KeyValueStore({ typeArg: 'userHomeDir', identityArg: 'gitzone-services', }); this.docker = new DockerContainer(); } /** * Get the singleton instance */ public static getInstance(): GlobalRegistry { if (!GlobalRegistry.instance) { GlobalRegistry.instance = new GlobalRegistry(); } return GlobalRegistry.instance; } /** * Register or update a project in the global registry */ public async registerProject(data: Omit): Promise { const allData = await this.kvStore.readAll(); const projects = allData.projects || {}; projects[data.projectPath] = { ...data, lastActive: Date.now(), }; await this.kvStore.writeKey('projects', projects); } /** * Remove a project from the registry */ public async unregisterProject(projectPath: string): Promise { const allData = await this.kvStore.readAll(); const projects = allData.projects || {}; if (projects[projectPath]) { delete projects[projectPath]; await this.kvStore.writeKey('projects', projects); } } /** * Update the lastActive timestamp for a project */ public async touchProject(projectPath: string): Promise { const allData = await this.kvStore.readAll(); const projects = allData.projects || {}; if (projects[projectPath]) { projects[projectPath].lastActive = Date.now(); await this.kvStore.writeKey('projects', projects); } } /** * Get all registered projects */ public async getAllProjects(): Promise<{ [path: string]: IRegisteredProject }> { const allData = await this.kvStore.readAll(); return allData.projects || {}; } /** * Check if a project is registered */ public async isRegistered(projectPath: string): Promise { const projects = await this.getAllProjects(); return !!projects[projectPath]; } /** * Get status of all containers across all registered projects */ public async getGlobalStatus(): Promise< Array<{ projectPath: string; projectName: string; containers: Array<{ name: string; status: string }>; lastActive: number; }> > { const projects = await this.getAllProjects(); const result: Array<{ projectPath: string; projectName: string; containers: Array<{ name: string; status: string }>; lastActive: number; }> = []; for (const [path, project] of Object.entries(projects)) { const containerStatuses: Array<{ name: string; status: string }> = []; for (const containerName of Object.values(project.containers)) { if (containerName) { const status = await this.docker.getStatus(containerName); containerStatuses.push({ name: containerName, status }); } } result.push({ projectPath: path, projectName: project.projectName, containers: containerStatuses, lastActive: project.lastActive, }); } return result; } /** * Stop all containers across all registered projects */ public async stopAll(): Promise<{ stopped: string[]; failed: string[] }> { const projects = await this.getAllProjects(); const stopped: string[] = []; const failed: string[] = []; for (const project of Object.values(projects)) { for (const containerName of Object.values(project.containers)) { if (containerName) { const status = await this.docker.getStatus(containerName); if (status === 'running') { if (await this.docker.stop(containerName)) { stopped.push(containerName); } else { failed.push(containerName); } } } } } return { stopped, failed }; } /** * Remove stale registry entries (projects that no longer exist on disk) */ public async cleanup(): Promise { const projects = await this.getAllProjects(); const removed: string[] = []; for (const projectPath of Object.keys(projects)) { const exists = await plugins.smartfs.directory(projectPath).exists(); if (!exists) { await this.unregisterProject(projectPath); removed.push(projectPath); } } return removed; } }