// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // // // The image cache base provides methods for implementing the interface. // It is recommended that any implementations inherit from this class. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Caching { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading.Tasks; using System.Web; using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; /// /// The image cache base provides methods for implementing the interface. /// It is recommended that any implementations inherit from this class. /// public abstract class ImageCacheBase : IImageCache { /// /// The request path for the image. /// protected readonly string RequestPath; /// /// The full path for the image. /// protected readonly string FullPath; /// /// The querystring containing processing instructions. /// protected readonly string Querystring; /// /// Initializes a new instance of the class. /// /// /// The request path for the image. /// /// /// The full path for the image. /// /// /// The querystring containing instructions. /// protected ImageCacheBase(string requestPath, string fullPath, string querystring) { this.RequestPath = requestPath; this.FullPath = fullPath; this.Querystring = querystring; this.Settings = ImageProcessorConfiguration.Instance.ImageCacheSettings; this.MaxDays = ImageProcessorConfiguration.Instance.ImageCacheMaxDays; } /// /// Gets or sets any additional settings required by the cache. /// public Dictionary Settings { get; set; } /// /// Gets or sets the path to the cached image. /// public string CachedPath { get; set; } /// /// Gets or sets the maximum number of days to store the image. /// public int MaxDays { get; set; } /// /// Gets a value indicating whether the image is new or updated in an asynchronous manner. /// /// /// The . /// public abstract Task IsNewOrUpdatedAsync(); /// /// Adds the image to the cache in an asynchronous manner. /// /// /// The stream containing the image data. /// /// /// The content type of the image. /// /// /// The representing an asynchronous operation. /// public abstract Task AddImageToCacheAsync(Stream stream, string contentType); /// /// Trims the cache of any expired items in an asynchronous manner. /// /// /// The asynchronous representing an asynchronous operation. /// public abstract Task TrimCacheAsync(); /// /// Gets a string identifying the cached file name. /// /// /// The asynchronous returning the value. /// public virtual async Task CreateCachedFileNameAsync() { string streamHash = string.Empty; try { if (new Uri(this.RequestPath).IsFile) { // Get the hash for the filestream. That way we can ensure that if the image is // updated but has the same name we will know. FileInfo imageFileInfo = new FileInfo(this.RequestPath); if (imageFileInfo.Exists) { // Pull the latest info. imageFileInfo.Refresh(); // Checking the stream itself is far too processor intensive so we make a best guess. string creation = imageFileInfo.CreationTimeUtc.ToString(CultureInfo.InvariantCulture); string length = imageFileInfo.Length.ToString(CultureInfo.InvariantCulture); streamHash = string.Format("{0}{1}", creation, length); } } } catch { streamHash = string.Empty; } // Use an sha1 hash of the full path including the querystring to create the image name. // That name can also be used as a key for the cached image and we should be able to use // The characters of that hash as sub-folders. string parsedExtension = ImageHelpers.GetExtension(this.FullPath, this.Querystring); string encryptedName = (streamHash + this.FullPath).ToSHA1Fingerprint(); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : "jpg"); return await Task.FromResult(cachedFileName); } /// /// Rewrites the path to point to the cached image. /// /// /// The encapsulating all information about the request. /// public abstract void RewritePath(HttpContext context); /// /// Gets a value indicating whether the given images creation date is out with /// the prescribed limit. /// /// /// The creation date. /// /// /// The true if the date is out with the limit, otherwise; false. /// protected virtual bool IsExpired(DateTime creationDate) { return creationDate.AddDays(this.MaxDays) < DateTime.UtcNow.AddDays(-this.MaxDays); } } }