Files
image-platform/apps/old-backend/src/internal-images/internal-images.controller.ts

64 lines
2.5 KiB
TypeScript
Raw Normal View History

import { Body, Controller, Header, Post, Res, StreamableFile } from "@nestjs/common"
import {
ApiBadGatewayResponse,
ApiBadRequestResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiResponse,
ApiTags,
} from "@nestjs/swagger"
import type { Response } from "express"
import { EnsureImageVariantRequestDto } from "./ensure-image-variant.dto"
import { InternalImagesService } from "./internal-images.service"
@ApiTags("internal-images")
@Controller("internal/images")
export class InternalImagesController {
constructor(private readonly internalImages: InternalImagesService) {}
@Post("ensure")
@ApiOperation({
summary: "подготовить variant изображения для Gateway",
description:
"Внутренний endpoint для Gateway. На L1 cache miss Backend проверяет PostgreSQL и S3, создаёт variant при необходимости, публикует RabbitMQ job, ждёт генерацию worker и возвращает готовые image bytes.",
})
@ApiOkResponse({
description: "Variant уже был готов в S3 или был успешно сгенерирован worker.",
content: {
"image/*": {
schema: {
format: "binary",
type: "string",
},
},
},
})
@ApiBadRequestResponse({ description: "Некорректный assetId, version, preset, width, quality или format." })
@ApiNotFoundResponse({ description: "Asset или указанная версия source image не найдены." })
@ApiBadGatewayResponse({ description: "Worker/imgproxy/S3 не смогли подготовить или вернуть variant." })
@ApiResponse({ status: 504, description: "Variant не успел сгенерироваться до истечения IMAGE_ENSURE_WAIT_MS." })
@Header("Cache-Control", "public, max-age=31536000, immutable")
async ensureImageVariant(
@Body() request: EnsureImageVariantRequestDto,
@Res({ passthrough: true }) response: Response,
): Promise<StreamableFile> {
const result = await this.internalImages.ensureImageVariant(request)
response.setHeader("Cache-Control", result.cacheControl)
response.setHeader("Content-Length", result.contentLength.toString())
response.setHeader("Content-Type", result.contentType)
if (result.etag) {
response.setHeader("ETag", result.etag)
}
if (result.vary) {
response.setHeader("Vary", result.vary)
}
return new StreamableFile(result.body)
}
}