Skip to content

Commit 8335068

Browse files
committed
Add generic client
1 parent d692cfd commit 8335068

13 files changed

+456
-0
lines changed

SimpleS3.sln

+28
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{DA
152152
Locals\Directory.Packages.props = Locals\Directory.Packages.props
153153
EndProjectSection
154154
EndProject
155+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleS3.Extensions.GenericS3", "Src\SimpleS3.Extensions.GenericS3\SimpleS3.Extensions.GenericS3.csproj", "{A422752D-C1D5-424F-AD60-BEBF8AC79696}"
156+
EndProject
157+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleS3.Extensions.GenericS3.Tests", "Src\SimpleS3.Extensions.GenericS3.Tests\SimpleS3.Extensions.GenericS3.Tests.csproj", "{5FF368E5-5A93-43BC-A9C4-961542A505D0}"
158+
EndProject
159+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleS3.GenericS3", "Src\SimpleS3.GenericS3\SimpleS3.GenericS3.csproj", "{BEC8E6BB-13EA-4C4E-B7F8-11F842042562}"
160+
EndProject
161+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleS3.GenericS3.Tests", "Src\SimpleS3.GenericS3.Tests\SimpleS3.GenericS3.Tests.csproj", "{1C4C5566-36B0-49F6-950D-C4112B73E0D6}"
162+
EndProject
155163
Global
156164
GlobalSection(SolutionConfigurationPlatforms) = preSolution
157165
Debug|Any CPU = Debug|Any CPU
@@ -298,6 +306,22 @@ Global
298306
{B382C7E1-AE72-4693-AC75-2B15C9D6AD10}.Debug|Any CPU.Build.0 = Debug|Any CPU
299307
{B382C7E1-AE72-4693-AC75-2B15C9D6AD10}.Release|Any CPU.ActiveCfg = Release|Any CPU
300308
{B382C7E1-AE72-4693-AC75-2B15C9D6AD10}.Release|Any CPU.Build.0 = Release|Any CPU
309+
{A422752D-C1D5-424F-AD60-BEBF8AC79696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
310+
{A422752D-C1D5-424F-AD60-BEBF8AC79696}.Debug|Any CPU.Build.0 = Debug|Any CPU
311+
{A422752D-C1D5-424F-AD60-BEBF8AC79696}.Release|Any CPU.ActiveCfg = Release|Any CPU
312+
{A422752D-C1D5-424F-AD60-BEBF8AC79696}.Release|Any CPU.Build.0 = Release|Any CPU
313+
{5FF368E5-5A93-43BC-A9C4-961542A505D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
314+
{5FF368E5-5A93-43BC-A9C4-961542A505D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
315+
{5FF368E5-5A93-43BC-A9C4-961542A505D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
316+
{5FF368E5-5A93-43BC-A9C4-961542A505D0}.Release|Any CPU.Build.0 = Release|Any CPU
317+
{BEC8E6BB-13EA-4C4E-B7F8-11F842042562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
318+
{BEC8E6BB-13EA-4C4E-B7F8-11F842042562}.Debug|Any CPU.Build.0 = Debug|Any CPU
319+
{BEC8E6BB-13EA-4C4E-B7F8-11F842042562}.Release|Any CPU.ActiveCfg = Release|Any CPU
320+
{BEC8E6BB-13EA-4C4E-B7F8-11F842042562}.Release|Any CPU.Build.0 = Release|Any CPU
321+
{1C4C5566-36B0-49F6-950D-C4112B73E0D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
322+
{1C4C5566-36B0-49F6-950D-C4112B73E0D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
323+
{1C4C5566-36B0-49F6-950D-C4112B73E0D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
324+
{1C4C5566-36B0-49F6-950D-C4112B73E0D6}.Release|Any CPU.Build.0 = Release|Any CPU
301325
EndGlobalSection
302326
GlobalSection(SolutionProperties) = preSolution
303327
HideSolutionNode = FALSE
@@ -337,6 +361,10 @@ Global
337361
{42708EFE-D307-407D-BF8F-51554F52207F} = {62F2C837-5670-4C27-9609-90F8B67BEC8E}
338362
{48AE12D0-60CD-40E7-8C5C-883B68322396} = {42708EFE-D307-407D-BF8F-51554F52207F}
339363
{DADE79C3-616F-4EDB-87EA-0558DD9EDBB7} = {42708EFE-D307-407D-BF8F-51554F52207F}
364+
{A422752D-C1D5-424F-AD60-BEBF8AC79696} = {5F231AF0-BA65-4AE0-959F-A29E76CC6DFD}
365+
{5FF368E5-5A93-43BC-A9C4-961542A505D0} = {5F231AF0-BA65-4AE0-959F-A29E76CC6DFD}
366+
{BEC8E6BB-13EA-4C4E-B7F8-11F842042562} = {E0B7243F-9495-459C-9108-2B422C2BA546}
367+
{1C4C5566-36B0-49F6-950D-C4112B73E0D6} = {E0B7243F-9495-459C-9108-2B422C2BA546}
340368
EndGlobalSection
341369
GlobalSection(ExtensibilityGlobals) = postSolution
342370
SolutionGuid = {5EB716AC-1004-4514-8045-DAFF9636F0C5}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Genbox.SimpleS3.Core.Abstracts.Enums;
2+
3+
namespace Genbox.SimpleS3.Extensions.GenericS3.Tests;
4+
5+
public class GenericS3InputValidatorTests
6+
{
7+
private readonly GenericS3InputValidator _validator;
8+
9+
public GenericS3InputValidatorTests()
10+
{
11+
_validator = new GenericS3InputValidator();
12+
}
13+
14+
[Fact]
15+
public void TryValidateKeyIdTest()
16+
{
17+
_validator.TryValidateKeyId("<something1random>", out ValidationStatus status, out _);
18+
Assert.Equal(ValidationStatus.Ok, status);
19+
}
20+
21+
[Fact]
22+
public void TryValidateAccessKeyTest()
23+
{
24+
_validator.TryValidateAccessKey(new byte[] { 1, 2, 3 }, out ValidationStatus status, out _);
25+
Assert.Equal(ValidationStatus.Ok, status);
26+
}
27+
28+
[Fact]
29+
public void TryValidateBucketNameTest()
30+
{
31+
_validator.TryValidateBucketName("<something1random>", BucketNameValidationMode.Default, out ValidationStatus status, out _);
32+
Assert.Equal(ValidationStatus.Ok, status);
33+
}
34+
35+
[Fact]
36+
public void TryValidateObjectKeyTest()
37+
{
38+
_validator.TryValidateObjectKey("<something1random>", ObjectKeyValidationMode.Default, out ValidationStatus status, out _);
39+
Assert.Equal(ValidationStatus.Ok, status);
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Genbox.SimpleS3.Core.Abstracts;
2+
using Genbox.SimpleS3.Core.Abstracts.Provider;
3+
using Genbox.SimpleS3.Core.Abstracts.Region;
4+
using Genbox.SimpleS3.Core.Common.Extensions;
5+
using Genbox.SimpleS3.Core.Common.Helpers;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Options;
8+
9+
namespace Genbox.SimpleS3.Extensions.GenericS3.Extensions;
10+
11+
public static class CoreBuilderExtensions
12+
{
13+
public static ICoreBuilder UseGenericS3(this ICoreBuilder clientBuilder, Action<GenericS3Config> config)
14+
{
15+
return UseGenericS3(clientBuilder, (s3Config, _) => config.Invoke(s3Config));
16+
}
17+
18+
public static ICoreBuilder UseGenericS3(this ICoreBuilder clientBuilder, Action<GenericS3Config, IServiceProvider> config)
19+
{
20+
clientBuilder.Services.Configure(config);
21+
22+
return UseAmazonS3(clientBuilder);
23+
}
24+
25+
public static ICoreBuilder UseAmazonS3(this ICoreBuilder clientBuilder)
26+
{
27+
clientBuilder.Services.AddSingleton<IInputValidator, GenericS3InputValidator>();
28+
29+
clientBuilder.Services.PostConfigure<SimpleS3Config>((x, y) =>
30+
{
31+
IOptions<GenericS3Config> awsCfg = y.GetRequiredService<IOptions<GenericS3Config>>();
32+
PropertyHelper.MapObjects(awsCfg.Value, x);
33+
});
34+
35+
return clientBuilder;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Genbox.SimpleS3.Core.Abstracts;
2+
using Genbox.SimpleS3.Core.Abstracts.Authentication;
3+
using Genbox.SimpleS3.Core.Common.Authentication;
4+
5+
namespace Genbox.SimpleS3.Extensions.GenericS3;
6+
7+
public class GenericS3Config : SimpleS3Config
8+
{
9+
public GenericS3Config()
10+
{
11+
ProviderName = "GenericS3";
12+
}
13+
14+
public GenericS3Config(string keyId, string secretKey, string endpoint, string regionCode) : this(new StringAccessKey(keyId, secretKey), endpoint, regionCode) {}
15+
16+
public GenericS3Config(IAccessKey credentials, string endpoint, string regionCode) : this()
17+
{
18+
Credentials = credentials;
19+
Endpoint = new Uri(endpoint);
20+
RegionCode = regionCode;
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Genbox.SimpleS3.Core.Abstracts.Enums;
2+
using Genbox.SimpleS3.Core.Common.Validation;
3+
4+
namespace Genbox.SimpleS3.Extensions.GenericS3;
5+
6+
public class GenericS3InputValidator : InputValidatorBase
7+
{
8+
protected override bool TryValidateKeyIdInternal(string keyId, out ValidationStatus status, out string? message)
9+
{
10+
status = ValidationStatus.Ok;
11+
message = null;
12+
return true;
13+
}
14+
15+
protected override bool TryValidateAccessKeyInternal(byte[] accessKey, out ValidationStatus status, out string? message)
16+
{
17+
status = ValidationStatus.Ok;
18+
message = null;
19+
return true;
20+
}
21+
22+
protected override bool TryValidateBucketNameInternal(string bucketName, BucketNameValidationMode mode, out ValidationStatus status, out string? message)
23+
{
24+
status = ValidationStatus.Ok;
25+
message = null;
26+
return true;
27+
}
28+
29+
protected override bool TryValidateObjectKeyInternal(string objectKey, ObjectKeyValidationMode mode, out ValidationStatus status, out string? message)
30+
{
31+
status = ValidationStatus.Ok;
32+
message = null;
33+
return true;
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# SimpleS3.Extensions.GenericS3
2+
3+
This extension supports any generic S3 endpoint. It does not provide any input validation as it is unknown what the generic endpoint would support.
4+
If the endpoint you want to use is a close match to AmazonS3, then use SimpleS3.AmazonS3 instead.
5+
6+
To use it, add a reference to [Genbox.SimpleS3.Extensions.GenericS3](https://www.nuget.org/packages/Genbox.SimpleS3.Extensions.GenericS3)
7+
8+
### Using Microsoft.Extensions.DependencyInjection
9+
10+
If you are using [Microsoft's dependency injection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/) (recommended), then you can use it like so:
11+
12+
```csharp
13+
ServiceCollection services = new ServiceCollection();
14+
ICoreBuilder coreBuilder = SimpleS3CoreServices.AddSimpleS3Core(services);
15+
IHttpClientBuilder httpBuilder = coreBuilder.UseHttpClientFactory();
16+
17+
coreBuilder.UseGenericS3(config =>
18+
{
19+
config.Endpoint = new Uri("https://myendpoint.com");
20+
config.RegionCode = "us-east-1";
21+
config.Credentials = new StringAccessKey("key id here", "access key here");
22+
});
23+
24+
IServiceProvider serviceProvider = services.BuildServiceProvider();
25+
IObjectClient objectClient = serviceProvider.GetRequiredService<IObjectClient>();
26+
```
27+
28+
You can now use the `objectClient` to work with objects.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Import Project="..\..\Imports\Library.props" />
4+
5+
<ItemGroup>
6+
<ProjectReference Include="..\SimpleS3.Core.Common\SimpleS3.Core.Common.csproj" />
7+
</ItemGroup>
8+
9+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<ItemGroup>
4+
<ProjectReference Include="..\SimpleS3.GenericS3\SimpleS3.GenericS3.csproj" />
5+
</ItemGroup>
6+
7+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Genbox.SimpleS3.Core.Common.Authentication;
2+
using Genbox.SimpleS3.Core.TestBase.Code;
3+
using Genbox.SimpleS3.Extensions.GenericS3;
4+
5+
namespace Genbox.SimpleS3.GenericS3.Tests;
6+
7+
public class StaticCreatorTests
8+
{
9+
[Fact]
10+
public async Task StaticClient()
11+
{
12+
NullNetworkDriver driver = new NullNetworkDriver();
13+
14+
GenericS3Config config = new GenericS3Config();
15+
config.Credentials = new StringAccessKey("ExampleKeyId00000000", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY");
16+
config.Endpoint = new Uri("https://myendpoint.com");
17+
config.RegionCode = "us-east-1";
18+
19+
using GenericS3Client client = new GenericS3Client(config, driver);
20+
21+
await client.GetObjectAsync("testbucket", "GetObjectAsync").ConfigureAwait(false);
22+
Assert.Equal("https://myendpoint.com/GetObjectAsync", driver.LastUrl);
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using Genbox.SimpleS3.Core.Abstracts;
2+
using Genbox.SimpleS3.Core.Abstracts.Clients;
3+
using Genbox.SimpleS3.Core.Abstracts.Transfer;
4+
using Genbox.SimpleS3.Core.Common.Extensions;
5+
using Genbox.SimpleS3.Core.Extensions;
6+
using Genbox.SimpleS3.Extensions.GenericS3;
7+
using Genbox.SimpleS3.Extensions.GenericS3.Extensions;
8+
using Genbox.SimpleS3.Extensions.HttpClientFactory.Extensions;
9+
using Genbox.SimpleS3.Extensions.HttpClientFactory.Polly.Extensions;
10+
using Genbox.SimpleS3.ProviderBase;
11+
using Genbox.SimpleS3.ProviderBase.Abstracts;
12+
using Microsoft.Extensions.DependencyInjection;
13+
14+
namespace Genbox.SimpleS3.GenericS3.Extensions;
15+
16+
public static class ServiceCollectionExtensions
17+
{
18+
/// <summary>Add SimpleS3 services to a service collection.</summary>
19+
/// <param name="collection">The service collection</param>
20+
/// <param name="config">The configuration delegate</param>
21+
public static IClientBuilder AddGenericS3(this IServiceCollection collection, Action<GenericS3Config, IServiceProvider> config)
22+
{
23+
collection.Configure(config);
24+
return AddGenericS3(collection);
25+
}
26+
27+
/// <summary>Add SimpleS3 services to a service collection.</summary>
28+
/// <param name="collection">The service collection</param>
29+
/// <param name="config">The configuration delegate</param>
30+
public static IClientBuilder AddGenericS3(this IServiceCollection collection, Action<GenericS3Config> config)
31+
{
32+
collection.Configure(config);
33+
return AddGenericS3(collection);
34+
}
35+
36+
/// <summary>Add SimpleS3 services to a service collection.</summary>
37+
/// <param name="collection">The service collection</param>
38+
public static IClientBuilder AddGenericS3(this IServiceCollection collection)
39+
{
40+
ICoreBuilder coreBuilder = SimpleS3CoreServices.AddSimpleS3Core(collection);
41+
coreBuilder.UseAmazonS3();
42+
43+
IHttpClientBuilder httpBuilder = coreBuilder.UseHttpClientFactory();
44+
httpBuilder.UseRetryAndTimeout();
45+
46+
coreBuilder.Services.AddSingleton(x =>
47+
{
48+
//We have to call a specific constructor for dependency injection
49+
IObjectClient objectClient = x.GetRequiredService<IObjectClient>();
50+
IBucketClient bucketClient = x.GetRequiredService<IBucketClient>();
51+
IMultipartClient multipartClient = x.GetRequiredService<IMultipartClient>();
52+
IMultipartTransfer multipartTransfer = x.GetRequiredService<IMultipartTransfer>();
53+
ITransfer transfer = x.GetRequiredService<ITransfer>();
54+
ISignedObjectClient signedObjectClient = x.GetRequiredService<ISignedObjectClient>();
55+
return new GenericS3Client(objectClient, bucketClient, multipartClient, multipartTransfer, transfer, signedObjectClient);
56+
});
57+
58+
//Add the client as the interface too
59+
coreBuilder.Services.AddSingleton<ISimpleClient>(x => x.GetRequiredService<GenericS3Client>());
60+
61+
return new ClientBuilder(collection, httpBuilder, coreBuilder);
62+
}
63+
}

0 commit comments

Comments
 (0)