Skip to content

Commit

Permalink
Merge pull request #6 from Shuttle/async
Browse files Browse the repository at this point in the history
Async
  • Loading branch information
eben-roux authored Apr 30, 2024
2 parents 75b0042 + 7bb7b4d commit 26145de
Show file tree
Hide file tree
Showing 17 changed files with 285 additions and 87 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,13 @@ services.AddCompression(builder => {
builder.AddNull();
});
```

## Usage

The `ICompressionService` can be injected into any class that requires compression services:

```c#
var algorithm = compressionService.Get("algorithm-name");
var compressed = await algorithm.CompressAsync(Encoding.UTF8.GetBytes("some data"));
var decompressed = await algorithm.DecompressAsync(compressed);
```
90 changes: 60 additions & 30 deletions Shuttle.Core.Compression.Tests/Fixture.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,76 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Shuttle.Core.Compression.Tests
namespace Shuttle.Core.Compression.Tests;

[TestFixture]
public class Fixture
{
[TestFixture]
public class Fixture
[Test]
public void Should_be_able_to_compress_and_decompress_using_gzip()
{
[Test]
public void Should_be_able_to_compress_and_decompress_using_gzip()
{
var algorithm = new GZipCompressionAlgorithm();
var algorithm = new GZipCompressionAlgorithm();

const string text = "gzip compression algorithm";

const string text = "gzip compression algorithm";
AssertAlgorithm(algorithm, text);
}

AssertAlgorithm(algorithm, text);
}
private static void AssertAlgorithm(ICompressionAlgorithm algorithm, string text)
{
Assert.AreEqual(text, Encoding.UTF8.GetString(algorithm.Decompress(algorithm.Compress(Encoding.UTF8.GetBytes(text)))));

private static void AssertAlgorithm(ICompressionAlgorithm algorithm, string text)
{
Assert.AreEqual(text,
Encoding.UTF8.GetString(algorithm.Decompress(algorithm.Compress(Encoding.UTF8.GetBytes(text)))));
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(text));
using var compressed = algorithm.Compress(stream);
using var decompressed = algorithm.Decompress(compressed);
using var decompressedStream = new MemoryStream();

using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
using (var compressed = algorithm.Compress(stream))
using (var decompressed = algorithm.Decompress(compressed))
using (var decompressedStream = new MemoryStream())
{
decompressed.CopyTo(decompressedStream);
decompressed.CopyTo(decompressedStream);

Assert.AreEqual(text, Encoding.UTF8.GetString(decompressedStream.ToArray()));
}
}
Assert.AreEqual(text, Encoding.UTF8.GetString(decompressedStream.ToArray()));
}

[Test]
public void Should_be_able_to_compress_and_decompress_using_deflate()
{
var algorithm = new DeflateCompressionAlgorithm();
[Test]
public void Should_be_able_to_compress_and_decompress_using_deflate()
{
var algorithm = new DeflateCompressionAlgorithm();

const string text = "deflate compression algorithm";

AssertAlgorithm(algorithm, text);
}

[Test]
public async Task Should_be_able_to_compress_and_decompress_using_gzip_async()
{
var algorithm = new GZipCompressionAlgorithm();

const string text = "gzip compression algorithm";

await AssertAlgorithmAsync(algorithm, text);
}

private static async Task AssertAlgorithmAsync(ICompressionAlgorithm algorithm, string text)
{
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(text));
await using var compressed = await algorithm.CompressAsync(stream);
await using var decompressed = await algorithm.DecompressAsync(compressed);
using var decompressedStream = new MemoryStream();

await decompressed.CopyToAsync(decompressedStream);

Assert.AreEqual(text, Encoding.UTF8.GetString(decompressedStream.ToArray()));
}

[Test]
public async Task Should_be_able_to_compress_and_decompress_using_deflate_async()
{
var algorithm = new DeflateCompressionAlgorithm();

const string text = "deflate compression algorithm";
const string text = "deflate compression algorithm";

AssertAlgorithm(algorithm, text);
}
await AssertAlgorithmAsync(algorithm, text);
}
}
4 changes: 2 additions & 2 deletions Shuttle.Core.Compression/.package/package.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<package>
<metadata>
<id>Shuttle.Core.Compression</id>
<version>11.0.1</version>
<version>12.0.0</version>
<authors>Eben Roux</authors>
<owners>Eben Roux</owners>
<license type="expression">BSD-3-Clause</license>
Expand All @@ -13,7 +13,7 @@
<repository type="git" url="https://github.com/shuttle/Shuttle.Core.Compression.git" />
<projectUrl>https://github.com/shuttle/Shuttle.Core.Compression</projectUrl>
<description>Compression adapter which includes GZip and Deflate implementations.</description>
<copyright>Copyright (c) 2022, Eben Roux</copyright>
<copyright>Copyright (c) 2024, Eben Roux</copyright>
<tags>compression gzip deflate</tags>
<dependencies>
<dependency id="Microsoft.Extensions.DependencyInjection" version="7.0.0" />
Expand Down
30 changes: 28 additions & 2 deletions Shuttle.Core.Compression/CompressionAlgorithmExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using Shuttle.Core.Contract;

namespace Shuttle.Core.Compression
Expand All @@ -9,25 +10,50 @@ public static Stream Compress(this ICompressionAlgorithm algorithm, Stream strea
{
Guard.AgainstNull(algorithm, nameof(algorithm));
Guard.AgainstNull(stream, nameof(stream));

using (var ms = new MemoryStream())
{
stream.CopyTo(ms);

return new MemoryStream(algorithm.Compress(ms.ToArray()));
}
}

public static Stream Decompress(this ICompressionAlgorithm algorithm, Stream stream)
{
Guard.AgainstNull(algorithm, nameof(algorithm));
Guard.AgainstNull(stream, nameof(stream));

using (var ms = new MemoryStream())
{
stream.CopyTo(ms);

return new MemoryStream(algorithm.Decompress(ms.ToArray()));
}
}

public static async Task<Stream> CompressAsync(this ICompressionAlgorithm algorithm, Stream stream)
{
Guard.AgainstNull(algorithm, nameof(algorithm));
Guard.AgainstNull(stream, nameof(stream));

using var ms = new MemoryStream();

await stream.CopyToAsync(ms).ConfigureAwait(false);

return new MemoryStream(await algorithm.CompressAsync(ms.ToArray()));
}

public static async Task<Stream> DecompressAsync(this ICompressionAlgorithm algorithm, Stream stream)
{
Guard.AgainstNull(algorithm, nameof(algorithm));
Guard.AgainstNull(stream, nameof(stream));

using var ms = new MemoryStream();

await stream.CopyToAsync(ms).ConfigureAwait(false);

return new MemoryStream(await algorithm.DecompressAsync(ms.ToArray()));
}
}
}
14 changes: 0 additions & 14 deletions Shuttle.Core.Compression/CompressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,6 @@ public CompressionBuilder(IServiceCollection services)

public IServiceCollection Services { get; }

public CompressionBuilder AddGzip()
{
Services.AddSingleton<ICompressionAlgorithm, GZipCompressionAlgorithm>();

return this;
}

public CompressionBuilder AddDeflate()
{
Services.AddSingleton<ICompressionAlgorithm, DeflateCompressionAlgorithm>();

return this;
}

public CompressionBuilder AddNull()
{
Services.AddSingleton<ICompressionAlgorithm, NullCompressionAlgorithm>();
Expand Down
17 changes: 7 additions & 10 deletions Shuttle.Core.Compression/CompressionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@ public CompressionService(IEnumerable<ICompressionAlgorithm> compressionAlgorith
}
}

public byte[] Compress(string name, byte[] bytes)
{
return Get(name).Compress(bytes);
}

public byte[] Decompress(string name, byte[] bytes)
{
return Get(name).Decompress(bytes);
}

public ICompressionService Add(ICompressionAlgorithm compressionAlgorithm)
{
Guard.AgainstNull(compressionAlgorithm, nameof(compressionAlgorithm));
Expand All @@ -53,5 +43,12 @@ public ICompressionAlgorithm Get(string name)

return _compressionAlgorithms[name];
}

public bool Contains(string name)
{
return _compressionAlgorithms.ContainsKey(Guard.AgainstNullOrEmptyString(name, nameof(name)));
}

public IEnumerable<ICompressionAlgorithm> Algorithms => _compressionAlgorithms.Values;
}
}
28 changes: 28 additions & 0 deletions Shuttle.Core.Compression/CompressionServiceExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Threading.Tasks;
using Shuttle.Core.Contract;

namespace Shuttle.Core.Compression
{
public static class CompressionServiceExtensions
{
public static byte[] Compress(this ICompressionService compressionService, string name, byte[] bytes)
{
return Guard.AgainstNull(compressionService, nameof(compressionService)).Get(name).Compress(bytes);
}

public static byte[] Decompress(this ICompressionService compressionService, string name, byte[] bytes)
{
return Guard.AgainstNull(compressionService, nameof(compressionService)).Get(name).Decompress(bytes);
}

public static async Task<byte[]> CompressAsync(this ICompressionService compressionService, string name, byte[] bytes)
{
return await Guard.AgainstNull(compressionService, nameof(compressionService)).Get(name).CompressAsync(bytes);
}

public static async Task<byte[]> DecompressAsync(this ICompressionService compressionService, string name, byte[] bytes)
{
return await Guard.AgainstNull(compressionService, nameof(compressionService)).Get(name).DecompressAsync(bytes);
}
}
}
60 changes: 48 additions & 12 deletions Shuttle.Core.Compression/DeflateCompressionAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
using Shuttle.Core.Contract;

namespace Shuttle.Core.Compression
Expand All @@ -9,32 +10,67 @@ public class DeflateCompressionAlgorithm : ICompressionAlgorithm
public string Name => "Deflate";

public byte[] Compress(byte[] bytes)
{
return CompressAsync(bytes, true).GetAwaiter().GetResult();
}

public byte[] Decompress(byte[] bytes)
{
return DecompressAsync(bytes, true).GetAwaiter().GetResult();
}

public async Task<byte[]> CompressAsync(byte[] bytes)
{
return await CompressAsync(bytes, false);
}

private static async Task<byte[]> CompressAsync(byte[] bytes, bool sync)
{
Guard.AgainstNull(bytes, nameof(bytes));

using (var compressed = MemoryStreamCache.Manager.GetStream())
{
using (var gzip = new DeflateStream(compressed, CompressionMode.Compress, true))
{
gzip.Write(bytes, 0, bytes.Length);
}
using var compressed = MemoryStreamCache.Manager.GetStream();
await using var deflate = new DeflateStream(compressed, CompressionMode.Compress, true);

return compressed.ToArray();
if (sync)
{
deflate.Write(bytes, 0, bytes.Length);
}
else
{
await deflate.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
}

deflate.Flush();

return compressed.ToArray();
}

public byte[] Decompress(byte[] bytes)
public async Task<byte[]> DecompressAsync(byte[] bytes)
{
return await DecompressAsync(bytes, false);
}

private static async Task<byte[]> DecompressAsync(byte[] bytes, bool sync)
{
Guard.AgainstNull(bytes, nameof(bytes));

using (var gzip = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress))
using var decompressed = MemoryStreamCache.Manager.GetStream();

var deflate = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);

await using (deflate.ConfigureAwait(false))
{
using (var decompressed = MemoryStreamCache.Manager.GetStream())
if (sync)
{
gzip.CopyTo(decompressed);
return decompressed.ToArray();
deflate.CopyTo(decompressed);
}
else
{
await deflate.CopyToAsync(decompressed).ConfigureAwait(false);
}
}

return decompressed.ToArray();
}
}
}
15 changes: 15 additions & 0 deletions Shuttle.Core.Compression/DeflateCompressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Shuttle.Core.Contract;

namespace Shuttle.Core.Compression
{
public static class DeflateCompressionExtensions
{
public static CompressionBuilder AddDeflate(this CompressionBuilder builder)
{
Guard.AgainstNull(builder, nameof(builder)).Services.AddSingleton<ICompressionAlgorithm, DeflateCompressionAlgorithm>();

return builder;
}
}
}
Loading

0 comments on commit 26145de

Please sign in to comment.