mirror of https://github.com/Squidex/squidex.git
7 changed files with 242 additions and 2 deletions
@ -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>(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue