using iFileProxy.Config; using iFileProxy.Helpers; using iFileProxy.Models; using Newtonsoft.Json; using Serilog; using MySql.Data.MySqlClient; using System.Data; using iFileProxy.Models.Task; namespace iFileProxy.Services { /// /// 本地缓存管理器 /// public class LocalCacheLifeManagementService { // 禁用空警告 因为初始化的时候就已经检查过相关的内容了 #pragma warning disable CS8601 private readonly AppConfig _appConfig = AppConfig.GetCurrConfig(); private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); private readonly object _lock = new (); private readonly Timer _timer; private readonly DatabaseGateService _dbGateService; private int CACHE_LIFETIME; /// /// 缓存管理器 /// public LocalCacheLifeManagementService(IServiceProvider serviceProvider) { _logger.Debug($"Initializing {this.GetType().Name}..."); CACHE_LIFETIME = _appConfig.DownloadOptions.CacheLifetime; _dbGateService = serviceProvider.GetRequiredService(); serviceProvider.GetRequiredService().AppConfigurationChanged += LocalCacheManager_AppConfigurationChange; // 开始定时清理任务 _timer = new Timer((obj) => { lock (_lock) { CheckAndCleanCache(); } }, null, TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(60)); _logger.Debug($"{this.GetType().Name} init successful."); } private void LocalCacheManager_AppConfigurationChange(object sender, AppConfig appConfig) { CACHE_LIFETIME = appConfig.DownloadOptions.CacheLifetime; } /// /// 检查并且清理缓存数据 /// public void CheckAndCleanCache() { try { // 获取数据库中超出生命周期的缓存数据 string sql = $@"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' AND tag <> 'STREAM' AND `status` <> {(int)TaskState.Stream} OR tag IS NULL )"; List? taskInfos; using (var conn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy)) { using var cmd = new MySqlCommand(sql, conn); using var adapter = new MySqlDataAdapter(cmd); using var dataTable = new DataTable(); adapter.Fill(dataTable); taskInfos = JsonConvert.DeserializeObject>( JsonConvert.SerializeObject(dataTable) ); } if (taskInfos != null) { foreach (TaskInfo taskInfo in taskInfos) { var dependencies = _dbGateService.CheckCacheDependencies(taskInfo.TaskId, taskInfo.ClientIp); // 获取依赖和已经过期的任务ID交集 var intersect = dependencies.Select(x => x.TaskId).Intersect(taskInfos.Select(x => x.TaskId)).ToList(); // 若依赖该缓存的任务也处于过期状态 则不进行缓存依赖检查 if (intersect.IndexOf(taskInfo.TaskId) == -1) if (dependencies != null && dependencies.Count > 0) { _logger.Warning($"TaskId: {taskInfo.TaskId} 所产生的缓存文件正被 {string.Join(",", dependencies.Select(x => x.TaskId))} 所依赖, 不会继续执行清理任务"); continue; } string cacheFileName = Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName); if (File.Exists(cacheFileName)) { _logger.Information($"正在清理缓存文件: {cacheFileName}"); try { File.Delete(cacheFileName); } catch (Exception e) { _logger.Error($"缓存文件删除失败: {e.Message}"); continue; } } // 更新数据库状态 using var conn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy); // 更新标签 using (var cmd = new MySqlCommand( "UPDATE t_tasks_info SET tag = @tag WHERE tid = @tid", conn)) { cmd.Parameters.AddWithValue("@tag", "CLEANED"); cmd.Parameters.AddWithValue("@tid", taskInfo.TaskId); cmd.ExecuteNonQuery(); } // 更新状态 taskInfo.Status = TaskState.Cleaned; _dbGateService.UpdateTaskStatus(taskInfo); } } } catch (Exception ex) { _logger.Error($"清理缓存时发生错误: {ex.Message}"); } } /// /// 停止定时清理服务 /// public void StopScheduledCleanupService() { _timer.Dispose(); } } }