Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
/**
|
|
* Infrastructure Adapter: InMemoryMediaStorageAdapter
|
|
*
|
|
* In-memory implementation of MediaStoragePort for testing purposes.
|
|
* Simulates file storage without actual filesystem operations.
|
|
*/
|
|
|
|
import type { MediaStoragePort, UploadOptions, UploadResult } from '@core/media/application/ports/MediaStoragePort';
|
|
import type { Logger } from '@core/shared/domain/Logger';
|
|
|
|
export class InMemoryMediaStorageAdapter implements MediaStoragePort {
|
|
private storage: Map<string, Buffer> = new Map();
|
|
private metadata: Map<string, { size: number; contentType: string }> = new Map();
|
|
|
|
constructor(private readonly logger: Logger) {
|
|
this.logger.info('[InMemoryMediaStorageAdapter] Initialized.');
|
|
}
|
|
|
|
async uploadMedia(buffer: Buffer, options: UploadOptions): Promise<UploadResult> {
|
|
this.logger.debug(`[InMemoryMediaStorageAdapter] Uploading media: ${options.filename}`);
|
|
|
|
// Validate content type
|
|
const allowedTypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'image/gif'];
|
|
if (!allowedTypes.includes(options.mimeType)) {
|
|
return {
|
|
success: false,
|
|
errorMessage: `Content type ${options.mimeType} is not allowed`,
|
|
};
|
|
}
|
|
|
|
// Generate storage key
|
|
const storageKey = `/media/uploaded/${Date.now()}-${options.filename.replace(/[^a-zA-Z0-9.-]/g, '_')}`;
|
|
|
|
// Store buffer and metadata
|
|
this.storage.set(storageKey, buffer);
|
|
this.metadata.set(storageKey, {
|
|
size: buffer.length,
|
|
contentType: options.mimeType,
|
|
});
|
|
|
|
this.logger.info(`Media uploaded successfully: ${storageKey}`);
|
|
|
|
return {
|
|
success: true,
|
|
filename: options.filename,
|
|
url: storageKey,
|
|
};
|
|
}
|
|
|
|
async deleteMedia(storageKey: string): Promise<void> {
|
|
this.logger.debug(`[InMemoryMediaStorageAdapter] Deleting media: ${storageKey}`);
|
|
|
|
this.storage.delete(storageKey);
|
|
this.metadata.delete(storageKey);
|
|
|
|
this.logger.info(`Media deleted successfully: ${storageKey}`);
|
|
}
|
|
|
|
async getBytes(storageKey: string): Promise<Buffer | null> {
|
|
this.logger.debug(`[InMemoryMediaStorageAdapter] Getting bytes for: ${storageKey}`);
|
|
|
|
const buffer = this.storage.get(storageKey) ?? null;
|
|
|
|
if (buffer) {
|
|
this.logger.info(`Retrieved bytes for: ${storageKey}`);
|
|
} else {
|
|
this.logger.warn(`No bytes found for: ${storageKey}`);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
async getMetadata(storageKey: string): Promise<{ size: number; contentType: string } | null> {
|
|
this.logger.debug(`[InMemoryMediaStorageAdapter] Getting metadata for: ${storageKey}`);
|
|
|
|
const meta = this.metadata.get(storageKey) ?? null;
|
|
|
|
if (meta) {
|
|
this.logger.info(`Retrieved metadata for: ${storageKey}`);
|
|
} else {
|
|
this.logger.warn(`No metadata found for: ${storageKey}`);
|
|
}
|
|
|
|
return meta;
|
|
}
|
|
|
|
/**
|
|
* Clear all stored media
|
|
*/
|
|
clear(): void {
|
|
this.storage.clear();
|
|
this.metadata.clear();
|
|
this.logger.info('[InMemoryMediaStorageAdapter] All media cleared.');
|
|
}
|
|
|
|
/**
|
|
* Get the total number of stored media files
|
|
*/
|
|
get size(): number {
|
|
return this.storage.size;
|
|
}
|
|
|
|
/**
|
|
* Check if a storage key exists
|
|
*/
|
|
has(storageKey: string): boolean {
|
|
return this.storage.has(storageKey);
|
|
}
|
|
}
|