fix file size limit

This commit is contained in:
lendry
2026-07-07 17:36:01 +03:00
parent b90017aad0
commit f36a8d7456
12 changed files with 482 additions and 159 deletions

View File

@@ -83,6 +83,7 @@ export class AdminAppReleaseController {
platform: { type: 'string', enum: ['ANDROID', 'WINDOWS'] },
version: { type: 'string', example: '1.2.0' },
versionCode: { type: 'integer', example: 120 },
variant: { type: 'string', example: 'arm64-v8a', description: 'Вариант сборки. Если пусто — определяется из имени файла.' },
releaseNotes: { type: 'string' },
file: { type: 'string', format: 'binary' }
},
@@ -96,6 +97,7 @@ export class AdminAppReleaseController {
@Body('platform') platform: string,
@Body('version') version: string,
@Body('versionCode') versionCodeRaw: string,
@Body('variant') variant: string | undefined,
@Body('releaseNotes') releaseNotes?: string
) {
assertAdminPermission(admin, 'canManageSettings');
@@ -124,7 +126,12 @@ export class AdminAppReleaseController {
const safeVersion = version.trim().replace(/[^a-zA-Z0-9._-]+/g, '_');
const safeName = fileName.replace(/[^a-zA-Z0-9._-]+/g, '_');
const storageKey = `releases/${normalizedPlatform.toLowerCase()}/${safeVersion}/${randomUUID()}-${safeName}`;
const normalizedVariant = (variant?.trim() || fileName.replace(/\.apk$/i, ''))
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^a-z0-9._-]/g, '')
.slice(0, 64) || 'universal';
const storageKey = `releases/${normalizedPlatform.toLowerCase()}/${safeVersion}/${normalizedVariant}/${randomUUID()}-${safeName}`;
const sha256 = createHash('sha256').update(file.buffer).digest('hex');
const contentType =
normalizedPlatform === 'ANDROID'
@@ -146,6 +153,7 @@ export class AdminAppReleaseController {
platform: normalizedPlatform,
version: version.trim(),
versionCode,
variant: variant?.trim() || undefined,
fileName,
storageKey,
fileSize: String(file.size),

View File

@@ -79,14 +79,19 @@ export class AppReleaseController {
@Get('download/:platform')
@ApiOperation({ summary: 'Скачать последний релиз', description: 'Отдаёт файл последней опубликованной версии.' })
@ApiParam({ name: 'platform', enum: ['android', 'windows', 'ANDROID', 'WINDOWS'] })
@ApiQuery({ name: 'variant', required: false, description: 'Вариант сборки, например universal или arm64-v8a' })
@ApiResponse({ status: 200, description: 'Файл релиза' })
async downloadLatest(@Param('platform') platform: string, @Res({ passthrough: false }) response: StreamResponse) {
async downloadLatest(
@Param('platform') platform: string,
@Query('variant') variant: string | undefined,
@Res({ passthrough: false }) response: StreamResponse
) {
const normalized = this.normalizePlatform(platform);
if (!normalized) {
response.status(400).json({ message: 'Некорректная платформа' });
return;
}
await this.streamRelease(response, normalized);
await this.streamRelease(response, normalized, undefined, variant);
}
@Get('download/:platform/:releaseId')
@@ -104,9 +109,14 @@ export class AppReleaseController {
await this.streamRelease(response, normalized, releaseId);
}
private async streamRelease(response: StreamResponse, platform: string, releaseId?: string) {
private async streamRelease(
response: StreamResponse,
platform: string,
releaseId?: string,
variant?: string
) {
const resolved = (await firstValueFrom(
this.core.appRelease.ResolveAppReleaseDownload({ platform, releaseId })
this.core.appRelease.ResolveAppReleaseDownload({ platform, releaseId, variant })
)) as {
storageKey: string;
fileName: string;
@@ -115,6 +125,7 @@ export class AppReleaseController {
sha256: string;
version: string;
versionCode: number;
variant: string;
};
const bucket = process.env.MINIO_BUCKET ?? 'lendry-id';
@@ -129,6 +140,7 @@ export class AppReleaseController {
response.setHeader('Content-Length', resolved.fileSize);
response.setHeader('X-Release-Version', resolved.version);
response.setHeader('X-Release-Version-Code', String(resolved.versionCode));
response.setHeader('X-Release-Variant', resolved.variant);
response.setHeader('X-Release-Sha256', resolved.sha256);
response.setHeader('Cache-Control', 'public, max-age=300');
response.setHeader('Content-Disposition', buildContentDisposition('attachment', resolved.fileName));