diff --git a/src/Controllers/VisitorManagementController.cs b/src/Controllers/VisitorManagementController.cs new file mode 100644 index 0000000..e406369 --- /dev/null +++ b/src/Controllers/VisitorManagementController.cs @@ -0,0 +1,51 @@ +using iFileProxy.Helpers; +using iFileProxy.Models; +using iFileProxy.Config; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Serilog; + +namespace iFileProxy.Controllers +{ + /// + /// 访客信息相关 + /// + [Route("/[controller]")] + [ApiController] + public class VisitorManagementController : ControllerBase + { + static DatabaseHelper _dbHelper = new DatabaseHelper(AppConfig.GetCurrConfig()); + private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); + + + [HttpDelete("DeleteInfo")] + public ActionResult DeleteInfo() + { + string ipAddr = MasterHelper.GetClientIPAddr(HttpContext); + var d = JsonConvert.DeserializeObject>(_dbHelper.GetTaskListByStateAndIp(ipAddr, TaskState.Running)); + int rd = (d != null) ? d.Count : 0; + if (rd <= 0) + { + d = JsonConvert.DeserializeObject>(_dbHelper.GetTaskListByIP(ipAddr)); + foreach (var taskInfo in d) + { + var dep = _dbHelper.CheckCacheDependencies(taskInfo.TaskId,ipAddr); + if (dep.Count <= 0) + { + if (MasterHelper.CheckDownloadFileExists(taskInfo.FileName)) + { + MasterHelper.RemoveDownloadFile(taskInfo.FileName); + _logger.Information("[客户端主动申请删除信息数据] 正在删除文件: {f}", taskInfo.FileName); + } + } + else + _logger.Warning($"准备删除的文件正在被以下Task所依赖: {JsonConvert.SerializeObject(dep)} 文件将不会被删除"); + + } + return Ok(new CommonRsp() { Retcode = 0, Message = "succ", Data = _dbHelper.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 1d589da..18b3943 100644 --- a/src/Controllers/iProxyController.cs +++ b/src/Controllers/iProxyController.cs @@ -11,7 +11,6 @@ namespace iFileProxy.Controllers public class iProxyController : ControllerBase { static readonly TaskManager taskManager = new (); - static Dictionary> IPAccessCountDict = []; static AppConfig? appConfig = AppConfig.GetCurrConfig(); [HttpPost] @@ -82,10 +81,10 @@ namespace iFileProxy.Controllers fileName = d.Where(x => x.TaskId == taskID).FirstOrDefault()?.FileName; } if (fileName == null) - return Ok(new CommonRsp() { Message = "file not exists", Retcode = -1 }); + return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 }); var filePath = Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName); - if (!System.IO.File.Exists(filePath)) + if (!MasterHelper.CheckDownloadFileExists(fileName)) { return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 }); } diff --git a/src/Helpers/DatabaseHelper.cs b/src/Helpers/DatabaseHelper.cs index 4251ce7..88cb37f 100644 --- a/src/Helpers/DatabaseHelper.cs +++ b/src/Helpers/DatabaseHelper.cs @@ -146,6 +146,47 @@ namespace iFileProxy.Helpers return n; } + 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"); + try + { + using MySqlCommand sqlCmd = new(sql, conn); + sqlCmd.Parameters.AddWithValue("@tag", $"REDIRECT:{taskId}"); + sqlCmd.Parameters.AddWithValue("@status", TaskState.Cached); + sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr); + + return JsonConvert.DeserializeObject>( QueryTableData(sqlCmd)); + } + catch (Exception e) + { + _logger.Error($"无法获取任务列表: {e.Message}"); + throw; + } + finally { conn.Close(); } + } + + public string GetTaskListByStateAndIp(string ipAddr, TaskState status) + { + string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr AND `status` = @status"; + MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); + try + { + using MySqlCommand sqlCmd = new(sql, conn); + sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr); + sqlCmd.Parameters.AddWithValue ("@status", status); + return QueryTableData(sqlCmd); + } + catch (Exception e) + { + _logger.Error($"无法获取任务列表: {e.Message}"); + throw; + } + finally { conn.Close(); } + } + + public string GetTaskListByIP(string ipAddr) { string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr"; @@ -305,6 +346,24 @@ namespace iFileProxy.Helpers return UpdateFieldsData("hash", taskInfo.TaskId, MasterHelper.GetFileHash(Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName), FileHashAlgorithm.MD5)); } + /// + /// 删除指定IP的任务信息 + /// + /// + /// + public int DeleteTaskInfoByIpAddr(string ipAddr) + { + try + { + string sql = $"DELETE FROM `t_tasks_info` WHERE `client_ip` = '{ipAddr}'"; + return Query(sql,DbConfigName.iFileProxy); + } + catch (Exception) + { + return -1; + } + } + public void TryInitialDB() { string sql = """ diff --git a/src/Helpers/MasterHelper.cs b/src/Helpers/MasterHelper.cs index 847ec5e..6a3a7bc 100644 --- a/src/Helpers/MasterHelper.cs +++ b/src/Helpers/MasterHelper.cs @@ -1,14 +1,17 @@ using iFileProxy.Config; using iFileProxy.Models; +using Serilog; +using System.Net; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace iFileProxy.Helpers { public class MasterHelper { + private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); + /// /// 检测链接是否为合法的网址格式 /// @@ -59,7 +62,10 @@ namespace iFileProxy.Helpers { clientIp = c.Connection.RemoteIpAddress?.ToString(); } - return clientIp; + IPAddress? ipAddress = null; + if (IPAddress.TryParse(clientIp, out ipAddress)) + return ipAddress.ToString(); + return null; } /// @@ -68,12 +74,44 @@ namespace iFileProxy.Helpers /// /// public static bool CheckDownloadFileExists(string fileName) - { - if (File.Exists(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath,fileName))) + { + if (File.Exists(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName))) + { + _logger.Debug("文件存在: {fileName}", fileName); return true; + } + _logger.Debug("文件不存在: {fileName}", fileName); + return false; } + /// + /// 删除指定的已下载文件 + /// + /// + /// + public static bool RemoveDownloadFile(string fileName) + { + var f = Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName); + if (File.Exists(f)) + { + try + { + File.Delete(f); + if (File.Exists(f + ".aria2")) + File.Delete(f + ".aria2"); // aria2c的临时文件 + return true; + } + catch (Exception) + { + return false; + throw; + } + } + else + return false; + } + /// /// 获取文件哈希 /// diff --git a/src/Models/Db.cs b/src/Models/Db.cs index fe21509..fde96d1 100644 --- a/src/Models/Db.cs +++ b/src/Models/Db.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; namespace iFileProxy.Models @@ -52,6 +53,10 @@ namespace iFileProxy.Models [JsonProperty("queue_position")] [JsonPropertyName("queue_position")] public int QueuePosition { get; set; } + + [System.Text.Json.Serialization.JsonIgnore] + [Newtonsoft.Json.JsonIgnore] + public Process Process { get; set; } } public class DbConfigName { diff --git a/src/Program.cs b/src/Program.cs index 60e67e5..7a5857d 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,5 +1,6 @@ using iFileProxy.Config; +using iFileProxy.Helpers; using iFileProxy.Middleware; using iFileProxy.Services; using Serilog; @@ -37,7 +38,7 @@ namespace iFileProxy { options.EnrichDiagnosticContext = (diagCtx, httpCtx) => { - diagCtx.Set("ClientIp", httpCtx.Connection.RemoteIpAddress?.ToString()); + diagCtx.Set("ClientIp", MasterHelper.GetClientIPAddr(httpCtx)); diagCtx.Set("contentType", httpCtx.Request.ContentType); diagCtx.Set("queryString", httpCtx.Request.QueryString); }; diff --git a/src/Services/TaskManager.cs b/src/Services/TaskManager.cs index 3975f22..205dbad 100644 --- a/src/Services/TaskManager.cs +++ b/src/Services/TaskManager.cs @@ -218,6 +218,7 @@ namespace iFileProxy.Services { _runningTasks.Add(taskInfo.TaskId, taskInfo); aria2c.Start(); + _runningTasks[taskInfo.TaskId].Process = aria2c; if (taskInfo.Status != TaskState.Running) { taskInfo.Status = TaskState.Running; @@ -331,6 +332,12 @@ namespace iFileProxy.Services { return new ServerTaskLoadInfo { Queuing = _pendingTasks.Count , Running = _runningTasks.Count}; } + + public void TryKillTask(TaskInfo taskInfo) + { + + } + //public bool DeleteTask(HttpContext c) //{ diff --git a/src/wwwroot/delete_my_info.html b/src/wwwroot/delete_my_info.html new file mode 100644 index 0000000..8aa01d9 --- /dev/null +++ b/src/wwwroot/delete_my_info.html @@ -0,0 +1,147 @@ + + + + + + 删除访客信息 + + + + + + +
+
正在加载数据...
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/src/wwwroot/index.html b/src/wwwroot/index.html index 64dccfc..ef2993e 100644 --- a/src/wwwroot/index.html +++ b/src/wwwroot/index.html @@ -42,9 +42,9 @@

-

运行中任务: 0 排队中任务:运行中任务: 0 排队中任务: 0

-

查询文件下载任务状态 | 捐赠

+

查询文件下载任务状态 | 捐赠 | 删除我的访客信息

Tips: 任务列表每个IP相互隔离,不必担心任务信息泄露

diff --git a/src/wwwroot/query_download_task.html b/src/wwwroot/query_download_task.html index 5928fd1..210b289 100644 --- a/src/wwwroot/query_download_task.html +++ b/src/wwwroot/query_download_task.html @@ -149,7 +149,7 @@

Tips: 任务列表每个IP相互隔离,不必担心任务信息泄露

-

返回主页 | 捐赠

+

返回主页 | 捐赠 | 删除我的访客信息

diff --git a/src/wwwroot/static/js/custom/Common.js b/src/wwwroot/static/js/custom/Common.js index e4b5cd9..8b5ed04 100644 --- a/src/wwwroot/static/js/custom/Common.js +++ b/src/wwwroot/static/js/custom/Common.js @@ -35,7 +35,7 @@ let tipsStr = [ "任务列表每个IP相互隔离,不必担心任务信息泄露。", "哈希算法为MD5。", "下载的文件不会永久存储在服务器上, 每隔一段时间服务器会自动清理那些文件, 并且任务状态会转变为 “已被清理”。", - "本站会收集一些访客信息用于访客数据分析, 若你不想被收集相关信息用于分析, 请点我自助删除已经存储在服务器上的信息(新加任务仍然会收集)。", + "本站会收集一些访客信息用于访客数据分析, 若你不想被收集相关信息用于分析, 请点我自助删除已经存储在服务器上的信息(新加任务仍然会收集)。", "服务器同时下载的任务达到限制时候, 新的任务会被加入队列(即 排队), 若队列达到管理员设置的最大值则不再接受新任务, 直至队列空出余量。", "本站为了节省成本和照顾其他访客的感受, 每个IP有一定的下载和任务提交配额, 达到限制后当天内不能再下载文件或者新增任务, 请勿浪费公共资源。" ];