|
|
|
|
@@ -11,15 +11,23 @@ import { diskStorage } from 'multer';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
import * as fsPromises from 'fs/promises';
|
|
|
|
|
import * as path from 'path';
|
|
|
|
|
import * as os from 'os';
|
|
|
|
|
import { execFile } from 'child_process';
|
|
|
|
|
import { promisify } from 'util';
|
|
|
|
|
import { randomUUID } from 'crypto';
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
|
|
|
const asyncapiBundle = require('@asyncapi/bundler');
|
|
|
|
|
|
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
|
|
|
const localBin = path.join(process.cwd(), 'node_modules', '.bin');
|
|
|
|
|
const execEnv = {
|
|
|
|
|
...process.env,
|
|
|
|
|
PATH: `${localBin}${path.delimiter}${process.env.PATH ?? ''}`,
|
|
|
|
|
};
|
|
|
|
|
import { ApisService } from '../apis/apis.service';
|
|
|
|
|
import { DocsGenerationService } from '../docs-generation/docs-generation.service';
|
|
|
|
|
import { ApiType } from '@datacat/shared';
|
|
|
|
|
|
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
|
|
|
|
|
|
|
|
@Controller('uploads')
|
|
|
|
|
export class UploadsController {
|
|
|
|
|
constructor(
|
|
|
|
|
@@ -30,7 +38,7 @@ export class UploadsController {
|
|
|
|
|
@Post()
|
|
|
|
|
@UseInterceptors(
|
|
|
|
|
FilesInterceptor('files', 20, {
|
|
|
|
|
storage: diskStorage({ destination: '/tmp/uploads' }),
|
|
|
|
|
storage: diskStorage({ destination: path.join(os.tmpdir(), 'datacat-uploads') }),
|
|
|
|
|
fileFilter: (_req, file, cb) => {
|
|
|
|
|
if (!file.originalname.match(/\.(yaml|yml)$/i)) {
|
|
|
|
|
return cb(new BadRequestException('Only YAML files are allowed'), false);
|
|
|
|
|
@@ -61,8 +69,9 @@ export class UploadsController {
|
|
|
|
|
if (!body.version) throw new BadRequestException('version is required');
|
|
|
|
|
|
|
|
|
|
/* Crée le répertoire si absent */
|
|
|
|
|
if (!fs.existsSync('/tmp/uploads')) {
|
|
|
|
|
fs.mkdirSync('/tmp/uploads', { recursive: true });
|
|
|
|
|
const uploadDir = path.join(os.tmpdir(), 'datacat-uploads');
|
|
|
|
|
if (!fs.existsSync(uploadDir)) {
|
|
|
|
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let yamlContent: string;
|
|
|
|
|
@@ -131,7 +140,7 @@ export class UploadsController {
|
|
|
|
|
mainFile: Express.Multer.File,
|
|
|
|
|
type: ApiType,
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
const tempDir = `/tmp/uploads/${randomUUID()}`;
|
|
|
|
|
const tempDir = path.join(os.tmpdir(), 'datacat-uploads', randomUUID());
|
|
|
|
|
const bundledPath = path.join(tempDir, 'bundled.yaml');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
@@ -145,12 +154,15 @@ export class UploadsController {
|
|
|
|
|
const mainPath = path.join(tempDir, mainFile.originalname);
|
|
|
|
|
|
|
|
|
|
if (type === 'OPENAPI') {
|
|
|
|
|
await execFileAsync('redocly', ['bundle', mainPath, '--output', bundledPath]);
|
|
|
|
|
} else {
|
|
|
|
|
await execFileAsync('asyncapi', ['bundle', mainPath, '--output', bundledPath]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* redocly bundle : pas d'appel réseau, fonctionne en local */
|
|
|
|
|
await execFileAsync('redocly', ['bundle', mainPath, '--output', bundledPath], { shell: true, env: execEnv });
|
|
|
|
|
return await fsPromises.readFile(bundledPath, 'utf-8');
|
|
|
|
|
} else {
|
|
|
|
|
/* @asyncapi/bundler API programmatique : aucun appel réseau */
|
|
|
|
|
const bundleFn = asyncapiBundle.default ?? asyncapiBundle;
|
|
|
|
|
const document = await bundleFn([mainPath], { base: mainPath });
|
|
|
|
|
return document.string();
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
/* Nettoyage du répertoire temp même en cas d'erreur */
|
|
|
|
|
await fsPromises.rm(tempDir, { recursive: true, force: true }).catch(() => undefined);
|
|
|
|
|
|