mirror of https://github.com/Squidex/squidex.git
17 changed files with 317 additions and 58 deletions
@ -0,0 +1,90 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GoogleCloudAssetStore.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Net; |
||||
|
using System.Threading.Tasks; |
||||
|
using Google; |
||||
|
using Google.Cloud.Storage.V1; |
||||
|
using Squidex.Infrastructure.Assets; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.GoogleCloud |
||||
|
{ |
||||
|
public sealed class GoogleCloudAssetStore : IAssetStore, IExternalSystem |
||||
|
{ |
||||
|
private readonly string bucketName; |
||||
|
private StorageClient storageClient; |
||||
|
|
||||
|
public GoogleCloudAssetStore(string bucketName) |
||||
|
{ |
||||
|
Guard.NotNullOrEmpty(bucketName, nameof(bucketName)); |
||||
|
|
||||
|
this.bucketName = bucketName; |
||||
|
} |
||||
|
|
||||
|
public void Connect() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
storageClient = StorageClient.Create(); |
||||
|
|
||||
|
storageClient.GetBucket(bucketName); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new ConfigurationException($"Cannot connect to google cloud bucket '${bucketName}'.", ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task DownloadAsync(Guid id, long version, string suffix, Stream stream) |
||||
|
{ |
||||
|
var objectName = GetObjectName(id, version, suffix); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
await storageClient.DownloadObjectAsync(bucketName, objectName, stream); |
||||
|
} |
||||
|
catch (GoogleApiException ex) |
||||
|
{ |
||||
|
if (ex.HttpStatusCode == HttpStatusCode.NotFound) |
||||
|
{ |
||||
|
throw new AssetNotFoundException($"Asset {id}, {version} not found.", ex); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task UploadAsync(Guid id, long version, string suffix, Stream stream) |
||||
|
{ |
||||
|
var objectName = GetObjectName(id, version, suffix); |
||||
|
|
||||
|
await storageClient.UploadObjectAsync(bucketName, objectName, "application/octet-stream", stream); |
||||
|
} |
||||
|
|
||||
|
private string GetObjectName(Guid id, long version, string suffix) |
||||
|
{ |
||||
|
if (storageClient == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException("No connection established yet."); |
||||
|
} |
||||
|
|
||||
|
var name = $"{id}_{version}"; |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(suffix)) |
||||
|
{ |
||||
|
name += "_" + suffix; |
||||
|
} |
||||
|
|
||||
|
return name; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard1.6</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
||||
|
<DebugType>full</DebugType> |
||||
|
<DebugSymbols>True</DebugSymbols> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Google.Cloud.Storage.V1" Version="1.0.0" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,29 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetNotFoundException.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Assets |
||||
|
{ |
||||
|
public class AssetNotFoundException : Exception |
||||
|
{ |
||||
|
public AssetNotFoundException() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public AssetNotFoundException(string message) |
||||
|
: base(message) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public AssetNotFoundException(string message, Exception inner) |
||||
|
: base(message, inner) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileCallbackResult.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace Squidex.Pipeline |
||||
|
{ |
||||
|
public class FileCallbackResult : FileResult |
||||
|
{ |
||||
|
private readonly Func<Stream, Task> callback; |
||||
|
|
||||
|
public Func<Stream, Task> Callback |
||||
|
{ |
||||
|
get { return callback; } |
||||
|
} |
||||
|
|
||||
|
public FileCallbackResult(string contentType, string name, Func<Stream, Task> callback) |
||||
|
: base(contentType) |
||||
|
{ |
||||
|
FileDownloadName = name; |
||||
|
|
||||
|
this.callback = callback; |
||||
|
} |
||||
|
|
||||
|
public override Task ExecuteResultAsync(ActionContext context) |
||||
|
{ |
||||
|
var executor = context.HttpContext.RequestServices.GetRequiredService<FileCallbackResultExecutor>(); |
||||
|
|
||||
|
return executor.ExecuteAsync(context, this); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#pragma warning restore 1573
|
||||
@ -0,0 +1,38 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileCallbackResultExecutor.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.Internal; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace Squidex.Pipeline |
||||
|
{ |
||||
|
public sealed class FileCallbackResultExecutor : FileResultExecutorBase |
||||
|
{ |
||||
|
public FileCallbackResultExecutor(ILoggerFactory loggerFactory) |
||||
|
: base(CreateLogger<VirtualFileResultExecutor>(loggerFactory)) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async Task ExecuteAsync(ActionContext context, FileCallbackResult result) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
SetHeadersAndLog(context, result); |
||||
|
|
||||
|
await result.Callback(context.HttpContext.Response.Body); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
context.HttpContext.Response.Headers.Clear(); |
||||
|
context.HttpContext.Response.StatusCode = 404; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue