使代码更加合理

This commit is contained in:
root 2024-11-30 12:11:40 +08:00
parent 69296bd413
commit bc589471f3
9 changed files with 284 additions and 88 deletions

View file

@ -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<DatabaseGateService>();
databaseHelper.TestDbConfig();
}
else

View file

@ -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<VisitorManagementController>();
@ -22,14 +27,14 @@ namespace iFileProxy.Controllers
public ActionResult<CommonRsp> DeleteInfo()
{
string ipAddr = MasterHelper.GetClientIPAddr(HttpContext);
var d = JsonConvert.DeserializeObject<List<TaskInfo>>(_dbHelper.GetTaskListByStateAndIp(ipAddr, TaskState.Running));
var d = JsonConvert.DeserializeObject<List<TaskInfo>>(_dbGateService.GetTaskListByStateAndIp(ipAddr, TaskState.Running));
int rd = (d != null) ? d.Count : 0;
if (rd <= 0)
{
d = JsonConvert.DeserializeObject<List<TaskInfo>>(_dbHelper.GetTaskListByIP(ipAddr));
d = JsonConvert.DeserializeObject<List<TaskInfo>>(_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 });

View file

@ -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<CommonRsp> AddOfflineTask()
{
return taskManager.AddTask(HttpContext) switch
return _taskManager.AddTask(HttpContext) switch
{
TaskAddState.Success => (ActionResult<CommonRsp>)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Success, Message = "succ" }),
TaskAddState.Fail => (ActionResult<CommonRsp>)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Fail, Message = "unkown error!" }),
@ -43,12 +49,12 @@ namespace iFileProxy.Controllers
[Route("/GetMyTasks")]
public ActionResult<CommonRsp> 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<CommonRsp> 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<IActionResult> 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 });

View file

@ -32,6 +32,10 @@
/// 正在排队
/// </summary>
Queuing = 6,
/// <summary>
/// 任务因为各种原因被取消
/// </summary>
Canceled = 7,
}
/// <summary>
/// 任务添加状态

View file

@ -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<Dictionary<string, Dictionary<string, uint>>>(serviceProvider =>
{
return new Dictionary<string, Dictionary<string, uint>>();
});
builder.Services.AddSingleton(AppConfig.GetCurrConfig());
builder.Services.AddSingleton<DatabaseGateService>();
builder.Services.AddSingleton<TaskManager>();
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<ErrorHandlerMiddleware>();
app.UseHttpsRedirection();
// 配置默认文件选项
@ -64,11 +76,9 @@ namespace iFileProxy
app.UseAuthorization();
var IPAccessCountDict = new Dictionary<string, Dictionary<string, uint>>();
var dailyRequestLimitPerIP = AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP;
app.UseMiddleware<IPAccessLimitMiddleware>(IPAccessCountDict, dailyRequestLimitPerIP);
app.UseMiddleware<ErrorHandlerMiddleware>(); // 错误处理中间件
app.UseMiddleware<IPAccessLimitMiddleware>(
app.Services.GetRequiredService<Dictionary<string, Dictionary<string, uint>>>(),
AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP);
app.MapControllers();

View file

@ -15,7 +15,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>e343bd8a-27ed-47e2-b50d-e3000730e65e</ProjectGuid>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>

View file

@ -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
/// <summary>
/// 数据库访问网关服务
/// 提供统一的数据库操作接口,管理数据库连接和查询
/// </summary>
public class DatabaseGateService
{
Database _db;
AppConfig _appConfig;
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<DatabaseHelper>();
private readonly Serilog.ILogger _logger = Log.Logger.ForContext<DatabaseGateService>();
Dictionary<string, DB> _dbDictionary = [];
public DatabaseHelper(AppConfig appConfig)
/// <summary>
/// 初始化数据库网关服务
/// </summary>
/// <param name="appConfig">应用程序配置</param>
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
}
/// <summary>
/// 加载数据库描述字典
/// 加载数据库配置字典
/// </summary>
public void LoadDbDict()
{
@ -43,13 +51,14 @@ namespace iFileProxy.Helpers
_logger.Debug($"Db Config: {item.Description} <=> {item.DatabaseName} Loaded.");
}
}
/// <summary>
/// 获取一个指定数据库的连接
/// 获取并打开指定数据库的连接
/// </summary>
/// <param name="db_desc">数据库描述字段 对应AppConfig的description字段</param>
/// <returns></returns>
/// <exception cref="Exception">若某些不允许为空的字段出现空值 则抛出此异常</exception>
///
/// <param name="db_desc">数据库描述符,对应配置文件中的 Description 字段</param>
/// <returns>已打开的数据库连接</returns>
/// <exception cref="Exception">当找不到匹配的数据库配置时抛出</exception>
/// <exception cref="NoNullAllowedException">当必需的配置字段为空时抛出</exception>
public MySqlConnection GetAndOpenDBConn(string db_desc)
{
if (!_dbDictionary.TryGetValue(db_desc, out DB Db))
@ -80,6 +89,10 @@ namespace iFileProxy.Helpers
return conn;
}
/// <summary>
/// 测试所有数据库配置的连接
/// </summary>
/// <returns>测试是否全部成功</returns>
public bool TestDbConfig()
{
foreach (var db in _dbDictionary)
@ -105,11 +118,10 @@ namespace iFileProxy.Helpers
}
/// <summary>
/// 获取一个json格式的数据表
/// 执行查询并返回 JSON 格式的结果
/// </summary>
/// <param name="sql"></param>
/// <param name="conn"></param>
/// <returns></returns>
/// <param name="sqlCmd">SQL 命令对象</param>
/// <returns>JSON 格式的查询结果</returns>
public static string QueryTableData(MySqlCommand sqlCmd)
{
DataTable dataTable = new();
@ -119,34 +131,43 @@ namespace iFileProxy.Helpers
}
/// <summary>
/// 获取一个json格式的数据表
/// 执行查询并返回 JSON 格式的结果
/// </summary>
/// <param name="sql"></param>
/// <param name="conn"></param>
/// <returns></returns>
public string QueryTableData(string sql,string dbConfName)
/// <param name="sql">SQL 查询语句</param>
/// <param name="dbConfName">数据库配置名称</param>
/// <returns>JSON 格式的查询结果</returns>
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);
}
/// <summary>
/// 内部查询数据专用 当此方法暴露给C端可能造成sql注入等安全问题
/// 执行非查询SQL语句
/// </summary>
/// <param name="sql">SQL语句</param>
/// <param name="dbConfName">配置文件中的Description字段</param>
/// <returns>影响的行数</returns>
/// <param name="dbConfName">数据库配置名称</param>
/// <returns>受影响的行数</returns>
/// <remarks>
/// 警告此方法仅供内部使用直接暴露给客户端可能导致SQL注入风险
/// </remarks>
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<TaskInfo> CheckCacheDependencies(string taskId,string ipAddr)
/// <summary>
/// 检查缓存依赖关系
/// </summary>
/// <param name="taskId">任务ID</param>
/// <param name="ipAddr">IP地址</param>
/// <returns>相关的任务信息列表</returns>
public List<TaskInfo> 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<List<TaskInfo>>( QueryTableData(sqlCmd));
return JsonConvert.DeserializeObject<List<TaskInfo>>(QueryTableData(sqlCmd));
}
catch (Exception e)
{
@ -167,6 +188,12 @@ namespace iFileProxy.Helpers
finally { conn.Close(); }
}
/// <summary>
/// 根据状态和IP地址获取任务列表
/// </summary>
/// <param name="ipAddr">IP地址</param>
/// <param name="status">任务状态</param>
/// <returns>JSON格式的任务列表</returns>
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(); }
}
/// <summary>
/// 根据IP地址获取任务列表
/// </summary>
/// <param name="ipAddr">IP地址</param>
/// <returns>JSON格式的任务列表</returns>
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(); }
}
/// <summary>
/// 根据任务ID获取任务信息
/// </summary>
/// <param name="tid">任务ID</param>
/// <returns>JSON格式的任务信息</returns>
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(); }
}
/// <summary>
/// 查询任务信息
/// </summary>
/// <param name="fileName">文件名</param>
/// <param name="url">URL</param>
/// <param name="size">文件大小</param>
/// <param name="status">任务状态</param>
/// <returns>任务信息对象如果未找到则返回null</returns>
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
}
/// <summary>
/// 插入任务数据
/// </summary>
/// <param name="taskInfo">任务信息对象</param>
/// <returns>是否插入成功</returns>
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)
/// <summary>
/// 更新指定字段的数据
/// </summary>
/// <param name="fieldsName">字段名</param>
/// <param name="key">主键值</param>
/// <param name="val">更新值</param>
/// <returns>是否更新成功</returns>
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
}
/// <summary>
/// 更新任务状态
/// </summary>
/// <param name="taskInfo">任务信息对象</param>
/// <returns>是否更新成功</returns>
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
}
}
/// <summary>
/// 更新任务的哈希值
/// </summary>
/// <param name="taskInfo">任务信息对象</param>
/// <returns>是否更新成功</returns>
public bool UpdateTaskHash(TaskInfo taskInfo)
{
return UpdateFieldsData("hash", taskInfo.TaskId, MasterHelper.GetFileHash(Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName), FileHashAlgorithm.MD5));
}
/// <summary>
/// 删除指定IP的任务信息
/// 删除指定IP地址所有任务信息
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
/// <param name="ipAddr">IP地址</param>
/// <returns>受影响的行数,-1表示操作失败</returns>
public int DeleteTaskInfoByIpAddr(string ipAddr)
{
try
@ -364,6 +432,12 @@ namespace iFileProxy.Helpers
}
}
/// <summary>
/// 尝试初始化数据库
/// </summary>
/// <remarks>
/// 创建必要的数据库表结构
/// </remarks>
public void TryInitialDB()
{
string sql = """
@ -398,5 +472,58 @@ namespace iFileProxy.Helpers
conn.Close();
}
}
/// <summary>
/// 执行标量查询
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="sql">SQL查询语句</param>
/// <param name="parameters">查询参数</param>
/// <returns>查询结果</returns>
public T ExecuteScalar<T>(string sql, Dictionary<string, object> 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();
}
/// <summary>
/// 执行查询并返回实体列表
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="sql">SQL查询语句</param>
/// <param name="parameters">查询参数</param>
/// <returns>实体列表</returns>
public List<T> ExecuteQuery<T>(string sql, Dictionary<string, object> 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<List<T>>(QueryTableData(cmd));
}
/// <summary>
/// 执行非查询SQL命令
/// </summary>
/// <param name="sql">SQL命令</param>
/// <param name="parameters">命令参数</param>
/// <returns>受影响的行数</returns>
public int ExecuteNonQuery(string sql, Dictionary<string, object> 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();
}
}
}

View file

@ -17,17 +17,17 @@ namespace iFileProxy.Services
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<LocalCacheManager>();
private readonly Timer _timer;
private readonly DatabaseHelper _dbHelper;
private readonly DatabaseGateService _dbGateService;
private readonly int CACHE_LIFETIME;
/// <summary>
/// 缓存管理器
/// </summary>
public LocalCacheManager()
public LocalCacheManager(IServiceProvider serviceProvider)
{
_logger.Information("Initializing LocalCacheManager.");
CACHE_LIFETIME = _appConfig.DownloadOptions.CacheLifetime;
_dbHelper = new DatabaseHelper(_appConfig);
_dbGateService = serviceProvider.GetRequiredService<DatabaseGateService>();
// 开始定时清理任务
_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<TaskInfo>? taskInfos = JsonConvert.DeserializeObject<List<TaskInfo>>(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);
}
}
}

View file

@ -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<TaskManager>();
private readonly AppConfig? _appConfig = AppConfig.GetCurrConfig("iFileProxy.json");
private readonly DatabaseHelper _dbHelper;
private readonly DatabaseGateService _dbGateService;
private Dictionary<string, TaskInfo> _runningTasks = [];
private Queue<TaskInfo> _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<DatabaseGateService>();
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
/// <returns></returns>
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<TaskInfo> GetTaskListByIpAddr(HttpContext c)
{
string? clientIp = MasterHelper.GetClientIPAddr(c);
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbHelper.GetTaskListByIP(clientIp)) ?? [];
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbGateService.GetTaskListByIP(clientIp)) ?? [];
}
/// <summary>
@ -292,8 +291,8 @@ namespace iFileProxy.Services
/// <returns></returns>
public List<TaskInfo> GetTaskInfo(string taskId)
{
_logger.Debug(_dbHelper.GetTaskInfoByTid(taskId));
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbHelper.GetTaskInfoByTid(taskId)) ?? [];
_logger.Debug(_dbGateService.GetTaskInfoByTid(taskId));
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbGateService.GetTaskInfoByTid(taskId)) ?? [];
}
public Dictionary<string, TaskInfo> GetRunningTasks() => _runningTasks;
@ -333,9 +332,54 @@ namespace iFileProxy.Services
return new ServerTaskLoadInfo { Queuing = _pendingTasks.Count , Running = _runningTasks.Count};
}
/// <summary>
/// 尝试中断指定的任务
/// </summary>
/// <param name="taskInfo">要中断的任务信息</param>
/// <returns>是否成功中断任务</returns>
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)