Improve backend media readiness for mobile clients
فشلت بعض الفحوصات
Deploy To Ghaymah / deploy (push) Has been cancelled
فشلت بعض الفحوصات
Deploy To Ghaymah / deploy (push) Has been cancelled
هذا الالتزام موجود في:
@@ -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();
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم