Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Added S3ClientProvider to AWSS3StorageCache and AWSS3StorageImageProvider #362

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ internal static class AmazonS3ClientFactory
/// with the same name does not already exist.
/// </summary>
/// <param name="options">The AWS S3 Storage cache options.</param>
/// <param name="serviceProvider">The current service provider.</param>
/// <returns>
/// A new <see cref="AmazonS3Client"/>.
/// </returns>
/// <exception cref="ArgumentException">Invalid configuration.</exception>
public static AmazonS3Client CreateClient(IAWSS3BucketClientOptions options)
public static AmazonS3Client CreateClient(IAWSS3BucketClientOptions options, IServiceProvider serviceProvider)
{
if (!string.IsNullOrWhiteSpace(options.Endpoint))
if (options.S3ClientProvider != null)
{
return options.S3ClientProvider(options, serviceProvider);
}
else if (!string.IsNullOrWhiteSpace(options.Endpoint))
{
// AccessKey can be empty.
// AccessSecret can be empty.
Expand Down
16 changes: 10 additions & 6 deletions src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ public class AWSS3StorageCache : IImageCache
/// Initializes a new instance of the <see cref="AWSS3StorageCache"/> class.
/// </summary>
/// <param name="cacheOptions">The cache options.</param>
public AWSS3StorageCache(IOptions<AWSS3StorageCacheOptions> cacheOptions)
/// <param name="serviceProvider">The current service provider.</param>
public AWSS3StorageCache(IOptions<AWSS3StorageCacheOptions> cacheOptions, IServiceProvider serviceProvider)
{
Guard.NotNull(cacheOptions, nameof(cacheOptions));
AWSS3StorageCacheOptions options = cacheOptions.Value;
this.bucketName = options.BucketName;
this.amazonS3Client = AmazonS3ClientFactory.CreateClient(options);
this.amazonS3Client = AmazonS3ClientFactory.CreateClient(options, serviceProvider);
this.cacheFolder = string.IsNullOrEmpty(options.CacheFolder)
? string.Empty
: options.CacheFolder.Trim().Trim('/') + '/';
Expand Down Expand Up @@ -82,20 +83,23 @@ public Task SetAsync(string key, Stream stream, ImageCacheMetadata metadata)
/// and object data. <see cref="S3CannedACL.Private"/> specifies that the bucket
/// data is private to the account owner.
/// </param>
/// <param name="serviceProvider">The current service provider.</param>
/// <returns>
/// If the bucket does not already exist, a <see cref="PutBucketResponse"/> describing the newly
/// created bucket. If the container already exists, <see langword="null"/>.
/// </returns>
public static PutBucketResponse? CreateIfNotExists(
AWSS3StorageCacheOptions options,
S3CannedACL acl)
=> AsyncHelper.RunSync(() => CreateIfNotExistsAsync(options, acl));
S3CannedACL acl,
IServiceProvider serviceProvider)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is a breaking change, because it requires users of this method to add the serviceProvider param.

=> AsyncHelper.RunSync(() => CreateIfNotExistsAsync(options, acl, serviceProvider));

private static async Task<PutBucketResponse?> CreateIfNotExistsAsync(
AWSS3StorageCacheOptions options,
S3CannedACL acl)
S3CannedACL acl,
IServiceProvider serviceProvider)
{
AmazonS3Client client = AmazonS3ClientFactory.CreateClient(options);
AmazonS3Client client = AmazonS3ClientFactory.CreateClient(options, serviceProvider);

bool foundBucket = false;
ListBucketsResponse listBucketsResponse = await client.ListBucketsAsync();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using Amazon.S3;

namespace SixLabors.ImageSharp.Web.Caching.AWS;

/// <summary>
/// Configuration options for the <see cref="AWSS3StorageCache"/> provider.
/// </summary>
public class AWSS3StorageCacheOptions : IAWSS3BucketClientOptions
{
/// <inheritdoc/>
public Func<IAWSS3BucketClientOptions, IServiceProvider, AmazonS3Client>? S3ClientProvider { get; set; } = null!;

/// <inheritdoc/>
public string? Region { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using Amazon.S3;

namespace SixLabors.ImageSharp.Web;

/// <summary>
/// Provides a common interface for AWS S3 Bucket Client Options.
/// </summary>
internal interface IAWSS3BucketClientOptions
public interface IAWSS3BucketClientOptions
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to make the internal interface public here, because it is used as a param of the S3ClientProvider.

{
/// <summary>
/// Gets or sets a custom Azure AmazonS3Client provider
/// </summary>
Func<IAWSS3BucketClientOptions, IServiceProvider, AmazonS3Client>? S3ClientProvider { get; set; }

/// <summary>
/// Gets or sets the AWS region endpoint (us-east-1/us-west-1/ap-southeast-2).
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ private readonly Dictionary<string, AmazonS3Client> buckets
/// </summary>
/// <param name="storageOptions">The S3 storage options</param>
/// <param name="formatUtilities">Contains various format helper methods based on the current configuration.</param>
public AWSS3StorageImageProvider(IOptions<AWSS3StorageImageProviderOptions> storageOptions, FormatUtilities formatUtilities)
/// <param name="serviceProvider">The current service provider.</param>
public AWSS3StorageImageProvider(IOptions<AWSS3StorageImageProviderOptions> storageOptions, FormatUtilities formatUtilities, IServiceProvider serviceProvider)
{
Guard.NotNull(storageOptions, nameof(storageOptions));

Expand All @@ -50,7 +51,7 @@ public AWSS3StorageImageProvider(IOptions<AWSS3StorageImageProviderOptions> stor

foreach (AWSS3BucketClientOptions bucket in this.storageOptions.S3Buckets)
{
this.buckets.Add(bucket.BucketName, AmazonS3ClientFactory.CreateClient(bucket));
this.buckets.Add(bucket.BucketName, AmazonS3ClientFactory.CreateClient(bucket, serviceProvider));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using Amazon.S3;

namespace SixLabors.ImageSharp.Web.Providers.AWS;

/// <summary>
Expand All @@ -19,6 +21,9 @@ public class AWSS3StorageImageProviderOptions
/// </summary>
public class AWSS3BucketClientOptions : IAWSS3BucketClientOptions
{
/// <inheritdoc/>
public Func<IAWSS3BucketClientOptions, IServiceProvider, AmazonS3Client>? S3ClientProvider { get; set; } = null!;

/// <inheritdoc/>
public string? Region { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override void ConfigureCustomServices(IServiceCollection services, IIm
o.Timeout = TestConstants.AWSTimeout;
o.CacheFolder = TestConstants.AWSCacheFolder;

AWSS3StorageCache.CreateIfNotExists(o, S3CannedACL.Private);
AWSS3StorageCache.CreateIfNotExists(o, S3CannedACL.Private, services.BuildServiceProvider());
})
.SetCache<AWSS3StorageCache>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected override void ConfigureCustomServices(IServiceCollection services, IIm
o.Region = TestConstants.AWSRegion;
o.Timeout = TestConstants.AWSTimeout;

AWSS3StorageCache.CreateIfNotExists(o, S3CannedACL.Private);
AWSS3StorageCache.CreateIfNotExists(o, S3CannedACL.Private, services.BuildServiceProvider());
})
.SetCache<AWSS3StorageCache>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ public static AWSS3StorageImageProvider Create(IServiceProvider services)
FormatUtilities utilities = services.GetRequiredService<FormatUtilities>();
AsyncHelper.RunSync(() => InitializeAWSStorageAsync(services, options.Value));

return new AWSS3StorageImageProvider(options, utilities);
return new AWSS3StorageImageProvider(options, utilities, services);
}

private static async Task InitializeAWSStorageAsync(IServiceProvider services, AWSS3StorageImageProviderOptions options)
{
// Upload an image to the AWS Test Storage;
AWSS3BucketClientOptions bucketOptions = options.S3Buckets.First();
AmazonS3Client amazonS3Client = AmazonS3ClientFactory.CreateClient(bucketOptions);
AmazonS3Client amazonS3Client = AmazonS3ClientFactory.CreateClient(bucketOptions, services);
ListBucketsResponse listBucketsResponse = await amazonS3Client.ListBucketsAsync();

bool foundBucket = false;
Expand Down
Loading