From bc589471f374193fc9e64bfb7f39cb776435571a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 30 Nov 2024 12:11:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E4=BB=A3=E7=A0=81=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E5=90=88=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Config/AppConfig.cs | 8 +- .../VisitorManagementController.cs | 15 +- src/Controllers/iProxyController.cs | 28 ++- src/Models/Task.cs | 4 + src/Program.cs | 32 ++- .../PublishProfiles/FolderProfile.pubxml | 2 +- .../DatabaseGateService.cs} | 195 +++++++++++++++--- src/Services/LocalCacheManager.cs | 12 +- src/Services/TaskManager.cs | 76 +++++-- 9 files changed, 284 insertions(+), 88 deletions(-) rename src/{Helpers/DatabaseHelper.cs => Services/DatabaseGateService.cs} (67%) diff --git a/src/Config/AppConfig.cs b/src/Config/AppConfig.cs index c27e501..9d514c0 100644 --- a/src/Config/AppConfig.cs +++ b/src/Config/AppConfig.cs @@ -1,4 +1,4 @@ -using iFileProxy.Helpers; +using iFileProxy.Services; using Serilog; using System.Text.Json; using System.Text.Json.Serialization; @@ -23,7 +23,7 @@ namespace iFileProxy.Config [JsonPropertyName("Database")] public Database Database { get; set; } - public static AppConfig? GetCurrConfig(string configPath = "iFileProxy.json") + public static AppConfig GetCurrConfig(string configPath = "iFileProxy.json") { if (File.Exists(configPath)) { @@ -41,7 +41,7 @@ namespace iFileProxy.Config _logger.Fatal($"Config File: {configPath} not exists!"); return null; } - public static void CheckAppConfig() + public static void CheckAppConfig(IServiceProvider serviceProvider) { AppConfig? c = GetCurrConfig(); if (c != null) @@ -59,7 +59,7 @@ namespace iFileProxy.Config Environment.Exit(1); } - DatabaseHelper databaseHelper = new(c); + var databaseHelper = serviceProvider.GetRequiredService(); databaseHelper.TestDbConfig(); } else diff --git a/src/Controllers/VisitorManagementController.cs b/src/Controllers/VisitorManagementController.cs index e406369..f650dde 100644 --- a/src/Controllers/VisitorManagementController.cs +++ b/src/Controllers/VisitorManagementController.cs @@ -1,4 +1,5 @@ using iFileProxy.Helpers; +using iFileProxy.Services; using iFileProxy.Models; using iFileProxy.Config; using Microsoft.AspNetCore.Mvc; @@ -14,7 +15,11 @@ namespace iFileProxy.Controllers [ApiController] public class VisitorManagementController : ControllerBase { - static DatabaseHelper _dbHelper = new DatabaseHelper(AppConfig.GetCurrConfig()); + private readonly DatabaseGateService _dbGateService; + public VisitorManagementController(DatabaseGateService dbGate) + { + _dbGateService = dbGate; + } private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); @@ -22,14 +27,14 @@ namespace iFileProxy.Controllers public ActionResult DeleteInfo() { string ipAddr = MasterHelper.GetClientIPAddr(HttpContext); - var d = JsonConvert.DeserializeObject>(_dbHelper.GetTaskListByStateAndIp(ipAddr, TaskState.Running)); + var d = JsonConvert.DeserializeObject>(_dbGateService.GetTaskListByStateAndIp(ipAddr, TaskState.Running)); int rd = (d != null) ? d.Count : 0; if (rd <= 0) { - d = JsonConvert.DeserializeObject>(_dbHelper.GetTaskListByIP(ipAddr)); + d = JsonConvert.DeserializeObject>(_dbGateService.GetTaskListByIP(ipAddr)); foreach (var taskInfo in d) { - var dep = _dbHelper.CheckCacheDependencies(taskInfo.TaskId,ipAddr); + var dep = _dbGateService.CheckCacheDependencies(taskInfo.TaskId,ipAddr); if (dep.Count <= 0) { if (MasterHelper.CheckDownloadFileExists(taskInfo.FileName)) @@ -42,7 +47,7 @@ namespace iFileProxy.Controllers _logger.Warning($"准备删除的文件正在被以下Task所依赖: {JsonConvert.SerializeObject(dep)} 文件将不会被删除"); } - return Ok(new CommonRsp() { Retcode = 0, Message = "succ", Data = _dbHelper.DeleteTaskInfoByIpAddr(ipAddr)}); + return Ok(new CommonRsp() { Retcode = 0, Message = "succ", Data = _dbGateService.DeleteTaskInfoByIpAddr(ipAddr)}); } else return Ok(new CommonRsp() {Retcode = -1, Message = "你还有正在运行的任务, 你现在不能删除你的数据, 请稍后等待任务完成后重试", Data = rd }); diff --git a/src/Controllers/iProxyController.cs b/src/Controllers/iProxyController.cs index 18b3943..563d025 100644 --- a/src/Controllers/iProxyController.cs +++ b/src/Controllers/iProxyController.cs @@ -10,14 +10,20 @@ namespace iFileProxy.Controllers { public class iProxyController : ControllerBase { - static readonly TaskManager taskManager = new (); - static AppConfig? appConfig = AppConfig.GetCurrConfig(); + private readonly TaskManager _taskManager; + private readonly AppConfig _appConfig; + + public iProxyController(TaskManager taskManager, AppConfig appConfig) + { + _taskManager = taskManager; + _appConfig = appConfig; + } [HttpPost] [Route("/AddOfflineTask")] public ActionResult AddOfflineTask() { - return taskManager.AddTask(HttpContext) switch + return _taskManager.AddTask(HttpContext) switch { TaskAddState.Success => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Success, Message = "succ" }), TaskAddState.Fail => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Fail, Message = "unkown error!" }), @@ -43,12 +49,12 @@ namespace iFileProxy.Controllers [Route("/GetMyTasks")] public ActionResult GetMyTasks() { - var data = taskManager.GetTaskListByIpAddr(HttpContext); + var data = _taskManager.GetTaskListByIpAddr(HttpContext); foreach (var d in data) { if (d.Status == TaskState.Queuing) { - d.QueuePosition = taskManager.GetQueuePosition(d.TaskId); + d.QueuePosition = _taskManager.GetQueuePosition(d.TaskId); } } return Ok(new CommonRsp() { Retcode = 0, Data = data ,Message = "succ" }); @@ -58,7 +64,7 @@ namespace iFileProxy.Controllers [HttpGet] [Route("/GetServerLoad")] public ActionResult GetServerLoad() { - return Ok(new CommonRsp { Retcode = 0, Message = "succ", Data = taskManager.GetServerTaskLoadInfo() }); + return Ok(new CommonRsp { Retcode = 0, Message = "succ", Data = _taskManager.GetServerTaskLoadInfo() }); } [HttpGet] @@ -67,12 +73,12 @@ namespace iFileProxy.Controllers public async Task DownloadFile(string taskID) { string fileName = ""; - var d = taskManager.GetTaskListByIpAddr(HttpContext); - var taskInfo = taskManager.GetTaskInfo(taskID); + var d = _taskManager.GetTaskListByIpAddr(HttpContext); + var taskInfo = _taskManager.GetTaskInfo(taskID); - if ((!appConfig.SecurityOptions.AllowDifferentIPsForDownload && d.Where(x => x.TaskId == taskID).Any()) || taskInfo != null) + if ((!_appConfig.SecurityOptions.AllowDifferentIPsForDownload && d.Where(x => x.TaskId == taskID).Any()) || taskInfo != null) { - if (appConfig.SecurityOptions.AllowDifferentIPsForDownload) + if (_appConfig.SecurityOptions.AllowDifferentIPsForDownload) { fileName = taskInfo[0].FileName; } @@ -83,7 +89,7 @@ namespace iFileProxy.Controllers if (fileName == null) return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 }); - var filePath = Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName); + var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, fileName); if (!MasterHelper.CheckDownloadFileExists(fileName)) { return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 }); diff --git a/src/Models/Task.cs b/src/Models/Task.cs index 1926d99..414978e 100644 --- a/src/Models/Task.cs +++ b/src/Models/Task.cs @@ -32,6 +32,10 @@ /// 正在排队 /// Queuing = 6, + /// + /// 任务因为各种原因被取消 + /// + Canceled = 7, } /// /// 任务添加状态 diff --git a/src/Program.cs b/src/Program.cs index 7a5857d..14f031a 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,4 +1,3 @@ - using iFileProxy.Config; using iFileProxy.Helpers; using iFileProxy.Middleware; @@ -16,11 +15,6 @@ namespace iFileProxy Console.Write(" "); // ǿ֢ſʼ־벻þ - AppConfig.CheckAppConfig(); - - // ʼ - LocalCacheManager localCacheManager = new (); - var builder = WebApplication.CreateBuilder(args); // Add services to the container. @@ -32,8 +26,23 @@ namespace iFileProxy builder.Host.UseSerilog(logger: Log.Logger); + builder.Services.AddSingleton>>(serviceProvider => + { + return new Dictionary>(); + }); + + builder.Services.AddSingleton(AppConfig.GetCurrConfig()); + + builder.Services.AddSingleton(); + + builder.Services.AddSingleton(); + var app = builder.Build(); + AppConfig.CheckAppConfig(app.Services); + + LocalCacheManager localCacheManager = new(app.Services); + app.UseSerilogRequestLogging(options => { options.EnrichDiagnosticContext = (diagCtx, httpCtx) => @@ -51,6 +60,9 @@ namespace iFileProxy app.UseSwaggerUI(); } + // м + app.UseMiddleware(); + app.UseHttpsRedirection(); // Ĭļѡ @@ -64,11 +76,9 @@ namespace iFileProxy app.UseAuthorization(); - var IPAccessCountDict = new Dictionary>(); - var dailyRequestLimitPerIP = AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP; - app.UseMiddleware(IPAccessCountDict, dailyRequestLimitPerIP); - - app.UseMiddleware(); // м + app.UseMiddleware( + app.Services.GetRequiredService>>(), + AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP); app.MapControllers(); diff --git a/src/Properties/PublishProfiles/FolderProfile.pubxml b/src/Properties/PublishProfiles/FolderProfile.pubxml index 1296e0c..8285a16 100644 --- a/src/Properties/PublishProfiles/FolderProfile.pubxml +++ b/src/Properties/PublishProfiles/FolderProfile.pubxml @@ -15,7 +15,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. <_TargetId>Folder net8.0 - linux-x64 + win-x64 e343bd8a-27ed-47e2-b50d-e3000730e65e false true diff --git a/src/Helpers/DatabaseHelper.cs b/src/Services/DatabaseGateService.cs similarity index 67% rename from src/Helpers/DatabaseHelper.cs rename to src/Services/DatabaseGateService.cs index 88cb37f..87a40fe 100644 --- a/src/Helpers/DatabaseHelper.cs +++ b/src/Services/DatabaseGateService.cs @@ -1,24 +1,32 @@ using iFileProxy.Config; using Serilog; using System.Data; -using System.Text.Json; +using iFileProxy.Helpers; using MySql.Data.MySqlClient; using iFileProxy.Models; using Newtonsoft.Json; -namespace iFileProxy.Helpers +namespace iFileProxy.Services { - public class DatabaseHelper + /// + /// 数据库访问网关服务 + /// 提供统一的数据库操作接口,管理数据库连接和查询 + /// + public class DatabaseGateService { Database _db; AppConfig _appConfig; - private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); + private readonly Serilog.ILogger _logger = Log.Logger.ForContext(); Dictionary _dbDictionary = []; - public DatabaseHelper(AppConfig appConfig) + /// + /// 初始化数据库网关服务 + /// + /// 应用程序配置 + public DatabaseGateService(AppConfig appConfig) { - _logger.Information("Initializing DatabaseHelper..."); + _logger.Information("Initializing DatabaseGateService..."); _db = appConfig.Database; _appConfig = appConfig; try @@ -33,7 +41,7 @@ namespace iFileProxy.Helpers } /// - /// 加载数据库描述字典 + /// 加载数据库配置字典 /// public void LoadDbDict() { @@ -43,13 +51,14 @@ namespace iFileProxy.Helpers _logger.Debug($"Db Config: {item.Description} <=> {item.DatabaseName} Loaded."); } } + /// - /// 获取一个指定数据库的连接 + /// 获取并打开指定数据库的连接 /// - /// 数据库描述字段 对应AppConfig的description字段 - /// - /// 若某些不允许为空的字段出现空值 则抛出此异常 - /// + /// 数据库描述符,对应配置文件中的 Description 字段 + /// 已打开的数据库连接 + /// 当找不到匹配的数据库配置时抛出 + /// 当必需的配置字段为空时抛出 public MySqlConnection GetAndOpenDBConn(string db_desc) { if (!_dbDictionary.TryGetValue(db_desc, out DB Db)) @@ -80,6 +89,10 @@ namespace iFileProxy.Helpers return conn; } + /// + /// 测试所有数据库配置的连接 + /// + /// 测试是否全部成功 public bool TestDbConfig() { foreach (var db in _dbDictionary) @@ -105,11 +118,10 @@ namespace iFileProxy.Helpers } /// - /// 获取一个json格式的数据表 + /// 执行查询并返回 JSON 格式的结果 /// - /// - /// - /// + /// SQL 命令对象 + /// JSON 格式的查询结果 public static string QueryTableData(MySqlCommand sqlCmd) { DataTable dataTable = new(); @@ -119,34 +131,43 @@ namespace iFileProxy.Helpers } /// - /// 获取一个json格式的数据表 + /// 执行查询并返回 JSON 格式的结果 /// - /// - /// - /// - public string QueryTableData(string sql,string dbConfName) + /// SQL 查询语句 + /// 数据库配置名称 + /// JSON 格式的查询结果 + public string QueryTableData(string sql, string dbConfName) { DataTable dataTable = new(); - using (MySqlDataAdapter adapter = new(new MySqlCommand(sql,GetAndOpenDBConn(dbConfName)))) + using (MySqlDataAdapter adapter = new(new MySqlCommand(sql, GetAndOpenDBConn(dbConfName)))) adapter.Fill(dataTable); return JsonConvert.SerializeObject(dataTable); } /// - /// 内部查询数据专用 当此方法暴露给C端可能造成sql注入等安全问题 + /// 执行非查询SQL语句 /// /// SQL语句 - /// 配置文件中的Description字段 - /// 影响的行数 + /// 数据库配置名称 + /// 受影响的行数 + /// + /// 警告:此方法仅供内部使用,直接暴露给客户端可能导致SQL注入风险 + /// public int Query(string sql, string dbConfName) - { + { using MySqlCommand sqlCmd = new (sql, GetAndOpenDBConn(dbConfName)); int n = sqlCmd.ExecuteNonQuery(); _logger.Debug($"查询完成, 受影响的行数: {n}"); return n; } - public List CheckCacheDependencies(string taskId,string ipAddr) + /// + /// 检查缓存依赖关系 + /// + /// 任务ID + /// IP地址 + /// 相关的任务信息列表 + public List CheckCacheDependencies(string taskId, string ipAddr) { string sql = $"SELECT * FROM t_tasks_info WHERE `status` = @status AND `tag` = @tag AND `client_ip` <> @ip_addr"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); @@ -157,7 +178,7 @@ namespace iFileProxy.Helpers sqlCmd.Parameters.AddWithValue("@status", TaskState.Cached); sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr); - return JsonConvert.DeserializeObject>( QueryTableData(sqlCmd)); + return JsonConvert.DeserializeObject>(QueryTableData(sqlCmd)); } catch (Exception e) { @@ -167,6 +188,12 @@ namespace iFileProxy.Helpers finally { conn.Close(); } } + /// + /// 根据状态和IP地址获取任务列表 + /// + /// IP地址 + /// 任务状态 + /// JSON格式的任务列表 public string GetTaskListByStateAndIp(string ipAddr, TaskState status) { string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr AND `status` = @status"; @@ -175,7 +202,7 @@ namespace iFileProxy.Helpers { using MySqlCommand sqlCmd = new(sql, conn); sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr); - sqlCmd.Parameters.AddWithValue ("@status", status); + sqlCmd.Parameters.AddWithValue("@status", status); return QueryTableData(sqlCmd); } catch (Exception e) @@ -186,7 +213,11 @@ namespace iFileProxy.Helpers finally { conn.Close(); } } - + /// + /// 根据IP地址获取任务列表 + /// + /// IP地址 + /// JSON格式的任务列表 public string GetTaskListByIP(string ipAddr) { string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr"; @@ -204,6 +235,12 @@ namespace iFileProxy.Helpers } finally { conn.Close(); } } + + /// + /// 根据任务ID获取任务信息 + /// + /// 任务ID + /// JSON格式的任务信息 public string GetTaskInfoByTid(string tid) { string sql = $"SELECT * FROM t_tasks_info WHERE `tid` =@tid"; @@ -222,6 +259,14 @@ namespace iFileProxy.Helpers finally { conn.Close(); } } + /// + /// 查询任务信息 + /// + /// 文件名 + /// URL + /// 文件大小 + /// 任务状态 + /// 任务信息对象,如果未找到则返回null public TaskInfo? QueryTaskInfo(string fileName, string url, long size, TaskState status) { string sql = $"SELECT * FROM t_tasks_info WHERE url = @url AND size = @size AND `status` = @status AND file_name = @fileName"; @@ -250,6 +295,11 @@ namespace iFileProxy.Helpers } + /// + /// 插入任务数据 + /// + /// 任务信息对象 + /// 是否插入成功 public bool InsertTaskData(TaskInfo taskInfo) { _logger.Debug(System.Text.Json.JsonSerializer.Serialize(taskInfo)); @@ -284,7 +334,15 @@ namespace iFileProxy.Helpers } return true; } - public bool UpdateFieldsData(string fieldsName, string key,string val) + + /// + /// 更新指定字段的数据 + /// + /// 字段名 + /// 主键值 + /// 更新值 + /// 是否更新成功 + public bool UpdateFieldsData(string fieldsName, string key, string val) { string sql = $"UPDATE t_tasks_info set `{fieldsName}` = @Data WHERE `tid` = @tid"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); @@ -312,6 +370,11 @@ namespace iFileProxy.Helpers } + /// + /// 更新任务状态 + /// + /// 任务信息对象 + /// 是否更新成功 public bool UpdateTaskStatus(TaskInfo taskInfo) { string sql = @"UPDATE t_tasks_info set `status` = @status , update_time = Now() WHERE `tid` = @tid"; @@ -341,16 +404,21 @@ namespace iFileProxy.Helpers } } + /// + /// 更新任务的哈希值 + /// + /// 任务信息对象 + /// 是否更新成功 public bool UpdateTaskHash(TaskInfo taskInfo) { return UpdateFieldsData("hash", taskInfo.TaskId, MasterHelper.GetFileHash(Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName), FileHashAlgorithm.MD5)); } /// - /// 删除指定IP的任务信息 + /// 删除指定IP地址的所有任务信息 /// - /// - /// + /// IP地址 + /// 受影响的行数,-1表示操作失败 public int DeleteTaskInfoByIpAddr(string ipAddr) { try @@ -364,6 +432,12 @@ namespace iFileProxy.Helpers } } + /// + /// 尝试初始化数据库 + /// + /// + /// 创建必要的数据库表结构 + /// public void TryInitialDB() { string sql = """ @@ -398,5 +472,58 @@ namespace iFileProxy.Helpers conn.Close(); } } + + /// + /// 执行标量查询 + /// + /// 返回值类型 + /// SQL查询语句 + /// 查询参数 + /// 查询结果 + public T ExecuteScalar(string sql, Dictionary parameters) + { + using var conn = GetAndOpenDBConn("iFileProxy_Db"); + using var cmd = new MySqlCommand(sql, conn); + foreach (var param in parameters) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + return (T)cmd.ExecuteScalar(); + } + + /// + /// 执行查询并返回实体列表 + /// + /// 实体类型 + /// SQL查询语句 + /// 查询参数 + /// 实体列表 + public List ExecuteQuery(string sql, Dictionary parameters) + { + using var conn = GetAndOpenDBConn("iFileProxy_Db"); + using var cmd = new MySqlCommand(sql, conn); + foreach (var param in parameters) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + return JsonConvert.DeserializeObject>(QueryTableData(cmd)); + } + + /// + /// 执行非查询SQL命令 + /// + /// SQL命令 + /// 命令参数 + /// 受影响的行数 + public int ExecuteNonQuery(string sql, Dictionary parameters) + { + using var conn = GetAndOpenDBConn("iFileProxy_Db"); + using var cmd = new MySqlCommand(sql, conn); + foreach (var param in parameters) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + return cmd.ExecuteNonQuery(); + } } } diff --git a/src/Services/LocalCacheManager.cs b/src/Services/LocalCacheManager.cs index c845a1e..a003150 100644 --- a/src/Services/LocalCacheManager.cs +++ b/src/Services/LocalCacheManager.cs @@ -17,17 +17,17 @@ namespace iFileProxy.Services private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); private readonly Timer _timer; - private readonly DatabaseHelper _dbHelper; + private readonly DatabaseGateService _dbGateService; private readonly int CACHE_LIFETIME; /// /// 缓存管理器 /// - public LocalCacheManager() + public LocalCacheManager(IServiceProvider serviceProvider) { _logger.Information("Initializing LocalCacheManager."); CACHE_LIFETIME = _appConfig.DownloadOptions.CacheLifetime; - _dbHelper = new DatabaseHelper(_appConfig); + _dbGateService = serviceProvider.GetRequiredService(); // 开始定时清理任务 _timer = new Timer(CheckAndCleanCache, null, TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(60)); _logger.Information("succ."); @@ -39,7 +39,7 @@ namespace iFileProxy.Services public void CheckAndCleanCache(object state) { // 获取数据库中超出生命周期的缓存数据 - string result = _dbHelper.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy); + string result = _dbGateService.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy); List? taskInfos = JsonConvert.DeserializeObject>(result); if (taskInfos != null) { @@ -59,9 +59,9 @@ namespace iFileProxy.Services throw; } } - _dbHelper.Query($"UPDATE t_tasks_info SET `tag` = \"CLEANED\" WHERE `tid` = '{taskInfo.TaskId}'", DbConfigName.iFileProxy); + _dbGateService.Query($"UPDATE t_tasks_info SET `tag` = \"CLEANED\" WHERE `tid` = '{taskInfo.TaskId}'", DbConfigName.iFileProxy); taskInfo.Status = TaskState.Cleaned; - _dbHelper.UpdateTaskStatus(taskInfo); + _dbGateService.UpdateTaskStatus(taskInfo); } } } diff --git a/src/Services/TaskManager.cs b/src/Services/TaskManager.cs index 9a7ddc3..3365009 100644 --- a/src/Services/TaskManager.cs +++ b/src/Services/TaskManager.cs @@ -1,7 +1,6 @@ using iFileProxy.Config; using iFileProxy.Helpers; using iFileProxy.Models; -using Org.BouncyCastle.Asn1.Tsp; using Serilog; using System.Diagnostics; using System.Text.Json; @@ -50,16 +49,16 @@ namespace iFileProxy.Services private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); private readonly AppConfig? _appConfig = AppConfig.GetCurrConfig("iFileProxy.json"); - private readonly DatabaseHelper _dbHelper; + private readonly DatabaseGateService _dbGateService; private Dictionary _runningTasks = []; private Queue _pendingTasks = new(); private readonly object _taskLock = new(); - public TaskManager() + public TaskManager(IServiceProvider serviceProvider) { _logger.Information("Initializing TaskManager..."); if (_appConfig != null) - _dbHelper = new DatabaseHelper(_appConfig); + _dbGateService = serviceProvider.GetRequiredService(); else { _logger.Fatal($"Failed to load application configuration"); @@ -140,7 +139,7 @@ namespace iFileProxy.Services if (MasterHelper.CheckDownloadFileExists(taskInfo.FileName)) { - var r = _dbHelper.QueryTaskInfo(taskInfo.FileName, taskInfo.Url, taskInfo.Size, TaskState.End); + var r = _dbGateService.QueryTaskInfo(taskInfo.FileName, taskInfo.Url, taskInfo.Size, TaskState.End); if (r != null) { taskInfo.Status = TaskState.Cached; @@ -163,7 +162,7 @@ namespace iFileProxy.Services /// public TaskAddState AddTaskInfoToDb(TaskInfo taskInfo, bool queuing = false) { - if (_dbHelper.InsertTaskData(taskInfo)) + if (_dbGateService.InsertTaskData(taskInfo)) { if (!queuing) // 如果不是正在排队的任务 { @@ -178,7 +177,7 @@ namespace iFileProxy.Services { taskInfo.Status = TaskState.Queuing; } - _dbHelper.UpdateTaskStatus(taskInfo); + _dbGateService.UpdateTaskStatus(taskInfo); return TaskAddState.Success; } @@ -222,7 +221,7 @@ namespace iFileProxy.Services if (taskInfo.Status != TaskState.Running) { taskInfo.Status = TaskState.Running; - _dbHelper.UpdateTaskStatus(taskInfo); + _dbGateService.UpdateTaskStatus(taskInfo); } _logger.Information($"[TaskId: {taskInfo.TaskId}] Started."); aria2c.BeginOutputReadLine(); @@ -237,14 +236,14 @@ namespace iFileProxy.Services { _logger.Error($"task: {taskInfo.TaskId} 进程退出状态异常 ExitCode: {aria2c.ExitCode}"); taskInfo.Status = TaskState.Error; - _dbHelper.UpdateTaskStatus(taskInfo); + _dbGateService.UpdateTaskStatus(taskInfo); } else { taskInfo.Status = TaskState.End; - _dbHelper.UpdateTaskStatus(taskInfo); + _dbGateService.UpdateTaskStatus(taskInfo); taskInfo.Hash = MasterHelper.GetFileHash(Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName), FileHashAlgorithm.MD5); - _dbHelper.UpdateTaskHash(taskInfo); + _dbGateService.UpdateTaskHash(taskInfo); } // 触发任务完成事件 @@ -282,7 +281,7 @@ namespace iFileProxy.Services public List GetTaskListByIpAddr(HttpContext c) { string? clientIp = MasterHelper.GetClientIPAddr(c); - return JsonSerializer.Deserialize>(_dbHelper.GetTaskListByIP(clientIp)) ?? []; + return JsonSerializer.Deserialize>(_dbGateService.GetTaskListByIP(clientIp)) ?? []; } /// @@ -292,8 +291,8 @@ namespace iFileProxy.Services /// public List GetTaskInfo(string taskId) { - _logger.Debug(_dbHelper.GetTaskInfoByTid(taskId)); - return JsonSerializer.Deserialize>(_dbHelper.GetTaskInfoByTid(taskId)) ?? []; + _logger.Debug(_dbGateService.GetTaskInfoByTid(taskId)); + return JsonSerializer.Deserialize>(_dbGateService.GetTaskInfoByTid(taskId)) ?? []; } public Dictionary GetRunningTasks() => _runningTasks; @@ -333,9 +332,54 @@ namespace iFileProxy.Services return new ServerTaskLoadInfo { Queuing = _pendingTasks.Count , Running = _runningTasks.Count}; } + /// + /// 尝试中断指定的任务 + /// + /// 要中断的任务信息 + /// 是否成功中断任务 public void TryKillTask(TaskInfo taskInfo) - { - + { + try + { + // 检查任务是否在运行中 + if (_runningTasks.TryGetValue(taskInfo.TaskId, out var runningTask)) + { + _logger.Information($"正在尝试中断任务: {taskInfo.TaskId}"); + + // 从运行任务字典中移除 + _runningTasks.Remove(taskInfo.TaskId); + + // 更新任务状态为错误 + taskInfo.Status = TaskState.Canceled; + _dbGateService.UpdateTaskStatus(taskInfo); + + // 删除未完成的文件 + var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName); + if (File.Exists(filePath)) + { + File.Delete(filePath); + _logger.Debug($"已删除未完成的文件: {filePath}"); + } + + // 删除aria2c的临时文件 + if (File.Exists(filePath + ".aria2")) + { + File.Delete(filePath + ".aria2"); + _logger.Debug("已删除aria2临时文件"); + } + + _logger.Information($"任务 {taskInfo.TaskId} 已中断"); + } + else + { + _logger.Warning($"任务 {taskInfo.TaskId} 不在运行状态,无需中断"); + } + } + catch (Exception ex) + { + _logger.Error($"中断任务时发生错误: {ex.Message}"); + throw; + } } //public bool DeleteTask(HttpContext c)