Philipp Kunz 7b81186bb3 feat(performance): Add async utility functions and filesystem utilities
- Implemented async utilities including delay, retryWithBackoff, withTimeout, parallelLimit, debounceAsync, AsyncMutex, and CircuitBreaker.
- Created tests for async utilities to ensure functionality and reliability.
- Developed AsyncFileSystem class with methods for file and directory operations, including ensureDir, readFile, writeFile, remove, and more.
- Added tests for filesystem utilities to validate file operations and error handling.
2025-05-31 17:45:40 +00:00

92 lines
2.6 KiB
TypeScript

import * as plugins from '../../plugins.js';
import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
import type { ICertificateData } from './certificate-manager.js';
export class CertStore {
constructor(private certDir: string) {}
public async initialize(): Promise<void> {
await AsyncFileSystem.ensureDir(this.certDir);
}
public async getCertificate(routeName: string): Promise<ICertificateData | null> {
const certPath = this.getCertPath(routeName);
const metaPath = `${certPath}/meta.json`;
if (!await AsyncFileSystem.exists(metaPath)) {
return null;
}
try {
const meta = await AsyncFileSystem.readJSON(metaPath);
const [cert, key] = await Promise.all([
AsyncFileSystem.readFile(`${certPath}/cert.pem`),
AsyncFileSystem.readFile(`${certPath}/key.pem`)
]);
let ca: string | undefined;
const caPath = `${certPath}/ca.pem`;
if (await AsyncFileSystem.exists(caPath)) {
ca = await AsyncFileSystem.readFile(caPath);
}
return {
cert,
key,
ca,
expiryDate: new Date(meta.expiryDate),
issueDate: new Date(meta.issueDate)
};
} catch (error) {
console.error(`Failed to load certificate for ${routeName}: ${error}`);
return null;
}
}
public async saveCertificate(
routeName: string,
certData: ICertificateData
): Promise<void> {
const certPath = this.getCertPath(routeName);
await AsyncFileSystem.ensureDir(certPath);
// Save certificate files in parallel
const savePromises = [
AsyncFileSystem.writeFile(`${certPath}/cert.pem`, certData.cert),
AsyncFileSystem.writeFile(`${certPath}/key.pem`, certData.key)
];
if (certData.ca) {
savePromises.push(
AsyncFileSystem.writeFile(`${certPath}/ca.pem`, certData.ca)
);
}
// Save metadata
const meta = {
expiryDate: certData.expiryDate.toISOString(),
issueDate: certData.issueDate.toISOString(),
savedAt: new Date().toISOString()
};
savePromises.push(
AsyncFileSystem.writeJSON(`${certPath}/meta.json`, meta)
);
await Promise.all(savePromises);
}
public async deleteCertificate(routeName: string): Promise<void> {
const certPath = this.getCertPath(routeName);
if (await AsyncFileSystem.isDirectory(certPath)) {
await AsyncFileSystem.removeDir(certPath);
}
}
private getCertPath(routeName: string): string {
// Sanitize route name for filesystem
const safeName = routeName.replace(/[^a-zA-Z0-9-_]/g, '_');
return `${this.certDir}/${safeName}`;
}
}