using Amazon.Runtime; using Amazon.S3; using Amazon.S3.Model; namespace qtc_api.Services.BucketService { public class BucketService : IBucketService { public string ServiceUrl { get; private set; } = string.Empty; public string AccessKey { get; private set; } = string.Empty; public string SecretKey { get; private set; } = string.Empty; public string ProfileImagesBucketName { get; private set; } = string.Empty; public string CDNBucketName { get; private set; } = string.Empty; public string ImagesBucketName { get; private set; } = string.Empty; private static AmazonS3Client S3Client = new(); private IConfiguration _config; private ILogger _logger; private bool Enabled { get; set; } public BucketService(IConfiguration config, ILogger logger) { _config = config; _logger = logger; var serviceUrl = _config["S3Config:S3ServiceUrl"]; var accessKey = _config["S3Config:S3AccessKey"]; var secretKey = _config["S3Config:S3SecretKey"]; var profileImagesBucket = _config["S3Config:S3ProfileImagesBucket"]; var cdnBucket = _config["S3Config:S3CDNBucket"]; var imagesBucket = _config["S3Config:S3ImagesBucket"]; var enabled = _config.GetValue("S3Config:S3Enabled"); if (serviceUrl != null) ServiceUrl = serviceUrl; if (accessKey != null) AccessKey = accessKey; if (secretKey != null) SecretKey = secretKey; if (profileImagesBucket != null) ProfileImagesBucketName = profileImagesBucket; if (cdnBucket != null) CDNBucketName = cdnBucket; if (imagesBucket != null) ImagesBucketName = imagesBucket; Enabled = enabled; var credentials = new BasicAWSCredentials(AccessKey, SecretKey); S3Client = new AmazonS3Client(credentials, new AmazonS3Config { ServiceURL = ServiceUrl, }); _logger = logger; } public async Task PutProfileImage(string userId, string imageName, byte[] imageBytes) { if (!Enabled) { _logger.LogWarning("Not Using S3 Bucket. Performance May Be Degraded."); return false; } try { using var stream = new MemoryStream(imageBytes); var request = new PutObjectRequest() { Key = $@"{userId}/{imageName}", BucketName = ProfileImagesBucketName, InputStream = stream, DisablePayloadSigning = true, DisableDefaultChecksumValidation = true }; var response = await S3Client.PutObjectAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK || response.HttpStatusCode == System.Net.HttpStatusCode.Accepted; } catch (AmazonS3Exception ex) { _logger.LogError($"S3 Bucket Threw An Exception\n{ex.Message}\n{ex.StackTrace}"); return false; } } public async Task GetProfileImageBytes(string userId, string imageName) { if (!Enabled) { _logger.LogWarning("Not Using S3 Bucket. Performance May Be Degraded."); return default; } try { var response = await S3Client.GetObjectAsync(ProfileImagesBucketName, $@"{userId}/{imageName}"); if (response != null) { using var stream = response.ResponseStream; using var ms = new MemoryStream(); stream.CopyTo(ms); return ms.ToArray(); } else return default; } catch (AmazonS3Exception ex) { _logger.LogError($"S3 Bucket Threw An Exception\n{ex.Message}\n{ex.StackTrace}"); return default; } } public async Task GetTagImageBytes(string tagName) { if (!Enabled) { _logger.LogWarning("Not Using S3 Bucket. Performance May Be Degraded."); return default; } try { var response = await S3Client.GetObjectAsync(CDNBucketName, $@"tags/{tagName}.png"); if (response != null) { using var stream = response.ResponseStream; using var ms = new MemoryStream(); stream.CopyTo(ms); return ms.ToArray(); } else return default; } catch (AmazonS3Exception ex) { _logger.LogError($"S3 Bucket Threw An Exception\n{ex.Message}\n{ex.StackTrace}"); return default; } } public async Task DeleteProfileImage(string userId, string imageName) { if (!Enabled) { _logger.LogWarning("Not Using S3 Bucket. Performance May Be Degraded."); return false; } try { var response = await S3Client.DeleteObjectAsync(ProfileImagesBucketName, $@"{userId}/{imageName}"); return response.HttpStatusCode == System.Net.HttpStatusCode.OK || response.HttpStatusCode == System.Net.HttpStatusCode.Accepted; } catch (AmazonS3Exception ex) { _logger.LogError($"S3 Bucket Threw An Exception\n{ex.Message}\n{ex.StackTrace}"); return false; } } } }