aaredb/frontend/fetch-openapi.js
GotthardG 3d55c42312 Refactor logistics and frontend code for better consistency.
Refactored several files to improve code clarity, error handling, and data integrity. Introduced type safety improvements, streamlined OpenAPI model integration, adjusted configuration settings, and enhanced QR code handling logic. Also updated scripts and tsconfig settings to temporarily bypass strict checks during development.
2025-03-06 13:24:12 +01:00

200 lines
7.1 KiB
JavaScript

import fs from 'fs';
import https from 'https';
import { exec } from 'child_process';
import chokidar from 'chokidar';
import path from 'path';
import util from 'util';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
if (!process.env.ENVIRONMENT) {
console.error("❌ ENVIRONMENT variable is missing.");
process.exit(1);
}
// Determine environment and configuration file
const nodeEnv = process.env.ENVIRONMENT || 'dev';
const configFile = `config_${nodeEnv}.json`;
// Load configuration file
let config;
try {
config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8'));
} catch (error) {
console.error(`❌ Failed to read configuration file '${configFile}': ${error.message}`);
process.exit(1);
}
// Validate required configurations
const requiredFields = [
'OPENAPI_URL',
'SCHEMA_PATH',
'OUTPUT_DIRECTORY',
'SSL_KEY_PATH',
'SSL_CERT_PATH',
];
for (const field of requiredFields) {
if (!config[field]) {
console.error(`❌ Missing required configuration: ${field}`);
process.exit(1);
}
}
// Resolve paths from the config
const OPENAPI_URL = config.OPENAPI_URL;
const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH);
const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY);
const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH);
const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH);
// Log configuration
console.log(`[INFO] Environment: ${nodeEnv}`);
console.log(`[INFO] Using SCHEMA_PATH: ${SCHEMA_PATH}`);
console.log(`[INFO] Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`);
// Verify SSL files
if (!fs.existsSync(SSL_KEY_PATH) || !fs.existsSync(SSL_CERT_PATH)) {
console.error(`❌ SSL files not found:
Key Path: ${SSL_KEY_PATH} (exists: ${fs.existsSync(SSL_KEY_PATH)})
Cert Path: ${SSL_CERT_PATH} (exists: ${fs.existsSync(SSL_CERT_PATH)})`);
process.exit(1);
}
const execPromisified = util.promisify(exec);
let isGenerating = false;
const debounceDelay = 500; // Debounce interval in milliseconds
// Debounce function to control rapid re-triggering
function debounce(func, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// Main function to fetch OpenAPI schema and generate services
async function fetchAndGenerate() {
if (isGenerating) {
console.log("⚠️ Generation process is already running.");
return;
}
isGenerating = true;
try {
// Fetch OpenAPI schema over HTTPS
console.log("🚀 Fetching OpenAPI schema...");
const options = {
rejectUnauthorized: false,
key: fs.readFileSync(SSL_KEY_PATH),
cert: fs.readFileSync(SSL_CERT_PATH),
};
const res = await new Promise((resolve, reject) => {
https.get(OPENAPI_URL, options, resolve).on('error', reject);
});
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', async () => {
try {
// Save schema file
fs.writeFileSync(SCHEMA_PATH, data, 'utf8');
console.log(`✅ OpenAPI schema saved to ${SCHEMA_PATH}`);
console.log("🧼 Cleaning output directory...");
await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true });
console.log(`✅ Output directory cleaned: ${OUTPUT_DIRECTORY}`);
if (!fs.existsSync(OUTPUT_DIRECTORY)) {
console.log(`✅ Confirmed removal of ${OUTPUT_DIRECTORY}`);
} else {
console.error(`❌ Failed to remove output directory: ${OUTPUT_DIRECTORY}`);
}
// Generate services
const command = `npx openapi -i ${SCHEMA_PATH} -o ${OUTPUT_DIRECTORY}`;
console.log(`🔧 Executing command: ${command}`);
const { stdout, stderr } = await execPromisified(command);
if (stderr) {
console.error(`⚠️ stderr while generating services: ${stderr}`);
} else {
console.log(`✅ Service generation completed successfully:\n${stdout}`);
}
// Copy the generated OpenAPI models to ../logistics/openapi
const targetDirectory = path.resolve('../logistics/openapi'); // Adjust as per logistics directory
console.log(`🔄 Copying generated OpenAPI models to ${targetDirectory}...`);
await fs.promises.rm(targetDirectory, { recursive: true, force: true }); // Clean target directory
await fs.promises.mkdir(targetDirectory, { recursive: true }); // Ensure the directory exists
// Copy files from OUTPUT_DIRECTORY to the target directory recursively
const copyRecursive = async (src, dest) => {
const entries = await fs.promises.readdir(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
await fs.promises.mkdir(destPath, { recursive: true });
await copyRecursive(srcPath, destPath);
} else {
await fs.promises.copyFile(srcPath, destPath);
}
}
};
await copyRecursive(OUTPUT_DIRECTORY, targetDirectory);
console.log(`✅ OpenAPI models copied successfully to ${targetDirectory}`);
} catch (error) {
console.error(`❌ Error during schema processing or generation: ${error.message}`);
}
isGenerating = false;
});
} catch (error) {
console.error(`❌ Failed to fetch OpenAPI schema: ${error.message}`);
isGenerating = false;
}
}
// Backend directory based on the environment
const backendDirectory = (() => {
switch (nodeEnv) {
case 'prod':
return path.resolve('/home/jungfrau/heidi-v2/backend/app'); // Production path
case 'test':
return path.resolve('/home/jungfrau/heidi-v2/backend/app'); // Test path
case 'dev':
default:
return path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app'); // Development path
}
})();
if (!fs.existsSync(backendDirectory)) {
console.error(`❌ Backend directory does not exist: ${backendDirectory}`);
process.exit(1);
}
console.log(`👀 Watching for changes in ${backendDirectory}`);
// Watcher for change detection
const watcher = chokidar.watch(backendDirectory, {
persistent: true,
ignored: [SCHEMA_PATH, OUTPUT_DIRECTORY],
});
watcher
.on('add', debounce(fetchAndGenerate, debounceDelay))
.on('change', debounce(fetchAndGenerate, debounceDelay))
.on('unlink', debounce(fetchAndGenerate, debounceDelay));
console.log(`👀 Watching for changes in ${backendDirectory}`);