优化下载内存占用 添加下载者统计

This commit is contained in:
root 2024-12-07 17:02:41 +08:00
parent c4fbd572cc
commit d09dcf7ecf
4 changed files with 164 additions and 34 deletions

View file

@ -436,5 +436,44 @@ namespace iFileProxy.Controllers
});
}
}
/// <summary>
/// 获取任务的下载历史
/// </summary>
[HttpGet("GetDownloadHistory/{taskId}")]
public async Task<ActionResult<CommonRsp>> GetDownloadHistory(string taskId)
{
try
{
// 先检查任务是否存在
var taskInfo = JsonSerializer.Deserialize<List<TaskInfo>>(_dbGateService.GetTaskInfoByTid(taskId))?[0];
if (taskInfo == null)
{
return Ok(new CommonRsp
{
Retcode = 1,
Message = "任务不存在"
});
}
var history = await _dbGateService.GetDownloadHistoryByTaskIdAsync(taskId);
return Ok(new CommonRsp
{
Retcode = 0,
Message = "success",
Data = history
});
}
catch (Exception ex)
{
_logger.Error(ex, "获取下载历史失败");
return Ok(new CommonRsp
{
Retcode = 1,
Message = "获取下载历史失败"
});
}
}
}
}

View file

@ -2,7 +2,7 @@
using iFileProxy.Helpers;
using iFileProxy.Models;
using iFileProxy.Services;
using Serilog;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
@ -12,11 +12,16 @@ namespace iFileProxy.Controllers
{
private readonly TaskManager _taskManager;
private readonly AppConfig _appConfig;
private readonly DatabaseGateService _dbGate;
public iProxyController(TaskManager taskManager, AppConfig appConfig)
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<iProxyController>();
public iProxyController(TaskManager taskManager, AppConfig appConfig, DatabaseGateService databaseGateService)
{
_taskManager = taskManager;
_appConfig = appConfig;
_dbGate = databaseGateService;
}
[HttpPost]
@ -72,44 +77,81 @@ namespace iFileProxy.Controllers
[Route("/Download/{taskID}")]
public async Task<IActionResult> DownloadFile(string taskID)
{
string fileName = "";
var d = _taskManager.GetTaskListByIpAddr(HttpContext);
var taskInfo = _taskManager.GetTaskInfo(taskID);
if ((!_appConfig.SecurityOptions.AllowDifferentIPsForDownload && d.Where(x => x.TaskId == taskID).Any()) || taskInfo != null)
try
{
if (_appConfig.SecurityOptions.AllowDifferentIPsForDownload)
{
fileName = taskInfo[0].FileName;
}
else
{
fileName = d.Where(x => x.TaskId == taskID).FirstOrDefault()?.FileName;
}
if (fileName == null)
return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 });
string? fileName = null;
var d = _taskManager.GetTaskListByIpAddr(HttpContext);
var taskInfo = _taskManager.GetTaskInfo(taskID);
var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, fileName);
if (!MasterHelper.CheckDownloadFileExists(fileName))
if ((!_appConfig.SecurityOptions.AllowDifferentIPsForDownload && d.Where(x => x.TaskId == taskID).Any()) || taskInfo != null)
{
return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 });
}
// 获取文件的 MIME 类型
var provider = new FileExtensionContentTypeProvider();
string contentType;
if (!provider.TryGetContentType(filePath, out contentType))
{
contentType = "application/octet-stream"; // 默认 MIME 类型
if (_appConfig.SecurityOptions.AllowDifferentIPsForDownload)
{
fileName = taskInfo[0].FileName;
}
else
{
fileName = d.Where(x => x.TaskId == taskID).FirstOrDefault()?.FileName;
}
if (fileName == null)
{
return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 });
}
var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, fileName);
if (!MasterHelper.CheckDownloadFileExists(fileName))
{
return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 });
}
// 获取文件的 MIME 类型
var provider = new FileExtensionContentTypeProvider();
string contentType;
if (!provider.TryGetContentType(filePath, out contentType))
{
contentType = "application/octet-stream";
}
// 获取文件信息
var fileInfo = new FileInfo(filePath);
// 设置响应头
Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{fileName}\"");
Response.Headers.Add("Content-Length", fileInfo.Length.ToString());
// 使用 FileStream 进行流式传输
var fileStream = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
bufferSize: 81920, // 80KB 缓冲区
useAsync: true
);
// 记录下载历史
await _dbGate.AddDownloadHistoryAsync(taskID, MasterHelper.GetClientIPAddr(HttpContext));
// 返回文件流
return new FileStreamResult(fileStream, contentType)
{
EnableRangeProcessing = true, // 支持断点续传
FileDownloadName = fileName
};
}
// 读取文件内容
var fileContents = await System.IO.File.ReadAllBytesAsync(filePath);
// 返回文件内容
return File(fileContents, contentType, Path.GetFileName(filePath));
return Ok(new CommonRsp() { Message = "task_id not exists", Retcode = -1 });
}
catch (Exception ex)
{
_logger.Error("处理下载请求失败: {ex}", ex);
return Ok(new CommonRsp()
{
Message = $"download failed: {ex.Message}",
Retcode = -1
});
}
return Ok(new CommonRsp() { Message = "task_id not exists", Retcode = -1 });
}
}
}

View file

@ -183,4 +183,16 @@ namespace iFileProxy.Models
/// </summary>
public string Info { get; set; } = string.Empty;
}
public class DownloadHistory
{
[JsonProperty("tid")]
public string TaskId { get; set; } = string.Empty;
[JsonProperty("time")]
public DateTime Time { get; set; }
[JsonProperty("client_ip")]
public string ClientIP { get; set; } = string.Empty;
}
}

View file

@ -80,6 +80,16 @@ namespace iFileProxy.Services
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
""";
private const string CREATE_DOWNLOAD_HISTORY_TABLE_SQL = """
CREATE TABLE IF NOT EXISTS `t_download_history` (
`tid` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'UUID',
`time` datetime NULL DEFAULT NULL COMMENT '',
`client_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'IP',
PRIMARY KEY (`tid`) USING BTREE,
CONSTRAINT `t_download_history_ibfk_1` FOREIGN KEY (`tid`) REFERENCES `t_tasks_info` (`tid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
""";
public DatabaseGateService(AppConfig appConfig)
{
_logger.Information("Initializing DatabaseGateService...");
@ -1065,5 +1075,32 @@ namespace iFileProxy.Services
Data = logs
};
}
public async Task<List<DownloadHistory>> GetDownloadHistoryByTaskIdAsync(string taskId)
{
var sql = "SELECT * FROM t_download_history WHERE tid = @taskId ORDER BY time DESC";
var parameters = new Dictionary<string, object>
{
{ "@taskId", taskId }
};
return await ExecuteQueryAsync<DownloadHistory>(sql, parameters);
}
public async Task<bool> AddDownloadHistoryAsync(string taskId, string clientIp)
{
var sql = @"INSERT INTO t_download_history (tid, time, client_ip)
VALUES (@taskId, @time, @clientIp)";
var parameters = new Dictionary<string, object>
{
{ "@taskId", taskId },
{ "@time", DateTime.Now },
{ "@clientIp", clientIp }
};
var result = await ExecuteNonQueryAsync(sql, parameters);
return result > 0;
}
}
}