优化下载内存占用 添加下载者统计
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.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 });
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue