using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Numerics; using System.Net; using Amazon.DynamoDBv2.Model; using Amazon.DynamoDBv2; using Amazon.S3; using Amazon.Internal; using Amazon; using Amazon.S3.Model; using Amazon.Runtime.Internal; namespace ServerCore; // HANDOVER: AWS S3 SDK Wrapper 클래스 이다. // S3 저장소에 관리할 Bucket 정보를 관리해 준다. public abstract class S3ConnectorBase { private AmazonS3Client? m_s3_client; private string m_access_key = string.Empty; private string m_secret_key = string.Empty; private string m_region = string.Empty; public bool createS3Client(string accessKey, string secretKey, string region) { try { m_access_key = accessKey; m_secret_key = secretKey; m_region = region; var regionEndpoint = RegionEndpoint.GetBySystemName(region); // 여기서 실제로 연결 시도는 하지 않는다 !!!, 단순 초기화 m_s3_client = new AmazonS3Client(accessKey, secretKey, regionEndpoint); } catch (Exception e) { Log.getLogger().error($"Exception !!!, Failed to perform in createS3Client() : accessKey:{accessKey}, secretKey:{secretKey}, region:{region}, exception:{e}"); return false; } return true; } public async Task<(bool, List)> getBuckets() { var buckets = new List(); try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var response = await m_s3_client.ListBucketsAsync(); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to ListBucketsAsync() !!! : HttpStatusCode:{response.HttpStatusCode}"); return (false, buckets); } return (true, response.Buckets); } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perfrom in getBuckets() !!! : exception:{e}"); } return (false, buckets); } public async Task createBucket(PutBucketRequest request) { try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var response = await m_s3_client.PutBucketAsync(request); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to PutBucketAsync() !!! : HttpStatusCode:{response.HttpStatusCode}"); return false; } } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perfrom in createBucket() !!! : exception:{e}"); return false; } return true; } public async Task uploadFile(PutObjectRequest request) { try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var response = await m_s3_client.PutObjectAsync(request); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to PutObjectAsync() !!! : HttpStatusCode:{response.HttpStatusCode}"); return false; } } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in uploadFile() : exception:{e}"); return false; } return true; } public async Task deleteFile(DeleteObjectRequest request) { try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var response = await m_s3_client.DeleteObjectAsync(request); if (response.HttpStatusCode != HttpStatusCode.NoContent) { Log.getLogger().fatal($"Failed to DeleteObjectAsync() !!!, in deleteFile() : HttpStatusCode:{response.HttpStatusCode}"); return false; } } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in deleteFile() : exception:{e}"); return false; } return true; } public async Task deleteFolderFile(ListObjectsV2Request request) { try { ListObjectsV2Response response; do { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); response = await m_s3_client.ListObjectsV2Async(request); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to ListObjectsV2Async() !!!, in deleteFolderFile() : HttpStatusCode:{response.HttpStatusCode}"); return false; } if (response.S3Objects.Count == 0) { return true; } var delete_request = new DeleteObjectsRequest { BucketName = request.BucketName, }; foreach (var s3_object in response.S3Objects) { delete_request.AddKey(s3_object.Key); } var delete_response = await m_s3_client.DeleteObjectsAsync(delete_request); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to DeleteObjectsAsync() !!!, in deleteFolderFile() : HttpStatusCode:{response.HttpStatusCode}"); return false; } request.ContinuationToken = response.NextContinuationToken; } while (response.IsTruncated); } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in deleteFolderFile() : exception:{e}"); return false; } return true; } public async Task<(bool, Stream?)> getFileStream(GetObjectRequest request) { try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var response = await m_s3_client.GetObjectAsync(request); if (response.HttpStatusCode != HttpStatusCode.OK) { Log.getLogger().fatal($"Failed to GetObjectAsync() !!! : HttpStatusCode:{response.HttpStatusCode}"); return (false, null); } return (true, response.ResponseStream); } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in getFileStream() : exception:{e}"); } return (false, null); } private async Task<(bool, string)> generatePreSignedUrl(GetPreSignedUrlRequest request) { try { NullReferenceCheckHelper.throwIfNull(m_s3_client, () => $"m_s3_client is null !!!"); var presigned_url = await m_s3_client.GetPreSignedURLAsync(request); return (true, presigned_url); } catch (Exception e) { Log.getLogger().fatal($"Exception !!!, Failed to perform in generatePresignedUrl() : exception:{e}"); } return (false, string.Empty); } public async Task createBucketIfNotExist(string bucketName) { if (false == await isExistBucket(bucketName)) { var request = new PutBucketRequest { BucketName = bucketName, UseClientRegion = true, }; if (false == await createBucket(request)) { var err_msg = $"Failed to createBucket() !!! : bucketName:{bucketName}"; Log.getLogger().error(err_msg); return false; } } return true; } public async Task isExistBucket(string bucketName) { (var is_success, var buckets) = await getBuckets(); if (false == is_success) { return false; } foreach (var bucket in buckets) { if (bucket.BucketName == bucketName) return true; } return false; } public async Task tryUploadFile(string bucketName, string s3Key, string data) { var err_msg = string.Empty; using (var memory_stream = data.toStream()) { var request = new PutObjectRequest { BucketName = bucketName, Key = s3Key, InputStream = memory_stream, }; if (false == await uploadFile(request)) { err_msg = $"Failed to uploadFile() !!!, in tryUploadFile() : bucketName:{bucketName}, s3Key:{s3Key}"; Log.getLogger().error(err_msg); return false; } } return true; } public async Task tryDeleteFile(string bucketName, string s3Key) { var request = new DeleteObjectRequest { BucketName = bucketName, Key = s3Key, }; if (false == await deleteFile(request)) { var err_msg = $"Failed to deleteFile() !!!, in tryDeleteFile() : bucketName:{bucketName}, s3Key:{s3Key}"; Log.getLogger().error(err_msg); return false; } return true; } public async Task tryDeleteFolderFile(string bucketName, string prefix) { var request = new ListObjectsV2Request { BucketName = bucketName, Prefix = prefix, }; if (false == await deleteFolderFile(request)) { var err_msg = $"Failed to deleteFolderFile() !!!, in tryDeleteFolderFile() : bucketName:{bucketName}, prefix:{prefix}"; Log.getLogger().error(err_msg); return false; } return true; } public async Task<(bool, string)> tryGetFileData(string bucketName, string s3Key) { var request = new GetObjectRequest { BucketName = bucketName, Key = s3Key, }; (var is_success, var stream) = await getFileStream(request); if (false == is_success) { var err_msg = $"Failed to getFile() !!! - bucketName:{bucketName}, s3Key:{s3Key}"; Log.getLogger().error(err_msg); return (false, string.Empty); } NullReferenceCheckHelper.throwIfNull(stream, () => $"stream is null !!! - bucketName:{bucketName}, s3Key:{s3Key}"); return (true, stream.toString()); } public async Task<(bool, string)> getPresignedUrl( string bucketName, string s3Key , HttpVerb verbType, DateTime toExpireTime ) { var err_msg = string.Empty; var request = new GetPreSignedUrlRequest { BucketName = bucketName, Key = s3Key, Verb = verbType, Expires = toExpireTime }; (var is_success, var presigned_url) = await generatePreSignedUrl(request); if(false == is_success) { err_msg = $"Failed to generatePreSignedUrl() !!! : bucketName:{bucketName}, s3Key:{s3Key}, httpVerbType:{verbType}, toExpireTime:{toExpireTime.toStringWithUtcIso8601()}"; Log.getLogger().error(err_msg); return (false, presigned_url); } return (true, presigned_url); } public AmazonS3Client? getAmazonS3Client() => m_s3_client; public string toBasicString() { return $"{this.getTypeName()}, AccessKey:{m_access_key}, SecretKey:{m_secret_key}, Region:{m_region}"; } }