191 lines
5.1 KiB
TypeScript
191 lines
5.1 KiB
TypeScript
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<IGlobalRegistryData>;
|
|
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<IRegisteredProject, 'lastActive'>): Promise<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<boolean> {
|
|
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<string[]> {
|
|
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;
|
|
}
|
|
}
|