Пример #1
0
 public static async Task <string> GetTextAsync(this AssetRef asset, string?encoding,
                                                IAssetFileStore assetFileStore,
                                                CancellationToken ct = default)
 {
     using (var stream = DefaultPools.MemoryStream.GetStream())
     {
         await assetFileStore.DownloadAsync(asset.AppId, asset.Id, asset.FileVersion, null, stream, default, ct);
Пример #2
0
        public static async Task <string> GetTextAsync(this IAssetFileStore assetFileStore, DomainId appId, DomainId id, long fileVersion, string?encoding)
        {
            using (var stream = DefaultPools.MemoryStream.GetStream())
            {
                await assetFileStore.DownloadAsync(appId, id, fileVersion, null, stream);

                stream.Position = 0;

                var bytes = stream.ToArray();

                switch (encoding?.ToLowerInvariant())
                {
                case "base64":
                    return(Convert.ToBase64String(bytes));

                case "ascii":
                    return(Encoding.ASCII.GetString(bytes));

                case "unicode":
                    return(Encoding.Unicode.GetString(bytes));

                default:
                    return(Encoding.UTF8.GetString(bytes));
                }
            }
        }
Пример #3
0
 private Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer)
 {
     return(writer.WriteBlobAsync(GetName(assetId, fileVersion), stream =>
     {
         return assetFileStore.DownloadAsync(appId, assetId, fileVersion, stream);
     }));
 }
Пример #4
0
        private async Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer,
                                           CancellationToken ct)
        {
            try
            {
                var fileName = GetName(assetId, fileVersion);

                await using (var stream = await writer.OpenBlobAsync(fileName, ct))
                {
                    await assetFileStore.DownloadAsync(appId, assetId, fileVersion, null, stream, default, ct);
        public async Task Should_not_resolve_asset_text_if_too_big()
        {
            var(vars, _) = SetupAssetVars(1_000_000);

            var template = @"
                {% assign ref = event.data.assets.iv[0] | asset %}
                Text: {{ ref | assetText }}
            ";

            var expected = $@"
                Text: ErrorTooBig
            ";

            var result = await sut.RenderAsync(template, vars);

            Assert.Equal(Cleanup(expected), Cleanup(result));

            A.CallTo(() => assetFileStore.DownloadAsync(A <DomainId> ._, A <DomainId> ._, A <long> ._, null, A <Stream> ._, A <BytesRange> ._, A <CancellationToken> ._))
            .MustNotHaveHappened();
        }
Пример #6
0
        private async Task TestBackupAsync(AssetEvent @event, long version)
        {
            var assetStream = new MemoryStream();
            var assetId     = @event.AssetId;

            var context = CreateBackupContext();

            A.CallTo(() => context.Writer.OpenBlobAsync($"{assetId}_{version}.asset", ct))
            .Returns(assetStream);

            await sut.BackupEventAsync(AppEvent(@event), context, ct);

            A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, ct))
Пример #7
0
        private async Task TestBackupAsync(AssetEvent @event, long version)
        {
            var assetStream = new MemoryStream();
            var assetId     = @event.AssetId;

            var context = CreateBackupContext();

            A.CallTo(() => context.Writer.WriteBlobAsync($"{assetId}_{version}.asset", A <Func <Stream, Task> > ._))
            .Invokes((string _, Func <Stream, Task> handler) => handler(assetStream));

            await sut.BackupEventAsync(AppEvent(@event), context);

            A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, default))
Пример #8
0
 private async Task WriteAssetAsync(DomainId appId, DomainId assetId, long fileVersion, IBackupWriter writer)
 {
     try
     {
         await writer.WriteBlobAsync(GetName(assetId, fileVersion), stream =>
         {
             return(assetFileStore.DownloadAsync(appId, assetId, fileVersion, stream));
         });
     }
     catch (AssetNotFoundException)
     {
         return;
     }
 }
Пример #9
0
        public async Task Should_not_resolve_text_if_too_big()
        {
            var (vars, _) = SetupAssetsVars(1, 1_000_000);

            var expected = @"
                Text: ErrorTooBig
            ";

            var script = @"
                getAssets(data.assets.iv, function (assets) {
                    getAssetText(assets[0], function (text) {
                        var result = `Text: ${text}`;

                        complete(result);
                    });
                });";

            var result = (await sut.ExecuteAsync(vars, script)).ToString();

            Assert.Equal(Cleanup(expected), Cleanup(result));

            A.CallTo(() => assetFileStore.DownloadAsync(A<DomainId>._, A<DomainId>._, A<long>._, null, A<Stream>._, A<BytesRange>._, A<CancellationToken>._))
                .MustNotHaveHappened();
        }
Пример #10
0
        private IActionResult DeliverAsset(IAssetEntity?asset, AssetQuery query)
        {
            query ??= new AssetQuery();

            if (asset == null || asset.FileVersion < query.Version)
            {
                return(NotFound());
            }

            if (asset.IsProtected && !this.HasPermission(Permissions.AppAssetsRead))
            {
                return(StatusCode(403));
            }

            var fileVersion = query.Version;

            if (fileVersion <= EtagVersion.Any)
            {
                fileVersion = asset.FileVersion;
            }

            Response.Headers[HeaderNames.ETag] = fileVersion.ToString();

            if (query.CacheDuration > 0)
            {
                Response.Headers[HeaderNames.CacheControl] = $"public,max-age={query.CacheDuration}";
            }

            var handler = new Func <Stream, Task>(async bodyStream =>
            {
                if (asset.Type == AssetType.Image && query.ShouldResize())
                {
                    var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{query.Width}_{query.Height}_{query.Mode}";

                    if (query.Quality.HasValue)
                    {
                        resizedAsset += $"_{query.Quality}";
                    }

                    try
                    {
                        await assetStore.DownloadAsync(resizedAsset, bodyStream);
                    }
                    catch (AssetNotFoundException)
                    {
                        using (Profiler.Trace("Resize"))
                        {
                            using (var sourceStream = GetTempStream())
                            {
                                using (var destinationStream = GetTempStream())
                                {
                                    using (Profiler.Trace("ResizeDownload"))
                                    {
                                        await assetFileStore.DownloadAsync(asset.Id, fileVersion, sourceStream);
                                        sourceStream.Position = 0;
                                    }

                                    using (Profiler.Trace("ResizeImage"))
                                    {
                                        await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, query.Width, query.Height, query.Mode, query.Quality);
                                        destinationStream.Position = 0;
                                    }

                                    using (Profiler.Trace("ResizeUpload"))
                                    {
                                        await assetStore.UploadAsync(resizedAsset, destinationStream);
                                        destinationStream.Position = 0;
                                    }

                                    await destinationStream.CopyToAsync(bodyStream);
                                }
                            }
                        }
                    }
                }
                else
                {
                    await assetFileStore.DownloadAsync(asset.Id, fileVersion, bodyStream);
                }
            });

            if (query.Download == 1)
            {
                return(new FileCallbackResult(asset.MimeType, asset.FileName, true, handler));
            }
            else
            {
                return(new FileCallbackResult(asset.MimeType, null, true, handler));
            }
        }
Пример #11
0
        private async Task <IActionResult> DeliverAssetAsync(IAssetEntity?asset, AssetContentQueryDto query)
        {
            query ??= new AssetContentQueryDto();

            if (asset == null)
            {
                return(NotFound());
            }

            if (asset.IsProtected && !Resources.CanReadEvents)
            {
                return(StatusCode(403));
            }

            if (query.Version > EtagVersion.Any && asset.Version != query.Version)
            {
                asset = await assetLoader.GetAsync(asset.Id, query.Version);
            }

            var resizeOptions = query.ToResizeOptions(asset);

            FileCallback callback;

            Response.Headers[HeaderNames.ETag] = asset.FileVersion.ToString();

            if (query.CacheDuration > 0)
            {
                Response.Headers[HeaderNames.CacheControl] = $"public,max-age={query.CacheDuration}";
            }

            var contentLength = (long?)null;

            if (asset.Type == AssetType.Image && resizeOptions.IsValid)
            {
                callback = new FileCallback(async(bodyStream, range, ct) =>
                {
                    var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{resizeOptions}";

                    if (query.ForceResize)
                    {
                        await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, true, ct);
                    }
                    else
                    {
                        try
                        {
                            await assetStore.DownloadAsync(resizedAsset, bodyStream);
                        }
                        catch (AssetNotFoundException)
                        {
                            await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, false, ct);
                        }
                    }
                });
            }
            else
            {
                contentLength = asset.FileSize;

                callback = new FileCallback(async(bodyStream, range, ct) =>
                {
                    await assetFileStore.DownloadAsync(asset.Id, asset.FileVersion, bodyStream, range, ct);
                });
            }

            return(new FileCallbackResult(asset.MimeType, callback)
            {
                EnableRangeProcessing = contentLength > 0,
                ErrorAs404 = true,
                FileDownloadName = asset.FileName,
                FileSize = contentLength,
                LastModified = asset.LastModified.ToDateTimeOffset(),
                SendInline = query.Download != 1
            });
        }
Пример #12
0
        private async Task <IActionResult> DeliverAssetAsync(Context context, IAssetEntity?asset, AssetContentQueryDto request)
        {
            request ??= new AssetContentQueryDto();

            if (asset == null)
            {
                return(NotFound());
            }

            if (asset.IsProtected && !Resources.CanReadAssets)
            {
                Response.Headers[HeaderNames.CacheControl] = "public,max-age=0";

                return(StatusCode(403));
            }

            if (asset != null && request.Version > EtagVersion.Any && asset.Version != request.Version)
            {
                if (context.App != null)
                {
                    asset = await assetQuery.FindAsync(context, asset.Id, request.Version, HttpContext.RequestAborted);
                }
                else
                {
                    // Fallback for old endpoint. Does not set the surrogate key.
                    asset = await assetLoader.GetAsync(asset.AppId.Id, asset.Id, request.Version);
                }
            }

            if (asset == null)
            {
                return(NotFound());
            }

            var resizeOptions = request.ToResizeOptions(asset);

            FileCallback callback;

            Response.Headers[HeaderNames.ETag] = asset.FileVersion.ToString();

            if (request.CacheDuration > 0)
            {
                Response.Headers[HeaderNames.CacheControl] = $"public,max-age={request.CacheDuration}";
            }

            var contentLength = (long?)null;

            if (asset.Type == AssetType.Image && resizeOptions.IsValid)
            {
                callback = async(bodyStream, range, ct) =>
                {
                    var resizedAsset = $"{asset.AppId.Id}_{asset.Id}_{asset.FileVersion}_{resizeOptions}";

                    if (request.ForceResize)
                    {
                        await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, true, ct);
                    }
                    else
                    {
                        try
                        {
                            await assetStore.DownloadAsync(resizedAsset, bodyStream, ct : ct);
                        }
                        catch (AssetNotFoundException)
                        {
                            await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, false, ct);
                        }
                    }
                };
            }
            else
            {
                contentLength = asset.FileSize;

                callback = async(bodyStream, range, ct) =>
                {
                    await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, bodyStream, range, ct);
                };
            }

            return(new FileCallbackResult(asset.MimeType, callback)
            {
                EnableRangeProcessing = contentLength > 0,
                ErrorAs404 = true,
                FileDownloadName = asset.FileName,
                FileSize = contentLength,
                LastModified = asset.LastModified.ToDateTimeOffset(),
                SendInline = request.Download != 1
            });
        }
Пример #13
0
        private IActionResult DeliverAsset(IAssetEntity?asset, AssetContentQueryDto query)
        {
            query ??= new AssetContentQueryDto();

            if (asset == null || asset.FileVersion < query.Version)
            {
                return(NotFound());
            }

            if (asset.IsProtected && !this.HasPermission(Permissions.AppAssetsRead))
            {
                return(StatusCode(403));
            }

            var fileVersion = query.Version;

            if (fileVersion <= EtagVersion.Any)
            {
                fileVersion = asset.FileVersion;
            }

            Response.Headers[HeaderNames.ETag] = fileVersion.ToString();

            if (query.CacheDuration > 0)
            {
                Response.Headers[HeaderNames.CacheControl] = $"public,max-age={query.CacheDuration}";
            }

            var handler = new Func <Stream, Task>(async bodyStream =>
            {
                var resizeOptions = query.ToResizeOptions(asset);

                if (asset.Type == AssetType.Image && resizeOptions.IsValid)
                {
                    var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{resizeOptions}";

                    if (query.ForceResize)
                    {
                        await ResizeAsync(asset, bodyStream, resizedAsset, fileVersion, resizeOptions, true);
                    }
                    else
                    {
                        try
                        {
                            await assetStore.DownloadAsync(resizedAsset, bodyStream);
                        }
                        catch (AssetNotFoundException)
                        {
                            await ResizeAsync(asset, bodyStream, resizedAsset, fileVersion, resizeOptions, false);
                        }
                    }
                }
                else
                {
                    await assetFileStore.DownloadAsync(asset.Id, fileVersion, bodyStream);
                }
            });

            var inline = query.Download != 1;

            return(new FileCallbackResult(asset.MimeType, asset.FileName, handler)
            {
                LastModified = asset.LastModified.ToDateTimeOffset(),
                Send404 = true,
                SendInline = inline,
            });
        }
Пример #14
0
 private async Task DownloadAsync(IAssetEntity asset, Stream bodyStream, string?suffix, BytesRange range,
                                  CancellationToken ct)
 {
     await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, bodyStream, range, ct);
 }