81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import sharp from 'sharp';
|
|
import { logger } from '../config/logger.js';
|
|
|
|
const s3Client = new S3Client({
|
|
region: process.env.AWS_REGION || 'us-east-1',
|
|
credentials: {
|
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
|
|
}
|
|
});
|
|
|
|
const BUCKET_NAME = process.env.AWS_S3_BUCKET || '';
|
|
|
|
export const s3Service = {
|
|
getUploadUrl: async (fileName: string, fileType: string) => {
|
|
const imageId = uuidv4();
|
|
const key = `uploads/${imageId}-${fileName}`;
|
|
|
|
const command = new PutObjectCommand({
|
|
Bucket: BUCKET_NAME,
|
|
Key: key,
|
|
ContentType: fileType
|
|
});
|
|
|
|
try {
|
|
const uploadUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
|
|
logger.info(`Generated pre-signed URL for upload: ${key}`);
|
|
return { uploadUrl, imageId, key };
|
|
} catch (error) {
|
|
logger.error('Error generating pre-signed URL:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
optimizeAndUpload: async (buffer: Buffer, key: string, resolution: { width: number; height: number }) => {
|
|
try {
|
|
let sharpInstance = sharp(buffer);
|
|
|
|
// Get image metadata
|
|
const metadata = await sharpInstance.metadata();
|
|
|
|
// Resize if resolution is specified
|
|
if (resolution.width > 0 && resolution.height > 0) {
|
|
sharpInstance = sharpInstance.resize(resolution.width, resolution.height, {
|
|
fit: 'inside',
|
|
withoutEnlargement: true
|
|
});
|
|
}
|
|
|
|
// Convert to WebP for better compression
|
|
const optimizedBuffer = await sharpInstance
|
|
.webp({ quality: 80 })
|
|
.toBuffer();
|
|
|
|
// Upload optimized image
|
|
const optimizedKey = key.replace(/\.[^/.]+$/, '.webp');
|
|
await s3Client.send(new PutObjectCommand({
|
|
Bucket: BUCKET_NAME,
|
|
Key: optimizedKey,
|
|
Body: optimizedBuffer,
|
|
ContentType: 'image/webp'
|
|
}));
|
|
|
|
logger.info(`Successfully optimized and uploaded image: ${optimizedKey}`);
|
|
|
|
return {
|
|
key: optimizedKey,
|
|
width: metadata.width,
|
|
height: metadata.height,
|
|
format: 'webp',
|
|
size: optimizedBuffer.length
|
|
};
|
|
} catch (error) {
|
|
logger.error('Error optimizing and uploading image:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
}; |