Skip to content

Commit

Permalink
Merge branch 'main' of github.com:imazen/imageflow-dotnet-server into…
Browse files Browse the repository at this point in the history
… main
  • Loading branch information
lilith committed Mar 13, 2021
2 parents e8f7d23 + 5b5d32f commit 0c3736d
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 43 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/dotnet-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ jobs:
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x'
- run: dotnet clean --configuration Release
- run: dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ namespace Imageflow.Server.Example
// You can call AddImageflowS3Service multiple times for each unique access key
services.AddImageflowS3Service(new S3ServiceOptions( null,null)
.MapPrefix("/ri/", RegionEndpoint.USEast1, "resizer-images")
.MapPrefix("/imageflow-resources/", RegionEndpoint.USWest2, "imageflow-resources"));
.MapPrefix("/imageflow-resources/", RegionEndpoint.USWest2, "imageflow-resources")
.MapPrefix("/custom-s3client/", () => new AmazonS3Client(), "custom-client", "", false, false)
);

// Make Azure container available at /azure
// You can call AddImageflowAzureBlobService multiple times for each connection string
Expand Down Expand Up @@ -361,3 +363,9 @@ namespace Imageflow.Server.Example
* Blurring is not yet supported, so `a.blur` is ignored.
* ICC profiles are never ignored, so `ignoreicc` is ignored.
* 404 redirects are not implemented, so `404` is ignored.

## Integrations into Other Systems

The following platforms / solutions have a direct integration

1. **Oqtane Blazor platform** ([website](https://oqtane.org/) / [docs](https://docs.oqtane.org/) / [git](https://github.com/oqtane/oqtane.framework)): Use the **ToSic.ImageFlow.Oqtane** ([git](https://github.com/2sic/oqtane-imageflow) / [nuget](https://www.nuget.org/packages/ToSic.Imageflow.Oqtane/)) middleware. The package will automatically appear in Oqtane as an installable extension.
5 changes: 4 additions & 1 deletion examples/Imageflow.Server.Example/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
using Amazon.S3;
using Imageflow.Server.HybridCache;

namespace Imageflow.Server.Example
Expand Down Expand Up @@ -45,7 +46,9 @@ public void ConfigureServices(IServiceCollection services)
// You can call AddImageflowS3Service multiple times for each unique access key
services.AddImageflowS3Service(new S3ServiceOptions( null,null)
.MapPrefix("/ri/", RegionEndpoint.USEast1, "resizer-images")
.MapPrefix("/imageflow-resources/", RegionEndpoint.USWest2, "imageflow-resources"));
.MapPrefix("/imageflow-resources/", RegionEndpoint.USWest2, "imageflow-resources")
.MapPrefix("/custom-s3client/", () => new AmazonS3Client(), "custom-client", "", false, false)
);

// Make Azure container available at /azure
// You can call AddImageflowAzureBlobService multiple times for each connection string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
<Description>Imageflow.Server plugin for fetching source images from remote URLs.</Description>
<PackageVersion>0.1</PackageVersion>
</PropertyGroup>
<Import Project="..\NugetPackages.targets"/>

<ItemGroup>
<None Remove="README.md" />
</ItemGroup>
<Import Project="..\NugetPackages.targets" />

<ItemGroup>
<ProjectReference Include="..\Imageflow.Server\Imageflow.Server.csproj" />
Expand Down
23 changes: 23 additions & 0 deletions src/Imageflow.Server.Storage.RemoteReader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@
services.AddImageflowRemoteReaderService(remoteReaderServiceOptions);
```

## Usage

```c#
// The origin file
var remoteUrl = "https://imageflow-resources.s3-us-west-2.amazonaws.com/test_inputs/imazen_400.png";
// We encode it, but this doesn't add the /remote/ prefix since that is configurable
var encodedRemoteUrl = RemoteReaderService.EncodeAndSignUrl(remoteUrl, remoteReaderKey);
// Now we add the /remote/ prefix and add some commands
var modifiedUrl = $"/remote/{encodedRemoteUrl}?width=100";
```

If we are also doing request signing (a different signing key and purpose), we would use,
```c#
var signedModifiedUrl = Imazen.Common.Helpers.Signatures.SignRequest(modifiedUrl, requestSigningKey);

//This of course assumes that in Startup.cs you set requestSigningKey as one of the valid keys
app.UseImageflow(new ImageflowMiddlewareOptions()
.SetRequestSignatureOptions(
new RequestSignatureOptions(SignatureRequired.ForAllRequests,
new []{requestSigningKey})
));

```
## Add Custom Headers
To configure the client to send custom headers, we need to use an overload of `AddHttpClient()` that returns an `IHttpClientBuilder`.
```
Expand Down
3 changes: 2 additions & 1 deletion src/Imageflow.Server.Storage.S3/PrefixMapping.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using Amazon.S3;

namespace Imageflow.Server.Storage.S3
{
internal struct PrefixMapping
{
internal string Prefix;
internal AmazonS3Config Config;
internal Func<IAmazonS3> ClientFactory;
internal string Bucket;
internal string BlobPrefix;
internal bool IgnorePrefixCase;
Expand Down
14 changes: 1 addition & 13 deletions src/Imageflow.Server.Storage.S3/S3Service.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.Runtime;
using Amazon.S3;
using Imazen.Common.Storage;
using Microsoft.Extensions.Logging;
Expand All @@ -13,19 +12,8 @@ public class S3Service : IBlobProvider
{
private readonly List<PrefixMapping> mappings = new List<PrefixMapping>();

private readonly AWSCredentials credentials;
public S3Service(S3ServiceOptions options, ILogger<S3Service> logger)
{

if (options.AccessKeyId == null)
{
credentials = new AnonymousAWSCredentials();
}
else
{
credentials = new BasicAWSCredentials(options.AccessKeyId, options.SecretAccessKey);
}

foreach (var m in options.Mappings)
{
mappings.Add(m);;
Expand Down Expand Up @@ -66,7 +54,7 @@ public async Task<IBlobData> Fetch(string virtualPath)

try
{
using var client = new AmazonS3Client(credentials, mapping.Config);
using var client = mapping.ClientFactory();
var req = new Amazon.S3.Model.GetObjectRequest() { BucketName = mapping.Bucket, Key = key };

var s = await client.GetObjectAsync(req);
Expand Down
59 changes: 44 additions & 15 deletions src/Imageflow.Server.Storage.S3/S3ServiceOptions.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;

namespace Imageflow.Server.Storage.S3
{
public class S3ServiceOptions
{

internal readonly string AccessKeyId;
internal readonly string SecretAccessKey;
private readonly AWSCredentials credentials;
internal readonly List<PrefixMapping> Mappings = new List<PrefixMapping>();

public S3ServiceOptions()
{
credentials = new AnonymousAWSCredentials();
}

public S3ServiceOptions(AWSCredentials credentials)
{
this.credentials = credentials;
}

public S3ServiceOptions(string accessKeyId, string secretAccessKey)
{
this.AccessKeyId = accessKeyId;
this.SecretAccessKey = secretAccessKey;
credentials = accessKeyId == null
? (AWSCredentials) new AnonymousAWSCredentials()
: new BasicAWSCredentials(accessKeyId, secretAccessKey);
}

public S3ServiceOptions MapPrefix(string prefix, RegionEndpoint region, string bucket)
Expand All @@ -30,9 +39,9 @@ public S3ServiceOptions MapPrefix(string prefix, RegionEndpoint region, string b

public S3ServiceOptions MapPrefix(string prefix, RegionEndpoint region, string bucket, string blobPrefix,
bool ignorePrefixCase, bool lowercaseBlobPath)
=> MapPrefix(prefix, new AmazonS3Config() {RegionEndpoint = region}, bucket,
=> MapPrefix(prefix, new AmazonS3Config() { RegionEndpoint = region }, bucket,
blobPrefix, ignorePrefixCase, lowercaseBlobPath);

/// <summary>
/// Maps a given prefix to a specified location within a bucket
/// </summary>
Expand All @@ -46,7 +55,27 @@ public S3ServiceOptions MapPrefix(string prefix, RegionEndpoint region, string b
/// (requires that actual blobs all be lowercase).</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public S3ServiceOptions MapPrefix(string prefix, AmazonS3Config s3Config, string bucket, string blobPrefix, bool ignorePrefixCase, bool lowercaseBlobPath)
public S3ServiceOptions MapPrefix(string prefix, AmazonS3Config s3Config, string bucket, string blobPrefix,
bool ignorePrefixCase, bool lowercaseBlobPath)
{
Func<IAmazonS3> client = () => new AmazonS3Client(credentials, s3Config);
return MapPrefix(prefix, client, bucket, blobPrefix, ignorePrefixCase, lowercaseBlobPath);
}

/// <summary>
/// Maps a given prefix to a specified location within a bucket
/// </summary>
/// <param name="prefix">The prefix to capture image requests within</param>
/// <param name="s3ClientFactory">Lambda function to provide an instance of IAmazonS3, which will be disposed after use.</param>
/// <param name="bucket">The bucket to serve images from</param>
/// <param name="blobPrefix">The path within the bucket to serve images from. Can be an empty string to serve
/// from root of bucket.</param>
/// <param name="ignorePrefixCase">Whether to be cases sensitive about requests matching 'prefix'</param>
/// <param name="lowercaseBlobPath">Whether to lowercase all incoming paths to allow for case insensitivity
/// (requires that actual blobs all be lowercase).</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public S3ServiceOptions MapPrefix(string prefix, Func<IAmazonS3> s3ClientFactory, string bucket, string blobPrefix, bool ignorePrefixCase, bool lowercaseBlobPath)
{
prefix = prefix.TrimStart('/').TrimEnd('/');
if (prefix.Length == 0)
Expand All @@ -59,16 +88,16 @@ public S3ServiceOptions MapPrefix(string prefix, AmazonS3Config s3Config, string

Mappings.Add(new PrefixMapping()
{
Bucket=bucket,
Prefix=prefix,
Config=s3Config,
Bucket = bucket,
Prefix = prefix,
ClientFactory = s3ClientFactory,
BlobPrefix = blobPrefix,
IgnorePrefixCase = ignorePrefixCase,
LowercaseBlobPath = lowercaseBlobPath

});
return this;
}

}
}
4 changes: 2 additions & 2 deletions src/Imazen.HybridCache/HashBasedPathBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ public string GetRelativePathFromHash(byte[] hash)
//Start with the subfolder distribution in bits, so we can easily delete old folders
//When we change the subfolder size
sb.AppendFormat(NumberFormatInfo.InvariantInfo, "{0:D}",subfolderBits);
sb.Append(Path.DirectorySeparatorChar);
sb.Append(RelativeDirSeparator);
//If subfolders is set above 256, it will nest files in multiple directories, one for each byte
foreach (var b in allBits)
{
sb.AppendFormat(NumberFormatInfo.InvariantInfo, "{0:x2}",b);
sb.Append(Path.DirectorySeparatorChar);
sb.Append(RelativeDirSeparator);
}

sb.AppendFormat(NumberFormatInfo.InvariantInfo,
Expand Down
1 change: 1 addition & 0 deletions tests/Imageflow.Server.Tests/Imageflow.Server.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Imageflow.Server.DiskCache\Imageflow.Server.DiskCache.csproj" />
<ProjectReference Include="..\..\src\Imageflow.Server.Storage.AzureBlob\Imageflow.Server.Storage.AzureBlob.csproj" />
<ProjectReference Include="..\..\src\Imageflow.Server.Storage.RemoteReader\Imageflow.Server.Storage.RemoteReader.csproj" />
<ProjectReference Include="..\..\src\Imageflow.Server.Storage.S3\Imageflow.Server.Storage.S3.csproj" />
<ProjectReference Include="..\..\src\Imageflow.Server\Imageflow.Server.csproj" />
<ProjectReference Include="..\Imazen.Common.Tests\Imazen.Common.Tests.csproj" />
Expand Down
Loading

0 comments on commit 0c3736d

Please sign in to comment.