diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ad6f4436..7061480f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,20 +9,20 @@ steps: - checkout: self submodules: true -- task: NuGetAuthenticate@0 - condition: ne(variables['Build.Reason'], 'PullRequest') - - task: UseDotNet@2 displayName: Ensure 3.1 SDK inputs: version: 3.1.x - performMultiLevelLookup: true + includePreviewVersions: true - script: | dotnet build src\MagicScaler -c Dist --version-suffix ci$(Build.BuildNumber) dotnet build src\WebRSize -c Dist --version-suffix ci$(Build.BuildNumber) displayName: Build +- task: NuGetAuthenticate@0 + condition: ne(variables['Build.Reason'], 'PullRequest') + - script: | dotnet nuget push --api-key AzureArtifacts --source https://pkgs.dev.azure.com/saucecontrol/PhotoSauce/_packaging/photosauce_ci/nuget/v3/index.json out\bin\MagicScaler\Dist\PhotoSauce.MagicScaler.*.nupkg dotnet nuget push --api-key AzureArtifacts --source https://pkgs.dev.azure.com/saucecontrol/PhotoSauce/_packaging/photosauce_ci/nuget/v3/index.json out\bin\WebRSize\Dist\PhotoSauce.WebRSize.*.nupkg diff --git a/src/MagicScaler/Core/ImageFileInfo.cs b/src/MagicScaler/Core/ImageFileInfo.cs index a5249f66..d61ca8bc 100644 --- a/src/MagicScaler/Core/ImageFileInfo.cs +++ b/src/MagicScaler/Core/ImageFileInfo.cs @@ -56,7 +56,12 @@ public ImageFileInfo(int width, int height) ContainerType = FileFormat.Unknown; } - private ImageFileInfo(FileFormat containerType, IReadOnlyList frames, long fileSize, DateTime fileDate) + /// Constructs a new instance the specified values. + /// The of the image container. + /// A list containing one per image frame in the container. + /// The size in bytes of the image file. + /// The last modified date of the image file. + public ImageFileInfo(FileFormat containerType, IReadOnlyList frames, long fileSize, DateTime fileDate) { ContainerType = containerType; Frames = frames; diff --git a/src/MagicScaler/MagicScaler.csproj b/src/MagicScaler/MagicScaler.csproj index 596d55ff..4acdc881 100644 --- a/src/MagicScaler/MagicScaler.csproj +++ b/src/MagicScaler/MagicScaler.csproj @@ -21,16 +21,17 @@ - + - + + - + diff --git a/src/WebRSize/CacheHelper.cs b/src/WebRSize/CacheHelper.cs index d5ac2b1e..d99a13a6 100644 --- a/src/WebRSize/CacheHelper.cs +++ b/src/WebRSize/CacheHelper.cs @@ -42,13 +42,12 @@ public static Task GetOrAddAsync(string cacheKey, Func> getValue = return val; } - public static Task GetImageInfoAsync(string path) + public static Task GetImageInfoAsync(VirtualPathProvider vpp, string path) { - return GetOrAddAsync(string.Concat("wrfi_", path), async () => { - var vpp = HostingEnvironment.VirtualPathProvider; - + return GetOrAddAsync(string.Concat("wsvppfi_", path), async () => { var file = vpp is CachingAsyncVirtualPathProvider vppAsync ? await vppAsync.GetFileAsync(path).ConfigureAwait(false) : vpp.GetFile(path); var afile = file as AsyncVirtualFile; + using var stream = afile != null ? await afile.OpenAsync().ConfigureAwait(false) : file.Open(); return ImageFileInfo.Load(stream, afile != null ? afile.LastModified : DateTime.MinValue); }, () => MakeVirtualPathDependency(path)); diff --git a/src/WebRSize/CachingAsyncVirtualPathProvider.cs b/src/WebRSize/CachingAsyncVirtualPathProvider.cs index 4c89dd43..e5edd7cf 100644 --- a/src/WebRSize/CachingAsyncVirtualPathProvider.cs +++ b/src/WebRSize/CachingAsyncVirtualPathProvider.cs @@ -6,6 +6,8 @@ using System.Collections; using System.Threading.Tasks; +using PhotoSauce.MagicScaler; + namespace PhotoSauce.WebRSize { /// A base that adds memory caching and async operation. @@ -58,6 +60,9 @@ protected virtual CacheDependency GetCacheDependencyInternal(string virtualPath, /// protected virtual Task GetDirectoryAsyncInternal(string virtualDir) => CacheHelper.CompletedTask.Default; + /// + protected virtual Task GetImageInfoAsyncInternal(string virtualPath) => CacheHelper.GetImageInfoAsync(this, virtualPath); + /// public override bool FileExists(string virtualPath) => IsPathCaptured(virtualPath) ? FileExistsInternal(virtualPath) : Previous.FileExists(virtualPath); @@ -114,6 +119,17 @@ public virtual Task GetDirectoryAsync(string virtualDir) return AsyncPrevious?.GetDirectoryAsync(virtualDir) ?? Task.FromResult(Previous.GetDirectory(virtualDir)); } + + /// Get the basic metadata associated with an image file at the given . + /// The virtual path of the image file. + /// The . + public virtual Task GetImageInfoAsync(string virtualPath) + { + if (IsPathCaptured(virtualPath)) + return CacheHelper.GetOrAddAsync(string.Concat("wsvppfi_", virtualPath), () => GetImageInfoAsyncInternal(virtualPath)); + + return AsyncPrevious?.GetImageInfoAsync(virtualPath) ?? CacheHelper.GetImageInfoAsync(Previous, virtualPath); + } } /// diff --git a/src/WebRSize/WebRSize.csproj b/src/WebRSize/WebRSize.csproj index 4ffd4011..d12d13ca 100644 --- a/src/WebRSize/WebRSize.csproj +++ b/src/WebRSize/WebRSize.csproj @@ -1,7 +1,7 @@  - 0.5.0 + 0.5.1 net46;net472 diff --git a/src/WebRSize/WebRSizeHandler.cs b/src/WebRSize/WebRSizeHandler.cs index 5139fefc..18901cc4 100644 --- a/src/WebRSize/WebRSizeHandler.cs +++ b/src/WebRSize/WebRSizeHandler.cs @@ -15,8 +15,11 @@ namespace PhotoSauce.WebRSize /// An implementation that performs a dynamic image processing operation, returns the result to the client, and queues caching the result. public class WebRSizeHandler : HttpTaskAsyncHandler { + internal static WebRSizeHandler Instance = new WebRSizeHandler(); + private struct QueueReleaser : IDisposable { public void Dispose() => sem.Release(); } + private static readonly bool diskCacheEnabled = WebRSizeConfig.Current.DiskCache.Enabled; private static readonly SemaphoreSlim sem = new SemaphoreSlim(Environment.ProcessorCount, Environment.ProcessorCount); private static readonly ConcurrentDictionary>> tdic = new ConcurrentDictionary>>(); private static readonly Lazy mpbvfType = new Lazy(() => Assembly.GetAssembly(typeof(HostingEnvironment)).GetType("System.Web.Hosting.MapPathBasedVirtualFile", true)); @@ -32,6 +35,9 @@ private static void saveResult(TaskCompletionSource> tcs, Mem oimg.TryGetBuffer(out var bytes); tcs.SetResult(bytes); + if (!diskCacheEnabled) + return; + HostingEnvironment.QueueBackgroundWorkItem(async __ => { try { var fi = new FileInfo(cachePath); if (!fi.Exists) diff --git a/src/WebRSize/WebRSizeModule.cs b/src/WebRSize/WebRSizeModule.cs index 50d0f227..7ed5ceb3 100644 --- a/src/WebRSize/WebRSizeModule.cs +++ b/src/WebRSize/WebRSizeModule.cs @@ -16,7 +16,7 @@ public class WebRSizeModule : IHttpModule internal const string CachePathKey = "wscachepath"; internal const string NotFoundPath = "/404/notfound.png"; - private static readonly WebRSizeHandler handler = new WebRSizeHandler(); + private static readonly bool diskCacheEnabled = WebRSizeConfig.Current.DiskCache.Enabled; private static readonly ImageFolder[] imageFolders = WebRSizeConfig.Current.ImageFolders.OfType().ToArray(); private static readonly Lazy namingStrategy = new Lazy(() => (ICacheFileNamingStrategy)Activator.CreateInstance(WebRSizeConfig.Current.DiskCache.NamingStrategy)); @@ -26,7 +26,7 @@ private async Task mapRequest(object sender, EventArgs e) var vpp = HostingEnvironment.VirtualPathProvider; string path = ctx.Request.Path; - bool exists = vpp is CachingAsyncVirtualPathProvider vppAsync ? await vppAsync.FileExistsAsync(path) : vpp.FileExists(path); + bool exists = vpp is CachingAsyncVirtualPathProvider vppAE ? await vppAE.FileExistsAsync(path).ConfigureAwait(false) : vpp.FileExists(path); var folderConfig = imageFolders.FirstOrDefault(f => ctx.Request.Path.StartsWith(f.Path, StringComparison.OrdinalIgnoreCase)); if (folderConfig is null) @@ -63,7 +63,7 @@ private async Task mapRequest(object sender, EventArgs e) s.SaveFormat = FileFormat.Png; } - ifi ??= await CacheHelper.GetImageInfoAsync(path); + ifi = vpp is CachingAsyncVirtualPathProvider vppAF ? await vppAF.GetImageInfoAsync(path).ConfigureAwait(false) : await CacheHelper.GetImageInfoAsync(vpp, path).ConfigureAwait(false); s.NormalizeFrom(ifi); if (!folderConfig.AllowEnlarge && s.ResizeMode != CropScaleMode.Max) @@ -99,7 +99,7 @@ private async Task mapRequest(object sender, EventArgs e) string cacheVPath = namingStrategy.Value.GetCacheFilePath(path, s); string cachePath = HostingEnvironment.MapPath(cacheVPath); - if (File.Exists(cachePath)) + if (diskCacheEnabled && File.Exists(cachePath)) { ctx.RewritePath(cacheVPath, null, string.Empty, false); return; @@ -110,7 +110,7 @@ private async Task mapRequest(object sender, EventArgs e) ctx.Items[ProcessImageSettingsKey] = s; ctx.Items[CachePathKey] = cachePath; - ctx.RemapHandler(handler); + ctx.RemapHandler(WebRSizeHandler.Instance); } ///