11import { getLogger } from '@infrastructure/logging/index.js' ;
2- import S3 from 'aws-sdk/clients/s3.js' ;
3- import type { Buffer } from 'buffer' ;
2+ import { S3Client , GetObjectCommand , PutObjectCommand , CreateBucketCommand } from '@aws-sdk/client-s3' ;
3+ import { Buffer } from 'buffer' ;
4+ import { Readable } from 'stream' ;
5+ import { streamToBuffer } from '@infrastructure/utils/streamToBuffer.js' ;
6+ import { isEmpty } from '@infrastructure/utils/empty.js' ;
47
58const s3StorageLogger = getLogger ( 's3Storage' ) ;
69
@@ -11,7 +14,7 @@ export class S3Storage {
1114 /**
1215 * S3 instance
1316 */
14- private readonly s3 : S3 ;
17+ private readonly s3 : S3Client ;
1518
1619 /**
1720 * Constructor for S3Bucket
@@ -21,10 +24,10 @@ export class S3Storage {
2124 * @param endpoint - AWS endpoint (in case of localstack or other S3 compatible services)
2225 */
2326 constructor ( accessKeyId : string , secretAccessKey : string , region ?: string , endpoint ?: string ) {
24- this . s3 = new S3 ( {
27+ this . s3 = new S3Client ( {
2528 endpoint,
2629 region,
27- s3ForcePathStyle : true ,
30+ forcePathStyle : true ,
2831 credentials : {
2932 accessKeyId,
3033 secretAccessKey,
@@ -39,27 +42,22 @@ export class S3Storage {
3942 * @param file - file data to upload
4043 */
4144 public async uploadFile ( bucket : string , key : string , file : Buffer ) : Promise < string | null > {
42- /**
43- * Create an upload manager to upload the file to S3
44- */
45- const uploadManager = this . s3 . upload ( {
46- Bucket : bucket ,
47- Key : key ,
48- Body : file ,
49- } ) ;
50-
51- /**
52- * Wait for the upload to complete and return the URL of the uploaded file
53- */
5445 try {
55- const response = await uploadManager . promise ( ) ;
56-
57- return response . Location ;
46+ /**
47+ * Try to upload file data to s3
48+ */
49+ await this . s3 . send ( new PutObjectCommand ( {
50+ Bucket : bucket ,
51+ Key : key ,
52+ Body : file ,
53+ } ) )
5854 } catch ( error ) {
5955 s3StorageLogger . error ( error ) ;
6056
6157 return null ;
6258 }
59+
60+ return key ;
6361 }
6462
6563 /**
@@ -68,18 +66,24 @@ export class S3Storage {
6866 * @param key - Key of the file in S3
6967 */
7068 public async getFile ( bucket : string , key : string ) : Promise < Buffer | null > {
71- const getObjectManager = this . s3 . getObject ( {
72- Bucket : bucket ,
73- Key : key ,
74- } ) ;
75-
7669 try {
77- const response = await getObjectManager . promise ( ) ;
70+ const { Body } = await this . s3 . send ( new GetObjectCommand ( {
71+ Bucket : bucket ,
72+ Key : key ,
73+ } ) ) ;
7874
79- return response . Body as Buffer ;
80- } catch ( error ) {
81- s3StorageLogger . error ( error ) ;
75+ /**
76+ * Body must be readable to parse stream
77+ */
78+ if ( ! ( Body instanceof Readable ) ) {
79+ s3StorageLogger . error ( 'Expected Body to be a Readable stream' ) ;
8280
81+ return null ;
82+ }
83+ const fileContent = await streamToBuffer ( Body ) ;
84+ return fileContent ;
85+ } catch ( err ) {
86+ s3StorageLogger . error ( err ) ;
8387 return null ;
8488 }
8589 }
@@ -89,18 +93,20 @@ export class S3Storage {
8993 * @param name - bucket name
9094 */
9195 public async createBucket ( name : string ) : Promise < string | null > {
92- const createBucketManager = this . s3 . createBucket ( {
93- Bucket : name ,
94- } ) ;
95-
9696 try {
97- const response = await createBucketManager . promise ( ) ;
97+ const { Location } = await this . s3 . send ( new CreateBucketCommand ( {
98+ Bucket : name ,
99+ } ) ) ;
98100
99- return response . Location as string ;
100- } catch ( error ) {
101- s3StorageLogger . error ( error ) ;
101+ if ( isEmpty ( Location ) ) {
102+ return null ;
103+ }
102104
103- return null ;
105+ return Location ;
106+ } catch ( err ) {
107+ s3StorageLogger . error ( err ) ;
108+
109+ return null ;
104110 }
105111 }
106112}
0 commit comments