Browse Source

Example plugin with in-memory asset store.

pull/349/head
Sebastian Stehle 7 years ago
parent
commit
e037196e85
  1. 29
      extensions/Squidex.Extensions/Samples/MemoryAssetStorePlugin.cs
  2. 119
      src/Squidex.Infrastructure/Assets/MemoryAssetStore.cs
  3. 52
      src/Squidex.Infrastructure/Assets/NoopAssetStore.cs
  4. 4
      src/Squidex.Infrastructure/Configuration/ConfigurationExtensions.cs
  5. 5
      src/Squidex/Config/Domain/AssetServices.cs
  6. 31
      tests/Squidex.Infrastructure.Tests/Assets/MemoryAssetStoreTests.cs
  7. 4
      tests/Squidex.Infrastructure.Tests/Assets/MongoGridFsAssetStoreTests.cs

29
extensions/Squidex.Extensions/Samples/MemoryAssetStorePlugin.cs

@ -0,0 +1,29 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Plugins;
namespace Squidex.Extensions.Samples
{
public sealed class MemoryAssetStorePlugin : IPlugin
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
var storeType = configuration.GetValue<string>("assetStore:type");
if (string.Equals(storeType, "Memory", StringComparison.OrdinalIgnoreCase))
{
services.AddSingletonAs<MemoryAssetStore>()
.As<IAssetStore>();
}
}
}
}

119
src/Squidex.Infrastructure/Assets/MemoryAssetStore.cs

@ -0,0 +1,119 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.Assets
{
public sealed class MemoryAssetStore : IAssetStore
{
private readonly ConcurrentDictionary<string, MemoryStream> streams = new ConcurrentDictionary<string, MemoryStream>();
private readonly AsyncLock readerLock = new AsyncLock();
private readonly AsyncLock writerLock = new AsyncLock();
public string GeneratePublicUrl(string id, long version, string suffix)
{
return null;
}
public async Task CopyAsync(string sourceFileName, string id, long version, string suffix, CancellationToken ct = default)
{
Guard.NotNullOrEmpty(sourceFileName, nameof(sourceFileName));
Guard.NotNullOrEmpty(id, nameof(id));
if (!streams.TryGetValue(sourceFileName, out var sourceStream))
{
throw new AssetNotFoundException(sourceFileName);
}
using (await readerLock.LockAsync())
{
await UploadAsync(id, version, suffix, sourceStream, ct);
}
}
public async Task DownloadAsync(string id, long version, string suffix, Stream stream, CancellationToken ct = default)
{
Guard.NotNullOrEmpty(id, nameof(id));
var fileName = GetFileName(id, version, suffix);
if (!streams.TryGetValue(fileName, out var sourceStream))
{
throw new AssetNotFoundException(fileName);
}
using (await readerLock.LockAsync())
{
try
{
await sourceStream.CopyToAsync(stream, 81920, ct);
}
finally
{
sourceStream.Position = 0;
}
}
}
public Task UploadAsync(string id, long version, string suffix, Stream stream, CancellationToken ct = default)
{
Guard.NotNullOrEmpty(id, nameof(id));
return UploadAsync(GetFileName(id, version, suffix), stream, ct);
}
public async Task UploadAsync(string fileName, Stream stream, CancellationToken ct = default)
{
var memoryStream = new MemoryStream();
if (streams.TryAdd(fileName, memoryStream))
{
using (await writerLock.LockAsync())
{
try
{
await stream.CopyToAsync(memoryStream, 81920, ct);
}
finally
{
memoryStream.Position = 0;
}
}
}
else
{
throw new AssetAlreadyExistsException(fileName);
}
}
public Task DeleteAsync(string id, long version, string suffix)
{
Guard.NotNullOrEmpty(id, nameof(id));
return DeleteAsync(GetFileName(id, version, suffix));
}
public Task DeleteAsync(string fileName)
{
Guard.NotNullOrEmpty(fileName, nameof(fileName));
streams.TryRemove(fileName, out _);
return TaskHelper.Done;
}
private string GetFileName(string id, long version, string suffix)
{
return StringExtensions.JoinNonEmpty("_", id, version.ToString(), suffix);
}
}
}

52
src/Squidex.Infrastructure/Assets/NoopAssetStore.cs

@ -0,0 +1,52 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Squidex.Infrastructure.Assets
{
public sealed class NoopAssetStore : IAssetStore
{
public string GeneratePublicUrl(string id, long version, string suffix)
{
return null;
}
public Task CopyAsync(string sourceFileName, string id, long version, string suffix, CancellationToken ct = default)
{
throw new NotSupportedException();
}
public Task DownloadAsync(string id, long version, string suffix, Stream stream, CancellationToken ct = default)
{
throw new NotSupportedException();
}
public Task UploadAsync(string fileName, Stream stream, CancellationToken ct = default)
{
throw new NotSupportedException();
}
public Task UploadAsync(string id, long version, string suffix, Stream stream, CancellationToken ct = default)
{
throw new NotSupportedException();
}
public Task DeleteAsync(string fileName)
{
throw new NotSupportedException();
}
public Task DeleteAsync(string id, long version, string suffix)
{
throw new NotSupportedException();
}
}
}

4
src/Squidex.Infrastructure/Configuration/ConfigurationExtensions.cs

@ -54,6 +54,10 @@ namespace Microsoft.Extensions.Configuration
{ {
action(); action();
} }
else if (options.TryGetValue("default", out action))
{
action();
}
else else
{ {
throw new ConfigurationException($"Unsupported value '{value}' for '{path}', supported: {string.Join(" ", options.Keys)}."); throw new ConfigurationException($"Unsupported value '{value}' for '{path}', supported: {string.Join(" ", options.Keys)}.");

5
src/Squidex/Config/Domain/AssetServices.cs

@ -22,6 +22,11 @@ namespace Squidex.Config.Domain
{ {
config.ConfigureByOption("assetStore:type", new Options config.ConfigureByOption("assetStore:type", new Options
{ {
["Default"] = () =>
{
services.AddSingletonAs<NoopAssetStore>()
.AsOptional<IAssetStore>();
},
["Folder"] = () => ["Folder"] = () =>
{ {
var path = config.GetRequiredValue("assetStore:folder:path"); var path = config.GetRequiredValue("assetStore:folder:path");

31
tests/Squidex.Infrastructure.Tests/Assets/MemoryAssetStoreTests.cs

@ -0,0 +1,31 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Xunit;
namespace Squidex.Infrastructure.Assets
{
public class MemoryAssetStoreTests : AssetStoreTests<MemoryAssetStore>
{
public override MemoryAssetStore CreateStore()
{
return new MemoryAssetStore();
}
public override void Dispose()
{
}
[Fact]
public void Should_not_calculate_source_url()
{
var url = Sut.GeneratePublicUrl(AssetId, 1, null);
Assert.Null(url);
}
}
}

4
tests/Squidex.Infrastructure.Tests/Assets/MongoGridFsAssetStoreTests.cs

@ -13,11 +13,11 @@ using Xunit;
namespace Squidex.Infrastructure.Assets namespace Squidex.Infrastructure.Assets
{ {
internal class MongoGridFSAssetStoreTests : AssetStoreTests<MongoGridFsAssetStore> internal class MongoGridFsAssetStoreTests : AssetStoreTests<MongoGridFsAssetStore>
{ {
private static readonly IGridFSBucket<string> GridFSBucket; private static readonly IGridFSBucket<string> GridFSBucket;
static MongoGridFSAssetStoreTests() static MongoGridFsAssetStoreTests()
{ {
var mongoClient = new MongoClient("mongodb://localhost"); var mongoClient = new MongoClient("mongodb://localhost");
var mongoDatabase = mongoClient.GetDatabase("Test"); var mongoDatabase = mongoClient.GetDatabase("Test");

Loading…
Cancel
Save