优化下载内存占用 添加下载者统计
This commit is contained in:
parent
c4fbd572cc
commit
d09dcf7ecf
4 changed files with 164 additions and 34 deletions
|
@ -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 = "获取下载历史失败"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using iFileProxy.Helpers;
|
using iFileProxy.Helpers;
|
||||||
using iFileProxy.Models;
|
using iFileProxy.Models;
|
||||||
using iFileProxy.Services;
|
using iFileProxy.Services;
|
||||||
|
using Serilog;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
|
|
||||||
|
@ -12,11 +12,16 @@ namespace iFileProxy.Controllers
|
||||||
{
|
{
|
||||||
private readonly TaskManager _taskManager;
|
private readonly TaskManager _taskManager;
|
||||||
private readonly AppConfig _appConfig;
|
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;
|
_taskManager = taskManager;
|
||||||
_appConfig = appConfig;
|
_appConfig = appConfig;
|
||||||
|
_dbGate = databaseGateService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
@ -72,7 +77,9 @@ namespace iFileProxy.Controllers
|
||||||
[Route("/Download/{taskID}")]
|
[Route("/Download/{taskID}")]
|
||||||
public async Task<IActionResult> DownloadFile(string taskID)
|
public async Task<IActionResult> DownloadFile(string taskID)
|
||||||
{
|
{
|
||||||
string fileName = "";
|
try
|
||||||
|
{
|
||||||
|
string? fileName = null;
|
||||||
var d = _taskManager.GetTaskListByIpAddr(HttpContext);
|
var d = _taskManager.GetTaskListByIpAddr(HttpContext);
|
||||||
var taskInfo = _taskManager.GetTaskInfo(taskID);
|
var taskInfo = _taskManager.GetTaskInfo(taskID);
|
||||||
|
|
||||||
|
@ -86,30 +93,65 @@ namespace iFileProxy.Controllers
|
||||||
{
|
{
|
||||||
fileName = d.Where(x => x.TaskId == taskID).FirstOrDefault()?.FileName;
|
fileName = d.Where(x => x.TaskId == taskID).FirstOrDefault()?.FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
|
{
|
||||||
return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 });
|
return Ok(new CommonRsp() { Message = "file not exists or taskId error", Retcode = -1 });
|
||||||
|
}
|
||||||
|
|
||||||
var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, fileName);
|
var filePath = Path.Combine(_appConfig.DownloadOptions.SavePath, fileName);
|
||||||
if (!MasterHelper.CheckDownloadFileExists(fileName))
|
if (!MasterHelper.CheckDownloadFileExists(fileName))
|
||||||
{
|
{
|
||||||
return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 });
|
return Ok(new CommonRsp() { Message = "file not exists", Retcode = 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件的 MIME 类型
|
// 获取文件的 MIME 类型
|
||||||
var provider = new FileExtensionContentTypeProvider();
|
var provider = new FileExtensionContentTypeProvider();
|
||||||
string contentType;
|
string contentType;
|
||||||
if (!provider.TryGetContentType(filePath, out contentType))
|
if (!provider.TryGetContentType(filePath, out contentType))
|
||||||
{
|
{
|
||||||
contentType = "application/octet-stream"; // 默认 MIME 类型
|
contentType = "application/octet-stream";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取文件内容
|
// 获取文件信息
|
||||||
var fileContents = await System.IO.File.ReadAllBytesAsync(filePath);
|
var fileInfo = new FileInfo(filePath);
|
||||||
|
|
||||||
// 返回文件内容
|
// 设置响应头
|
||||||
return File(fileContents, contentType, Path.GetFileName(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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(new CommonRsp() { Message = "task_id not exists", Retcode = -1 });
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,4 +183,16 @@ namespace iFileProxy.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Info { get; set; } = string.Empty;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,16 @@ namespace iFileProxy.Services
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) 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)
|
public DatabaseGateService(AppConfig appConfig)
|
||||||
{
|
{
|
||||||
_logger.Information("Initializing DatabaseGateService...");
|
_logger.Information("Initializing DatabaseGateService...");
|
||||||
|
@ -1065,5 +1075,32 @@ namespace iFileProxy.Services
|
||||||
Data = logs
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue