diff --git a/src/app.controller.ts b/src/app.controller.ts index 39348a0..272567d 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,7 +1,11 @@ +import { Response } from 'express'; +import { Readable } from 'stream'; + import { Controller, Get, Header, + Res, Param, Headers, HttpException, @@ -9,7 +13,9 @@ import { StreamableFile, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; +import { ApiOkResponse, ApiNotFoundResponse } from '@nestjs/swagger'; import { GetObjectCommandInput } from '@aws-sdk/client-s3'; + import { AppService } from './app.service'; @Controller() @@ -19,15 +25,19 @@ export class AppController { private readonly appService: AppService, ) {} + @ApiOkResponse() @Get('healthz') getHealthz(): string { return this.appService.getHealthz(); } + @ApiOkResponse() + @ApiNotFoundResponse() @Get(`:repo/os/:arch/:pkg`) @Header('Accept-Ranges', 'bytes') async getRepo( @Headers('Range') range: string, + @Res({ passthrough: true }) res: Response, @Param('repo') repo: string, @Param('arch') arch: string, @Param('pkg') pkg: string, @@ -40,15 +50,18 @@ export class AppController { HttpStatus.NOT_FOUND, ); - const stream = await this.appService.getObject({ + const output = await this.appService.getObject({ Bucket: this.configService.get('MINIO_BUCKET'), Key: pkg, Range: range, } as GetObjectCommandInput); - if (!stream) - throw new HttpException( - `No such file '${pkg}'`, HttpStatus.NOT_FOUND); + if (!output || !output.Body) + throw new HttpException(`No such file '${pkg}'`, HttpStatus.NOT_FOUND); - return new StreamableFile(stream); + if (range !== undefined) { + res.set('Content-Length', `${output.ContentLength}`) + res.set('Content-Range', `${output.ContentRange}`) + } + return new StreamableFile(output.Body as Readable); } } diff --git a/src/app.service.ts b/src/app.service.ts index 51b870a..d28f529 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -30,22 +30,16 @@ export class AppService { return 'OK'; } - async getObject(getObjectConfig: GetObjectCommandInput): Promise { + async getObject( + getObjectConfig: GetObjectCommandInput, + ): Promise { const command = new GetObjectCommand(getObjectConfig); - let res: GetObjectCommandOutput; try { - res = await this.s3Client.send(command); + return await this.s3Client.send(command); } catch (err: unknown) { if (err instanceof NoSuchKey) return null; throw err; } - if (!res.Body) - throw new HttpException( - 's3 get object failed', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - - return res.Body as Readable; } }