11package com .sonkim .bookmarking .common .s3 .service ;
22
3- import com .sksamuel . scrimage . ImmutableImage ;
4- import com .sksamuel . scrimage . webp . WebpWriter ;
3+ import com .fasterxml . jackson . core . JsonProcessingException ;
4+ import com .fasterxml . jackson . databind . ObjectMapper ;
55import com .sonkim .bookmarking .common .s3 .dto .PresignedUrlDto ;
66import lombok .extern .slf4j .Slf4j ;
77import org .springframework .beans .factory .annotation .Value ;
88import org .springframework .stereotype .Service ;
9- import software .amazon .awssdk .core .ResponseBytes ;
9+ import software .amazon .awssdk .core .SdkBytes ;
1010import software .amazon .awssdk .core .sync .RequestBody ;
11+ import software .amazon .awssdk .services .lambda .LambdaClient ;
12+ import software .amazon .awssdk .services .lambda .model .InvokeRequest ;
13+ import software .amazon .awssdk .services .lambda .model .InvokeResponse ;
1114import software .amazon .awssdk .services .s3 .S3Client ;
12- import software .amazon .awssdk .services .s3 .model .DeleteObjectRequest ;
1315import software .amazon .awssdk .services .s3 .model .GetObjectRequest ;
14- import software .amazon .awssdk .services .s3 .model .GetObjectResponse ;
1516import software .amazon .awssdk .services .s3 .model .PutObjectRequest ;
1617import software .amazon .awssdk .services .s3 .presigner .S3Presigner ;
1718import software .amazon .awssdk .services .s3 .presigner .model .GetObjectPresignRequest ;
1819import software .amazon .awssdk .services .s3 .presigner .model .PresignedGetObjectRequest ;
1920import software .amazon .awssdk .services .s3 .presigner .model .PresignedPutObjectRequest ;
2021import software .amazon .awssdk .services .s3 .presigner .model .PutObjectPresignRequest ;
2122
22- import java .io .IOException ;
2323import java .net .URL ;
2424import java .time .Duration ;
25+ import java .util .HashMap ;
26+ import java .util .Map ;
2527import java .util .UUID ;
2628
2729@ Slf4j
@@ -31,11 +33,18 @@ public class S3Service {
3133 private final S3Client s3Client ;
3234 private final String bucketName ;
3335 private final S3Presigner s3Presigner ;
36+ private final LambdaClient lambdaClient ;
37+ private final ObjectMapper objectMapper ;
3438
35- public S3Service (S3Client s3Client , @ Value ("${aws.s3.bucket-name}" ) String bucketName , S3Presigner s3Presigner ) {
39+ @ Value ("${aws.lambda.function-name}" )
40+ private String lambdaFunctionName ;
41+
42+ public S3Service (S3Client s3Client , @ Value ("${aws.s3.bucket-name}" ) String bucketName , S3Presigner s3Presigner , LambdaClient lambdaClient , ObjectMapper objectMapper ) {
3643 this .s3Client = s3Client ;
3744 this .bucketName = bucketName ;
3845 this .s3Presigner = s3Presigner ;
46+ this .lambdaClient = lambdaClient ;
47+ this .objectMapper = objectMapper ;
3948 }
4049
4150 public URL generatePresignedGetUrl (String prefix , String key ) {
@@ -77,48 +86,43 @@ public PresignedUrlDto generatePresignedPutUrl(String fileName) {
7786 }
7887
7988 public String moveFileToPermanentStorage (String prefix , String fileName ) {
80- String sourceKey = "temp/" + fileName ;
81-
8289 try {
83- // S3 임시 폴더에서 이미지 다운로드
84- GetObjectRequest getRequest = GetObjectRequest .builder ()
85- .bucket (bucketName )
86- .key (sourceKey )
90+ // Lambda에 보낼 데이터 생성
91+ Map <String , String > payloadMap = new HashMap <>();
92+ payloadMap .put ("prefix" , prefix );
93+ payloadMap .put ("fileName" , fileName );
94+ String jsonPayload = objectMapper .writeValueAsString (payloadMap );
95+
96+ // Lambda 호출 요청 생성
97+ InvokeRequest invokeRequest = InvokeRequest .builder ()
98+ .functionName (lambdaFunctionName )
99+ .payload (SdkBytes .fromUtf8String (jsonPayload ))
87100 .build ();
88- ResponseBytes <GetObjectResponse > responseBytes = s3Client .getObjectAsBytes (getRequest );
89- byte [] originalBytes = responseBytes .asByteArray ();
90101
91- // 리사이징 및 WebP로 변환
92- ImmutableImage image = ImmutableImage .loader ().fromBytes (originalBytes );
93- if (image .width > 600 ) {
94- image = image .scaleToWidth (600 );
102+ log .info ("AWS Lambda 호출 시작: Function={}, Payload={}" , lambdaFunctionName , jsonPayload );
103+
104+ // 호출. 완료될 때까지 대기
105+ InvokeResponse invokeResponse = lambdaClient .invoke (invokeRequest );
106+
107+ // 완료 후 전달된 응답에 담긴 파일 이름 가져오기
108+ String responseString = invokeResponse .payload ().asUtf8String ();
109+
110+ // 에러 체크 (Lambda 실행 에러)
111+ if (invokeResponse .functionError () != null ) {
112+ log .error ("Lambda 실행 오류: {}" , responseString );
113+ throw new RuntimeException ("이미지 처리 Lambda 실행 중 오류 발생: " + responseString );
95114 }
96- byte [] convertedBytes = image .bytes (WebpWriter .DEFAULT .withQ (80 ));
97-
98- // 새로운 파일 이름 생성 (확장자를 .webp로 변경)
99- String newFileName = getFileNameWithoutExtension (fileName ) + ".webp" ;
100- String destKey = prefix + newFileName ;
101-
102- // 영구 저장소에 이미지 업로드
103- PutObjectRequest putRequest = PutObjectRequest .builder ()
104- .bucket (bucketName )
105- .key (destKey )
106- .contentType ("image/webp" )
107- .contentDisposition ("inline" )
108- .build ();
109- s3Client .putObject (putRequest , RequestBody .fromBytes (convertedBytes ));
110115
111- // 임시 저장소의 원본 파일 제거
112- s3Client .deleteObject (DeleteObjectRequest .builder ()
113- .bucket (bucketName )
114- .key (sourceKey )
115- .build ());
116+ // 앞뒤 쌍따옴표 제거
117+ String newFileName = responseString .replace ("\" " , "" );
116118
117- log .info ("이미지 변환 및 이동 완료: {} -> {}" , sourceKey , destKey );
119+ log .info ("AWS Lambda 처리 완료. 변환된 파일명: {}" , newFileName );
118120 return newFileName ;
119121
120- } catch (IOException e ) {
121- throw new RuntimeException ("이미지 처리 및 이동 중 오류 발생: " + fileName , e );
122+ } catch (JsonProcessingException e ) {
123+ throw new RuntimeException ("Lambda 호출 Payload 생성 실패" , e );
124+ } catch (Exception e ) {
125+ throw new RuntimeException ("이미지 처리 서버(Lambda) 호출 중 오류 발생" , e );
122126 }
123127 }
124128
@@ -166,11 +170,4 @@ private String getContentType(String fileName) {
166170 "application/octet-stream" ;
167171 };
168172 }
169-
170- private String getFileNameWithoutExtension (String fileName ) {
171- if (fileName .contains ("." )) {
172- return fileName .substring (0 , fileName .lastIndexOf ('.' ));
173- }
174- return fileName ;
175- }
176173}
0 commit comments