-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
src/OrchardCore.Modules/OrchardCore.Media/Services/RemoteMediaCacheBackgroundTask.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using OrchardCore.BackgroundTasks; | ||
using OrchardCore.Environment.Shell; | ||
using OrchardCore.Media.Core; | ||
using OrchardCore.Modules; | ||
|
||
namespace OrchardCore.Media.Services; | ||
|
||
[BackgroundTask(Schedule = "30 0 * * *", Description = "'Remote media cache cleanup.")] | ||
public class RemoteMediaCacheBackgroundTask : IBackgroundTask | ||
{ | ||
private static readonly EnumerationOptions _enumerationOptions = new() { RecurseSubdirectories = true }; | ||
|
||
private readonly IMediaFileStore _mediaFileStore; | ||
private readonly ILogger _logger; | ||
|
||
private readonly string _cachePath; | ||
private readonly TimeSpan? _cacheMaxStale; | ||
|
||
public RemoteMediaCacheBackgroundTask( | ||
ShellSettings shellSettings, | ||
IMediaFileStore mediaFileStore, | ||
IWebHostEnvironment webHostEnvironment, | ||
IOptions<MediaOptions> mediaOptions, | ||
ILogger<RemoteMediaCacheBackgroundTask> logger) | ||
{ | ||
_mediaFileStore = mediaFileStore; | ||
|
||
_cachePath = Path.Combine( | ||
webHostEnvironment.WebRootPath, | ||
shellSettings.Name, | ||
DefaultMediaFileStoreCacheFileProvider.AssetsCachePath); | ||
|
||
_cacheMaxStale = mediaOptions.Value.RemoteCacheMaxStale; | ||
_logger = logger; | ||
} | ||
|
||
public async Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) | ||
{ | ||
// Ensure that the cache folder exists and should be cleaned. | ||
if (!_cacheMaxStale.HasValue || !Directory.Exists(_cachePath)) | ||
{ | ||
return; | ||
} | ||
|
||
// Ensure that a remote media cache has been registered. | ||
if (serviceProvider.GetService<IMediaFileStoreCache>() is null) | ||
{ | ||
return; | ||
} | ||
|
||
// The min write time for an item to be retained in the cache, | ||
// without having to get the item info from the remote store. | ||
var minWriteTimeUtc = DateTimeOffset.UtcNow - _cacheMaxStale.Value; | ||
try | ||
{ | ||
// Lookup for all cache directories. | ||
var directories = Directory.GetDirectories(_cachePath, "*", _enumerationOptions); | ||
foreach (var directory in directories) | ||
{ | ||
// Check if the directory is retained. | ||
var directoryInfo = new DirectoryInfo(directory); | ||
if (!directoryInfo.Exists || directoryInfo.LastWriteTimeUtc > minWriteTimeUtc) | ||
{ | ||
continue; | ||
} | ||
|
||
var path = Path.GetRelativePath(_cachePath, directoryInfo.FullName); | ||
|
||
// Check if the remote directory doesn't exist. | ||
var entry = await _mediaFileStore.GetDirectoryInfoAsync(path); | ||
if (entry is null) | ||
{ | ||
Directory.Delete(directoryInfo.FullName, true); | ||
} | ||
} | ||
|
||
// Lookup for all cache files. | ||
var files = Directory.GetFiles(_cachePath, "*", _enumerationOptions); | ||
foreach (var file in files) | ||
{ | ||
// Check if the file is retained. | ||
var fileInfo = new FileInfo(file); | ||
if (!fileInfo.Exists || fileInfo.LastWriteTimeUtc > minWriteTimeUtc) | ||
{ | ||
continue; | ||
} | ||
|
||
var path = Path.GetRelativePath(_cachePath, fileInfo.FullName); | ||
|
||
// Check if the remote media doesn't exist or was updated. | ||
var entry = await _mediaFileStore.GetFileInfoAsync(path); | ||
if (entry is null || | ||
(entry.LastModifiedUtc > fileInfo.LastWriteTimeUtc && | ||
entry.LastModifiedUtc < minWriteTimeUtc)) | ||
{ | ||
File.Delete(fileInfo.FullName); | ||
} | ||
} | ||
} | ||
catch (Exception ex) when (ex is DirectoryNotFoundException) | ||
{ | ||
} | ||
catch (Exception ex) when (ex.IsFileSharingViolation()) | ||
{ | ||
if (_logger.IsEnabled(LogLevel.Warning)) | ||
{ | ||
_logger.LogWarning( | ||
ex, | ||
"Sharing violation while cleaning the remote media cache at '{CachePath}'.", | ||
_cachePath); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError( | ||
ex, | ||
"Failed to clean the remote media cache at '{CachePath}'.", | ||
_cachePath); | ||
} | ||
|
||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
src/OrchardCore.Modules/OrchardCore.Media/Services/ResizedMediaCacheBackgroundTask.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using OrchardCore.BackgroundTasks; | ||
using OrchardCore.Modules; | ||
using SixLabors.ImageSharp.Web.Caching; | ||
using SixLabors.ImageSharp.Web.Middleware; | ||
|
||
namespace OrchardCore.Media.Services; | ||
|
||
[BackgroundTask(Schedule = "0 0 * * *", Description = "'Resized media cache cleanup.")] | ||
public class ResizedMediaCacheBackgroundTask : IBackgroundTask | ||
{ | ||
private static readonly EnumerationOptions _enumerationOptions = new() { RecurseSubdirectories = true }; | ||
|
||
private readonly ILogger _logger; | ||
|
||
private readonly string _cachePath; | ||
private readonly string _cacheFolder; | ||
private readonly TimeSpan _cacheMaxAge; | ||
private readonly TimeSpan? _cacheMaxStale; | ||
|
||
public ResizedMediaCacheBackgroundTask( | ||
IWebHostEnvironment webHostEnvironment, | ||
IOptions<MediaOptions> mediaOptions, | ||
IOptions<ImageSharpMiddlewareOptions> middlewareOptions, | ||
IOptions<PhysicalFileSystemCacheOptions> cacheOptions, | ||
ILogger<ResizedMediaCacheBackgroundTask> logger) | ||
{ | ||
_cachePath = Path.Combine(webHostEnvironment.WebRootPath, cacheOptions.Value.CacheFolder); | ||
_cacheFolder = Path.GetFileName(cacheOptions.Value.CacheFolder); | ||
_cacheMaxAge = middlewareOptions.Value.CacheMaxAge; | ||
_cacheMaxStale = mediaOptions.Value.ResizedCacheMaxStale; | ||
_logger = logger; | ||
} | ||
|
||
public Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) | ||
{ | ||
// Ensure that the cache folder exists and should be cleaned. | ||
if (!_cacheMaxStale.HasValue || !Directory.Exists(_cachePath)) | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
// The min write time for an item to be retained in the cache. | ||
var minWriteTimeUtc = DateTime.UtcNow.Subtract(_cacheMaxAge + _cacheMaxStale.Value); | ||
try | ||
{ | ||
// Lookup for all meta files. | ||
var files = Directory.GetFiles(_cachePath, "*.meta", _enumerationOptions); | ||
foreach (var file in files) | ||
{ | ||
// Check if the file is retained. | ||
var fileInfo = new FileInfo(file); | ||
if (!fileInfo.Exists || fileInfo.LastWriteTimeUtc > minWriteTimeUtc) | ||
{ | ||
continue; | ||
} | ||
|
||
// Delete the folder including the media item. | ||
Directory.Delete(fileInfo.DirectoryName, true); | ||
|
||
// Delete new empty parent directories. | ||
var parent = fileInfo.Directory.Parent; | ||
while (parent is not null && parent.Name != _cacheFolder) | ||
{ | ||
Directory.Delete(parent.FullName); | ||
|
||
parent = parent.Parent; | ||
if (!parent.Exists || parent.EnumerateFileSystemInfos().Any()) | ||
{ | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
catch (Exception ex) when (ex is DirectoryNotFoundException) | ||
{ | ||
} | ||
catch (Exception ex) when (ex.IsFileSharingViolation()) | ||
{ | ||
if (_logger.IsEnabled(LogLevel.Warning)) | ||
{ | ||
_logger.LogWarning( | ||
ex, | ||
"Sharing violation while cleaning the resized media cache at '{CachePath}'.", | ||
_cachePath); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError( | ||
ex, | ||
"Failed to clean the resized media cache at '{CachePath}'.", | ||
_cachePath); | ||
} | ||
|
||
return Task.CompletedTask; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters