Improve backend media readiness for mobile clients
فشلت بعض الفحوصات
Deploy To Ghaymah / deploy (push) Has been cancelled

هذا الالتزام موجود في:
boutmoun123
2026-05-25 23:18:00 +03:00
الأصل efd87659b2
التزام acd8d0d8cf
8 ملفات معدلة مع 238 إضافات و2 حذوفات

عرض الملف

@@ -8,7 +8,8 @@ import {
} from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import { randomUUID } from 'crypto';
import { mkdir, rm, unlink, writeFile } from 'fs/promises';
import { constants } from 'fs';
import { access, mkdir, rm, unlink, writeFile } from 'fs/promises';
import { dirname, join, posix } from 'path';
@Injectable()
@@ -182,6 +183,53 @@ export class ManagedStorageService implements OnModuleDestroy {
await rm(join(process.cwd(), ...directoryPath.split('/')), { recursive: true, force: true });
}
async getHealth(): Promise<Record<string, unknown>> {
const provider = this.getProvider();
const basePath = this.getBasePath();
const publicBaseUrl =
(this.configService.get<string>('storage.publicBaseUrl', { infer: true }) ?? '').replace(
/\/$/,
'',
);
const health: Record<string, unknown> = {
provider,
basePath,
publicPath: `/${basePath}`,
publicBaseUrlConfigured: !!publicBaseUrl,
s3Configured: provider === 's3' ? this.hasS3Configuration() : undefined,
};
if (provider === 'local') {
const uploadDir = join(process.cwd(), ...basePath.split('/'));
const probePath = join(uploadDir, `.media-health-${randomUUID()}.tmp`);
let writable = false;
let error = '';
try {
await mkdir(uploadDir, { recursive: true });
await writeFile(probePath, 'ok');
await unlink(probePath);
writable = true;
} catch (probeError) {
error = probeError instanceof Error ? probeError.message : 'unknown local storage error';
try {
await unlink(probePath);
} catch {
// Ignore cleanup failure for a failed probe.
}
}
health.local = {
runtimePath: uploadDir,
writable,
readable: await this.canAccess(uploadDir, constants.R_OK),
error,
};
}
return health;
}
onModuleDestroy(): void {
this.s3Client = null;
}
@@ -323,6 +371,24 @@ export class ManagedStorageService implements OnModuleDestroy {
return null;
}
private hasS3Configuration(): boolean {
return !!(
(this.configService.get<string>('storage.s3.bucket', { infer: true }) ?? '') &&
(this.configService.get<string>('storage.s3.endpoint', { infer: true }) ?? '') &&
(this.configService.get<string>('storage.s3.accessKeyId', { infer: true }) ?? '') &&
(this.configService.get<string>('storage.s3.secretAccessKey', { infer: true }) ?? '')
);
}
private async canAccess(path: string, mode: number): Promise<boolean> {
try {
await access(path, mode);
return true;
} catch {
return false;
}
}
private async deleteS3Prefix(prefix: string): Promise<void> {
const client = this.getS3Client();
const bucket = this.getS3Bucket();