.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package kz.konturai.parser.service;
|
||||
|
||||
import io.minio.GetPresignedObjectUrlArgs;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.PutObjectArgs;
|
||||
import io.minio.http.Method;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* MinIO-based implementation of ImageStorageService.
|
||||
*
|
||||
* Uploads images to MinIO storage and returns presigned URLs that are publicly
|
||||
* accessible for a limited time (7 days). These URLs can be used by Instagram
|
||||
* API.
|
||||
*/
|
||||
@Service
|
||||
public class ImageStorageServiceImpl implements ImageStorageService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ImageStorageServiceImpl.class);
|
||||
private static final int PRESIGNED_URL_EXPIRY_DAYS = 7;
|
||||
|
||||
private final MinioClient minioClient;
|
||||
private final String bucketName;
|
||||
|
||||
public ImageStorageServiceImpl(
|
||||
@Value("${minio.endpoint}") String endpoint,
|
||||
@Value("${minio.access-key}") String accessKey,
|
||||
@Value("${minio.secret-key}") String secretKey,
|
||||
@Value("${minio.bucket-name}") String bucketName) {
|
||||
this.minioClient = MinioClient.builder()
|
||||
.endpoint(endpoint)
|
||||
.credentials(accessKey, secretKey)
|
||||
.build();
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadImage(byte[] imageBytes, String filename) {
|
||||
try {
|
||||
// Generate a unique object name with timestamp and UUID to avoid collisions
|
||||
String objectName = generateObjectName(filename);
|
||||
|
||||
// Determine content type based on filename extension
|
||||
String contentType = determineContentType(filename);
|
||||
|
||||
// Upload the image to MinIO
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.stream(new ByteArrayInputStream(imageBytes), imageBytes.length, -1)
|
||||
.contentType(contentType)
|
||||
.build());
|
||||
|
||||
logger.info("Successfully uploaded image to MinIO: {}", objectName);
|
||||
|
||||
// Generate a presigned URL that's valid for 7 days
|
||||
String presignedUrl = minioClient.getPresignedObjectUrl(
|
||||
GetPresignedObjectUrlArgs.builder()
|
||||
.method(Method.GET)
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.expiry(PRESIGNED_URL_EXPIRY_DAYS, TimeUnit.DAYS)
|
||||
.build());
|
||||
|
||||
logger.info("Generated presigned URL for image: {}", objectName);
|
||||
return presignedUrl;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to upload image to MinIO and generate presigned URL: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Failed to upload image to storage: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique object name for the image.
|
||||
* Format: instagram/{timestamp}-{uuid}-{original-filename}
|
||||
*/
|
||||
private String generateObjectName(String filename) {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String uuid = UUID.randomUUID().toString().substring(0, 8);
|
||||
String sanitizedFilename = filename != null ? filename.replaceAll("[^a-zA-Z0-9._-]", "_") : "image.jpg";
|
||||
return String.format("instagram/%s-%s-%s", timestamp, uuid, sanitizedFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the content type based on the filename extension.
|
||||
*/
|
||||
private String determineContentType(String filename) {
|
||||
if (filename == null) {
|
||||
return "image/jpeg";
|
||||
}
|
||||
|
||||
String lowerFilename = filename.toLowerCase();
|
||||
if (lowerFilename.endsWith(".png")) {
|
||||
return "image/png";
|
||||
} else if (lowerFilename.endsWith(".gif")) {
|
||||
return "image/gif";
|
||||
} else if (lowerFilename.endsWith(".webp")) {
|
||||
return "image/webp";
|
||||
} else {
|
||||
return "image/jpeg"; // Default to JPEG
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user