diff --git a/src/Controllers/iProxyController.cs b/src/Controllers/iProxyController.cs index e8766fd..1d589da 100644 --- a/src/Controllers/iProxyController.cs +++ b/src/Controllers/iProxyController.cs @@ -20,22 +20,22 @@ namespace iFileProxy.Controllers { 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!" }), - TaskAddState.ErrUrlRepeat => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrUrlRepeat, message = "此url已经在任务队列中,请勿重复提交" }), - TaskAddState.ErrTaskIdRepeat => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrTaskIdRepeat, message = "TaskIdRepeat!!!" }), - TaskAddState.ErrUrlInvalid => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrUrlInvalid, message = "非法Url" }), - TaskAddState.ErrDbFail => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrDbFail, message = "数据库数据提交失败!" }), - TaskAddState.ErrMaxParallelTasksLimit => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrMaxParallelTasksLimit, message = "服务端并行数量达到上限!" }), - TaskAddState.ErrFileSizeLimit => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrFileSizeLimit, message = "指定的文件大小超过系统最大限制!" }), - TaskAddState.ErrFileNameForbidden => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrFileNameForbidden, message = "文件名非法!" }), - TaskAddState.ErrIPForbidden => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrIPForbidden, message = "请求次数超过限制!" }), - TaskAddState.ErrTargetHostForbidden => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrTargetHostForbidden, message = "目标主机不在服务白名单内!" }), - TaskAddState.ErrGetFileInfo => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrGetFileInfo, message = "目标文件信息获取失败!" }), - TaskAddState.ErrQueueLengthLimit => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrQueueLengthLimit, message = "服务器任务队列已满 请稍候重试!" }), - TaskAddState.Pending => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.Pending, message = "已经添加到任务队列!" }), + 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!" }), + TaskAddState.ErrUrlRepeat => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrUrlRepeat, Message = "此url已经在任务队列中,请勿重复提交" }), + TaskAddState.ErrTaskIdRepeat => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrTaskIdRepeat, Message = "TaskIdRepeat!!!" }), + TaskAddState.ErrUrlInvalid => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrUrlInvalid, Message = "非法Url" }), + TaskAddState.ErrDbFail => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrDbFail, Message = "数据库数据提交失败!" }), + TaskAddState.ErrMaxParallelTasksLimit => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrMaxParallelTasksLimit, Message = "服务端并行数量达到上限!" }), + TaskAddState.ErrFileSizeLimit => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrFileSizeLimit, Message = "指定的文件大小超过系统最大限制!" }), + TaskAddState.ErrFileNameForbidden => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrFileNameForbidden, Message = "文件名非法!" }), + TaskAddState.ErrIPForbidden => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrIPForbidden, Message = "请求次数超过限制!" }), + TaskAddState.ErrTargetHostForbidden => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrTargetHostForbidden, Message = "目标主机不在服务白名单内!" }), + TaskAddState.ErrGetFileInfo => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrGetFileInfo, Message = "目标文件信息获取失败!" }), + TaskAddState.ErrQueueLengthLimit => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.ErrQueueLengthLimit, Message = "服务器任务队列已满 请稍候重试!" }), + TaskAddState.Pending => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Pending, Message = "已经添加到任务队列!" }), - _ => (ActionResult)Ok(new CommonRsp() { retcode = (int)TaskAddState.Success, message = "succ default" }), + _ => (ActionResult)Ok(new CommonRsp() { Retcode = (int)TaskAddState.Success, Message = "succ default" }), }; } @@ -52,7 +52,14 @@ namespace iFileProxy.Controllers d.QueuePosition = taskManager.GetQueuePosition(d.TaskId); } } - return Ok(new CommonRsp() { retcode = 0, data = data ,message = "succ" }); + return Ok(new CommonRsp() { Retcode = 0, Data = data ,Message = "succ" }); + } + + [HttpPost] + [HttpGet] + [Route("/GetServerLoad")] + public ActionResult GetServerLoad() { + return Ok(new CommonRsp { Retcode = 0, Message = "succ", Data = taskManager.GetServerTaskLoadInfo() }); } [HttpGet] @@ -75,12 +82,12 @@ 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", Retcode = -1 }); var filePath = Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName); if (!System.IO.File.Exists(filePath)) { - return Ok(new CommonRsp() { message = "file not exists", retcode = 1 }); + return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 }); } // 获取文件的 MIME 类型 var provider = new FileExtensionContentTypeProvider(); @@ -96,7 +103,7 @@ namespace iFileProxy.Controllers // 返回文件内容 return File(fileContents, contentType, Path.GetFileName(filePath)); } - return Ok(new CommonRsp() { message = "task_id not exists", retcode = -1 }); + return Ok(new CommonRsp() { Message = "task_id not exists", Retcode = -1 }); } } diff --git a/src/Helpers/DatabaseHelper.cs b/src/Helpers/DatabaseHelper.cs index e79d919..4251ce7 100644 --- a/src/Helpers/DatabaseHelper.cs +++ b/src/Helpers/DatabaseHelper.cs @@ -14,7 +14,7 @@ namespace iFileProxy.Helpers AppConfig _appConfig; private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); - Dictionary _dbDictionary = new Dictionary(); + Dictionary _dbDictionary = []; public DatabaseHelper(AppConfig appConfig) { @@ -245,12 +245,12 @@ namespace iFileProxy.Helpers } public bool UpdateFieldsData(string fieldsName, string key,string val) { - string sql = $"UPDATE t_tasks_info set `{fieldsName}` = @data WHERE `tid` = @tid"; + string sql = $"UPDATE t_tasks_info set `{fieldsName}` = @Data WHERE `tid` = @tid"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new(sql, conn); - sqlCmd.Parameters.AddWithValue("@data",val); + sqlCmd.Parameters.AddWithValue("@Data",val); sqlCmd.Parameters.AddWithValue("@tid",key); if (sqlCmd.ExecuteNonQuery() == 1) { @@ -261,7 +261,7 @@ namespace iFileProxy.Helpers } catch (Exception) { - _logger.Fatal($"Task data update error."); + _logger.Fatal($"Task Data update error."); throw; } finally diff --git a/src/Helpers/MasterHelper.cs b/src/Helpers/MasterHelper.cs index 7a95752..847ec5e 100644 --- a/src/Helpers/MasterHelper.cs +++ b/src/Helpers/MasterHelper.cs @@ -45,6 +45,11 @@ namespace iFileProxy.Helpers return randomNumber; } + /// + /// 获取客户端IP地址 + /// + /// HttpContext + /// public static string? GetClientIPAddr(HttpContext c) { // 尝试从 X-Forwarded-For 请求头获取客户端IP地址 @@ -57,6 +62,11 @@ namespace iFileProxy.Helpers return clientIp; } + /// + /// 检查要下载的文件是否存在 + /// + /// + /// public static bool CheckDownloadFileExists(string fileName) { if (File.Exists(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath,fileName))) @@ -64,6 +74,12 @@ namespace iFileProxy.Helpers return false; } + /// + /// 获取文件哈希 + /// + /// 文件路径 + /// 哈希算法 + /// public static string GetFileHash(string fileName, FileHashAlgorithm algorithm) { byte[] hash = []; diff --git a/src/Middleware/ErrorHandlerMiddleware.cs b/src/Middleware/ErrorHandlerMiddleware.cs index ad54357..080a4a0 100644 --- a/src/Middleware/ErrorHandlerMiddleware.cs +++ b/src/Middleware/ErrorHandlerMiddleware.cs @@ -31,7 +31,7 @@ namespace iFileProxy if (context.Response.StatusCode == 404) { context.Response.ContentType = "application/json"; - await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { retcode = 404, message = "this route not exists." })); + await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { Retcode = 404, Message = "this route not exists." })); } } @@ -63,7 +63,7 @@ namespace iFileProxy context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)code; - return context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { retcode = 1, message = "server internal error" })); + return context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { Retcode = 1, Message = "server internal error" })); } } } diff --git a/src/Middleware/IPAccessLimitMiddleware.cs b/src/Middleware/IPAccessLimitMiddleware.cs index d030c65..5c161e5 100644 --- a/src/Middleware/IPAccessLimitMiddleware.cs +++ b/src/Middleware/IPAccessLimitMiddleware.cs @@ -56,7 +56,7 @@ { context.Response.StatusCode = 200; context.Response.ContentType = "application/json"; - await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { retcode = 403, message = "请求次数超过限制!" })); + await context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { Retcode = 403, Message = "请求次数超过限制!" })); return; } _IPAccessCountDict[dateStr][ipStr]++; diff --git a/src/Models/CommonRsp.cs b/src/Models/CommonRsp.cs index 24811cd..7c0a6dc 100644 --- a/src/Models/CommonRsp.cs +++ b/src/Models/CommonRsp.cs @@ -1,9 +1,12 @@ namespace iFileProxy.Models { + /// + /// 通用Http Response + /// public class CommonRsp { - public string message { get; set; } - public object data { get; set; } - public int retcode { get; set; } + public string Message { get; set; } = "def msg"; + public object Data { get; set; } = new object(); + public int Retcode { get; set; } } } diff --git a/src/Models/Security.cs b/src/Models/Security.cs new file mode 100644 index 0000000..f6cc279 --- /dev/null +++ b/src/Models/Security.cs @@ -0,0 +1,14 @@ +namespace iFileProxy.Models +{ + /// + /// 计算文件Hash类型 + /// + public enum FileHashAlgorithm + { + MD5, + SHA1, + SHA256, + SHA384, + SHA512, + } +} diff --git a/src/Models/Task.cs b/src/Models/Task.cs index 2a7cacd..1926d99 100644 --- a/src/Models/Task.cs +++ b/src/Models/Task.cs @@ -1,40 +1,121 @@ namespace iFileProxy.Models { - public enum TaskState { - NoInit = 0, // 还未初始化 - Running = 1, // 正在进行 - Error = 2, // 任务执行时候发生错误 已经结束 - End = 3, // 任务正常结束 - Cached = 4, // 要下载的内容已经缓存 - Cleaned =5, // 内容过期已被清理 - Queuing = 6, // 正在排队 + /// + /// 任务状态 + /// + public enum TaskState { + /// + /// 还未初始化 + /// + NoInit = 0, + /// + /// 正在进行 + /// + Running = 1, + /// + /// 任务执行时候发生错误 已经结束 + /// + Error = 2, + /// + /// 任务正常结束 + /// + End = 3, + /// + /// 要下载的内容已经缓存 + /// + Cached = 4, + /// + /// 内容过期已被清理 + /// + Cleaned = 5, + /// + /// 正在排队 + /// + Queuing = 6, } + /// + /// 任务添加状态 + /// public enum TaskAddState { + /// + /// 成功 + /// Success = 0, + /// + /// 失败 + /// Fail = 1, + /// + /// Url重复 + /// ErrUrlRepeat = 2, + /// + /// taskId重复 + /// ErrTaskIdRepeat = 3, + /// + /// Url无效 + /// ErrUrlInvalid = 4, + /// + /// 数据库过程失败 + /// ErrDbFail = 5, + /// + /// 并行任务达到设定最大值 + /// ErrMaxParallelTasksLimit = 6, + /// + /// 文件大小达到设定最大值 + /// ErrFileSizeLimit = 7, + /// + /// 指定的主机已经被管理员拉入黑名单 + /// ErrTargetHostForbidden = 8, + /// + /// 禁止的文件名 + /// ErrFileNameForbidden = 9, + /// + /// 来访者IP被管理员拉入黑名单 + /// ErrIPForbidden = 10, + /// + /// 获取下载信息时候出现错误 + /// ErrGetFileInfo = 11, + /// + /// 正在等待任务执行 + /// Pending = 12, + /// + /// 队列大小达到设定最大值 + /// ErrQueueLengthLimit = 13, } - public enum FileHashAlgorithm - { - MD5, - SHA1, - SHA256, - SHA384, - SHA512, - } public class DownloadFileInfo { + /// + /// 文件名 + /// public string FileName { get; set; } + /// + /// 文件大小 + /// public long Size { get; set; } } + + /// + /// 任务负载信息 + /// + public class ServerTaskLoadInfo { + /// + /// 正在运行的任务数 + /// + public int Running { get; set; } + /// + /// 正在队列中的任务数 + /// + public int Queuing { get; set; } + } } \ No newline at end of file diff --git a/src/Services/LocalCacheManager.cs b/src/Services/LocalCacheManager.cs index 8434d69..c845a1e 100644 --- a/src/Services/LocalCacheManager.cs +++ b/src/Services/LocalCacheManager.cs @@ -20,11 +20,15 @@ namespace iFileProxy.Services private readonly DatabaseHelper _dbHelper; private readonly int CACHE_LIFETIME; + /// + /// 缓存管理器 + /// public LocalCacheManager() { _logger.Information("Initializing LocalCacheManager."); CACHE_LIFETIME = _appConfig.DownloadOptions.CacheLifetime; _dbHelper = new DatabaseHelper(_appConfig); + // 开始定时清理任务 _timer = new Timer(CheckAndCleanCache, null, TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(60)); _logger.Information("succ."); } diff --git a/src/Services/TaskManager.cs b/src/Services/TaskManager.cs index e9cb825..3975f22 100644 --- a/src/Services/TaskManager.cs +++ b/src/Services/TaskManager.cs @@ -41,7 +41,7 @@ namespace iFileProxy.Services for (int i = 0; i < add_task_num; i++) // 运行的任务中不足最大并行数并且有正在队列的task时候添加足够多的任务 { TaskInfo nextTask = _pendingTasks.Dequeue(); - Task.Run(() => StartTask(nextTask)).ConfigureAwait(false); + Task.Run(() => StartTaskAsync(nextTask)).ConfigureAwait(false); } } } @@ -155,6 +155,12 @@ namespace iFileProxy.Services } + /// + /// 添加任务信息到数据库并开始任务 + /// + /// 任务信息 + /// 是否正在排队 若正在排队则不开始任务 等待任务调度 + /// public TaskAddState AddTaskInfoToDb(TaskInfo taskInfo, bool queuing = false) { if (_dbHelper.InsertTaskData(taskInfo)) @@ -163,7 +169,7 @@ namespace iFileProxy.Services { if (taskInfo.Status != TaskState.Cached) { - StartTask(taskInfo); + StartTaskAsync(taskInfo); taskInfo.Status = TaskState.Running; } _logger.Debug($"[TaskId: {taskInfo.TaskId}] Add to Database Successful."); @@ -180,7 +186,12 @@ namespace iFileProxy.Services return TaskAddState.ErrDbFail; } - public async Task StartTask(TaskInfo taskInfo) + /// + /// 开始任务 + /// + /// 任务信息 + /// + public async Task StartTaskAsync(TaskInfo taskInfo) { if (_runningTasks.ContainsKey(taskInfo.TaskId)) { @@ -262,12 +273,22 @@ namespace iFileProxy.Services _logger.Debug($"[TaskId: {c.StartInfo.Environment["TaskId"]}] {e.Data}"); } + /// + /// 基于IP地址查询下载列表 + /// + /// + /// public List GetTaskListByIpAddr(HttpContext c) { string? clientIp = MasterHelper.GetClientIPAddr(c); return JsonSerializer.Deserialize>(_dbHelper.GetTaskListByIP(clientIp)) ?? []; } + /// + /// 获取任务信息 + /// + /// + /// public List GetTaskInfo(string taskId) { _logger.Debug(_dbHelper.GetTaskInfoByTid(taskId)); @@ -276,6 +297,11 @@ namespace iFileProxy.Services public Dictionary GetRunningTasks() => _runningTasks; + /// + /// 获取task在队列中的位置 + /// + /// + /// public int GetQueuePosition(string taskId) { int position = -1; // 默认值表示未找到 @@ -296,6 +322,15 @@ namespace iFileProxy.Services return position; } + + /// + /// 获取服务器任务负载信息 + /// + /// + public ServerTaskLoadInfo GetServerTaskLoadInfo() + { + return new ServerTaskLoadInfo { Queuing = _pendingTasks.Count , Running = _runningTasks.Count}; + } //public bool DeleteTask(HttpContext c) //{ diff --git a/src/wwwroot/index.html b/src/wwwroot/index.html index 74dab1a..7ba28ff 100644 --- a/src/wwwroot/index.html +++ b/src/wwwroot/index.html @@ -42,6 +42,8 @@

+

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

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

@@ -74,6 +76,18 @@ } }); }); + // 加载服务器负载信息 + $.ajax({ + type: "GET", + url: "/GetServerLoad", + dataType: "json", + success: function (response) { + if (response.retcode == 0) { + running_count.textContent = response.data.running; + queuing_count.textContent = response.data.queuing; + } + } + }); });