Feat: repo api done

This commit is contained in:
2025-07-10 15:04:24 +08:00
parent 6374a3815e
commit 0a87670469
7 changed files with 1382 additions and 14 deletions

View File

@@ -20,16 +20,19 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.844.0",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/cli": "^11.0.7",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@swc/cli": "^0.6.0",

1294
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,8 +15,8 @@ describe('AppController', () => {
});
describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
it('should return "OK"', () => {
expect(appController.getHealthz()).toBe('OK');
});
});
});

View File

@@ -1,12 +1,51 @@
import { Controller, Get } from '@nestjs/common';
import {
Controller,
Get,
Header,
Param,
Headers,
HttpException,
HttpStatus,
StreamableFile,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { GetObjectCommandInput } from '@aws-sdk/client-s3';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
constructor(
private readonly configService: ConfigService,
private readonly appService: AppService,
) {}
@Get()
getHello(): string {
return this.appService.getHello();
@Get('healthz')
getHealthz(): string {
return this.appService.getHealthz();
}
@Get(`:repo/os/:arch/:pkg`)
@Header('Accept-Ranges', 'bytes')
async getRepo(
@Headers('Range') range: string,
@Param('repo') repo: string,
@Param('arch') arch: string,
@Param('pkg') pkg: string,
): Promise<StreamableFile> {
if (repo !== this.configService.get<string>('REPO_NAME'))
throw new HttpException(`Repo '${repo}' not exist`, HttpStatus.NOT_FOUND);
if (arch !== this.configService.get<string>('ARCH_NAME'))
throw new HttpException(
`Architecture '${arch}' not exist`,
HttpStatus.NOT_FOUND,
);
const stream = await this.appService.getObject({
Bucket: this.configService.get<string>('MINIO_BUCKET'),
Key: pkg,
Range: range,
} as GetObjectCommandInput);
return new StreamableFile(stream);
}
}

View File

@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
imports: [ConfigModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})

View File

@@ -1,8 +1,41 @@
import { Injectable } from '@nestjs/common';
import { Readable } from 'stream';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
S3Client,
S3ClientConfig,
GetObjectCommand,
GetObjectCommandInput,
} from '@aws-sdk/client-s3';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
private readonly s3Client: S3Client;
constructor(private readonly configService: ConfigService) {
this.s3Client = new S3Client({
region: 'us-west-1',
endpoint: this.configService.get<string>('MINIO_ENDPOINT'),
credentials: {
accessKeyId: this.configService.get<string>('MINIO_ACCESSKEY'),
secretAccessKey: this.configService.get<string>('MINIO_SECRETKEY'),
},
forcePathStyle: true,
} as S3ClientConfig);
}
getHealthz(): string {
return 'OK';
}
async getObject(getObjectConfig: GetObjectCommandInput): Promise<Readable> {
const command = new GetObjectCommand(getObjectConfig);
const res = await this.s3Client.send(command);
if (!res.Body)
throw new HttpException(
's3 get object failed',
HttpStatus.INTERNAL_SERVER_ERROR,
);
return res.Body as Readable;
}
}

View File

@@ -5,4 +5,4 @@ async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
void bootstrap();