支持重复文件利用
This commit is contained in:
parent
d22404bdbb
commit
e530cb46fe
10 changed files with 193 additions and 22 deletions
|
@ -9,5 +9,5 @@
|
|||
- [x] 基于IP查询提交的任务状态
|
||||
- [x] 基于IP和路由的请求次数限制
|
||||
- [ ] 任务队列
|
||||
- [ ] 已经存在对应文件时候直接跳过代理下载 直接下载已经缓存的内容
|
||||
- [x] 已经存在对应文件时候直接跳过代理下载 直接下载已经缓存的内容
|
||||
- [ ] 捐赠
|
|
@ -110,7 +110,7 @@ namespace iFileProxy.Helpers
|
|||
/// <param name="sql"></param>
|
||||
/// <param name="conn"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetTableData(MySqlCommand sqlCmd)
|
||||
public static string QueryTableData(MySqlCommand sqlCmd)
|
||||
{
|
||||
DataTable dataTable = new();
|
||||
using (MySqlDataAdapter adapter = new (sqlCmd))
|
||||
|
@ -118,6 +118,34 @@ namespace iFileProxy.Helpers
|
|||
return JsonConvert.SerializeObject(dataTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个json格式的数据表
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
/// <param name="conn"></param>
|
||||
/// <returns></returns>
|
||||
public string QueryTableData(string sql,string dbConfName)
|
||||
{
|
||||
DataTable dataTable = new();
|
||||
using (MySqlDataAdapter adapter = new(new MySqlCommand(sql,GetAndOpenDBConn(dbConfName))))
|
||||
adapter.Fill(dataTable);
|
||||
return JsonConvert.SerializeObject(dataTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部查询数据专用 当此方法暴露给C端可能造成sql注入等安全问题
|
||||
/// </summary>
|
||||
/// <param name="sql">SQL语句</param>
|
||||
/// <param name="dbConfName">配置文件中的Description字段</param>
|
||||
/// <returns>影响的行数</returns>
|
||||
public int Query(string sql, string dbConfName)
|
||||
{
|
||||
using MySqlCommand sqlCmd = new (sql, GetAndOpenDBConn(dbConfName));
|
||||
int n = sqlCmd.ExecuteNonQuery();
|
||||
_logger.Debug($"查询完成, 受影响的行数: {n}");
|
||||
return n;
|
||||
}
|
||||
|
||||
public string GetTaskListByIP(string ipAddr)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE client_ip = @ip_addr";
|
||||
|
@ -126,7 +154,7 @@ namespace iFileProxy.Helpers
|
|||
{
|
||||
using MySqlCommand sqlCmd = new (sql,conn);
|
||||
sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr);
|
||||
return GetTableData(sqlCmd);
|
||||
return QueryTableData(sqlCmd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -143,7 +171,7 @@ namespace iFileProxy.Helpers
|
|||
{
|
||||
using MySqlCommand sqlCmd = new(sql, conn);
|
||||
sqlCmd.Parameters.AddWithValue("@tid", tid);
|
||||
return GetTableData(sqlCmd);
|
||||
return QueryTableData(sqlCmd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -153,13 +181,39 @@ namespace iFileProxy.Helpers
|
|||
finally { conn.Close(); }
|
||||
}
|
||||
|
||||
public TaskInfo? QueryTaskInfo(string fileName, string url, long size, TaskState status)
|
||||
{
|
||||
string sql = $"SELECT * FROM t_tasks_info WHERE url = @url AND size = @size AND `status` = @status AND file_name = @fileName";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
try {
|
||||
MySqlCommand sqlCmd = new MySqlCommand(sql, conn);
|
||||
sqlCmd.Parameters.AddWithValue("@url", url);
|
||||
sqlCmd.Parameters.AddWithValue("@size", size);
|
||||
sqlCmd.Parameters.AddWithValue("@status", status);
|
||||
sqlCmd.Parameters.AddWithValue("@fileName", fileName);
|
||||
string result = QueryTableData(sqlCmd);
|
||||
List<TaskInfo>? r = JsonConvert.DeserializeObject<List<TaskInfo>>(result);
|
||||
if (r != null)
|
||||
{
|
||||
return r[0];
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
catch (Exception e){
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
conn.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool InsertTaskData(TaskInfo taskInfo)
|
||||
{
|
||||
_logger.Debug(System.Text.Json.JsonSerializer.Serialize(taskInfo));
|
||||
string sql = "INSERT INTO `t_tasks_info` (`tid`, `file_name`, `client_ip`, `add_time`, `update_time`, `status`, `url`, `size`, `hash`) " +
|
||||
"VALUES (@tid, @file_name, @client_ip, @add_time, @update_time, @status, @url, @size, @hash)";
|
||||
string sql = "INSERT INTO `t_tasks_info` (`tid`, `file_name`, `client_ip`, `add_time`, `update_time`, `status`, `url`, `size`, `hash`, `tag`) " +
|
||||
"VALUES (@tid, @file_name, @client_ip, @add_time, @update_time, @status, @url, @size, @hash, @tag)";
|
||||
MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db");
|
||||
|
||||
try
|
||||
|
@ -174,6 +228,7 @@ namespace iFileProxy.Helpers
|
|||
sqlCmd.Parameters.AddWithValue("@url", taskInfo.Url);
|
||||
sqlCmd.Parameters.AddWithValue("@size", taskInfo.Size);
|
||||
sqlCmd.Parameters.AddWithValue("@hash", taskInfo.Hash);
|
||||
sqlCmd.Parameters.AddWithValue("@tag", taskInfo.Tag);
|
||||
|
||||
sqlCmd.ExecuteNonQuery();
|
||||
}
|
||||
|
@ -225,13 +280,13 @@ namespace iFileProxy.Helpers
|
|||
using MySqlCommand sqlCmd = new (sql, conn);
|
||||
sqlCmd.Parameters.AddWithValue("@status", taskInfo.Status);
|
||||
sqlCmd.Parameters.AddWithValue("@tid", taskInfo.TaskId);
|
||||
if (sqlCmd.ExecuteNonQuery() == 1)
|
||||
if (sqlCmd.ExecuteNonQuery() >= 1)
|
||||
{
|
||||
_logger.Debug($"Task: {taskInfo.TaskId} Task Status Change to {taskInfo.Status}");
|
||||
_logger.Debug($"Task: {taskInfo.TaskId} Status Change to {taskInfo.Status}");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
_logger.Warning($"Task: {taskInfo.TaskId} Task Status Change Failed.");
|
||||
_logger.Warning($"Task: {taskInfo.TaskId} Status Change Failed.");
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using iFileProxy.Models;
|
||||
using iFileProxy.Config;
|
||||
using iFileProxy.Models;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
@ -56,6 +57,13 @@ namespace iFileProxy.Helpers
|
|||
return clientIp;
|
||||
}
|
||||
|
||||
public static bool CheckDownloadFileExists(string fileName)
|
||||
{
|
||||
if (File.Exists(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath,fileName)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string GetFileHash(string fileName, FileHashAlgorithm algorithm)
|
||||
{
|
||||
byte[] hash = [];
|
||||
|
|
|
@ -1,37 +1,57 @@
|
|||
using System.Text.Json;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
namespace iFileProxy.Models
|
||||
{
|
||||
public class TaskInfo
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
[JsonPropertyName("id")]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[JsonProperty("tid")]
|
||||
[JsonPropertyName("tid")]
|
||||
public string TaskId { get; set; }
|
||||
|
||||
[JsonProperty("file_name")]
|
||||
[JsonPropertyName("file_name")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
[JsonProperty("client_ip")]
|
||||
[JsonPropertyName("client_ip")]
|
||||
public string? ClientIp { get; set; }
|
||||
|
||||
[JsonProperty("add_time")]
|
||||
[JsonPropertyName("add_time")]
|
||||
public DateTime AddTime { get; set; }
|
||||
|
||||
[JsonProperty("update_time")]
|
||||
[JsonPropertyName("update_time")]
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
[JsonProperty("status")]
|
||||
[JsonPropertyName("status")]
|
||||
public TaskState Status { get; set; }
|
||||
|
||||
[JsonProperty("url")]
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
[JsonProperty("size")]
|
||||
[JsonPropertyName("size")]
|
||||
public long Size { get; set; }
|
||||
|
||||
[JsonProperty("hash")]
|
||||
[JsonPropertyName("hash")]
|
||||
public string Hash { get; set; }
|
||||
|
||||
[JsonProperty("tag")]
|
||||
[JsonPropertyName("tag")]
|
||||
public string Tag { get; set; }
|
||||
}
|
||||
|
||||
public class DbConfigName {
|
||||
public static string iFileProxy = "iFileProxy_Db";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
Error = 2, // 任务执行时候发生错误 已经结束
|
||||
End = 3, // 任务正常结束
|
||||
Cached = 4, // 要下载的内容已经缓存
|
||||
Cleaned =5, // 内容过期已被清理
|
||||
}
|
||||
public enum TaskAddState {
|
||||
Success = 0,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
using iFileProxy.Config;
|
||||
using iFileProxy.Middleware;
|
||||
using iFileProxy.Services;
|
||||
using Serilog;
|
||||
|
||||
namespace iFileProxy
|
||||
|
@ -12,10 +13,13 @@ namespace iFileProxy
|
|||
SerilogConfig.CreateLogger();
|
||||
Serilog.ILogger logger = Log.Logger.ForContext<Program>();
|
||||
|
||||
Console.Write(" ");
|
||||
Console.Write(" "); // 强迫症,看着开始的那条日志不对齐不得劲
|
||||
|
||||
AppConfig.CheckAppConfig();
|
||||
|
||||
// 初始化缓存管理服务
|
||||
LocalCacheManager localCacheManager = new ();
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
|
|
@ -15,7 +15,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<ProjectGuid>e343bd8a-27ed-47e2-b50d-e3000730e65e</ProjectGuid>
|
||||
<SelfContained>false</SelfContained>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
|
|
|
@ -1,9 +1,74 @@
|
|||
namespace iFileProxy.Services
|
||||
using iFileProxy.Config;
|
||||
using iFileProxy.Helpers;
|
||||
using iFileProxy.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
namespace iFileProxy.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地缓存管理器
|
||||
/// </summary>
|
||||
public class LocalCacheManager
|
||||
{
|
||||
// 禁用空警告 因为初始化的时候就已经检查过相关的内容了
|
||||
#pragma warning disable CS8601
|
||||
private readonly AppConfig _appConfig = AppConfig.GetCurrConfig();
|
||||
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<LocalCacheManager>();
|
||||
|
||||
private readonly Timer _timer;
|
||||
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.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并且清理缓存数据
|
||||
/// </summary>
|
||||
public void CheckAndCleanCache(object state)
|
||||
{
|
||||
// 获取数据库中超出生命周期的缓存数据
|
||||
string result = _dbHelper.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy);
|
||||
List<TaskInfo>? taskInfos = JsonConvert.DeserializeObject<List<TaskInfo>>(result);
|
||||
if (taskInfos != null)
|
||||
{
|
||||
foreach (TaskInfo taskInfo in taskInfos)
|
||||
{
|
||||
string cacheFileName = Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName);
|
||||
if (File.Exists(cacheFileName))
|
||||
{
|
||||
_logger.Information($"正在清理缓存文件: {cacheFileName}");
|
||||
try
|
||||
{
|
||||
File.Delete(cacheFileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error("缓存文件删除失败: {e}", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
_dbHelper.Query($"UPDATE t_tasks_info SET `tag` = \"CLEANED\" WHERE `tid` = '{taskInfo.TaskId}'", DbConfigName.iFileProxy);
|
||||
taskInfo.Status = TaskState.Cleaned;
|
||||
_dbHelper.UpdateTaskStatus(taskInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止定时清理服务
|
||||
/// </summary>
|
||||
public void StopScheduledCleanupService()
|
||||
{
|
||||
_timer.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace iFileProxy.Services
|
|||
if (_appConfig.SecurityOptions.BlockedFileName.IndexOf(fileInfo.FileName) != -1)
|
||||
return TaskAddState.ErrFileNameForbidden;
|
||||
|
||||
TaskInfo taskInfo = new()
|
||||
TaskInfo taskInfo = new()
|
||||
{
|
||||
Url = t_url,
|
||||
TaskId = Guid.NewGuid().ToString(),
|
||||
|
@ -72,12 +72,28 @@ namespace iFileProxy.Services
|
|||
Status = TaskState.NoInit,
|
||||
UpdateTime = DateTime.Now
|
||||
};
|
||||
|
||||
|
||||
if (MasterHelper.CheckDownloadFileExists(taskInfo.FileName))
|
||||
{
|
||||
var r = _dbHelper.QueryTaskInfo(taskInfo.FileName, taskInfo.Url, taskInfo.Size, TaskState.End);
|
||||
if (r != null)
|
||||
{
|
||||
taskInfo.Status = TaskState.Cached;
|
||||
taskInfo.Hash = r.Hash;
|
||||
taskInfo.Size = r.Size;
|
||||
taskInfo.Tag = $"REDIRECT:{r.TaskId}";
|
||||
}
|
||||
}
|
||||
if (_dbHelper.InsertTaskData(taskInfo))
|
||||
{
|
||||
StartTask(taskInfo);
|
||||
taskInfo.Status = TaskState.Running;
|
||||
_dbHelper.UpdateTaskStatus(taskInfo);
|
||||
_logger.Debug("数据插入成功");
|
||||
if (taskInfo.Status != TaskState.Cached)
|
||||
{
|
||||
StartTask(taskInfo);
|
||||
taskInfo.Status = TaskState.Running;
|
||||
_dbHelper.UpdateTaskStatus(taskInfo);
|
||||
}
|
||||
_logger.Debug("任务添加成功.");
|
||||
return TaskAddState.Success;
|
||||
}
|
||||
else
|
||||
|
@ -160,7 +176,7 @@ namespace iFileProxy.Services
|
|||
public List<TaskInfo> GetTaskInfo(string taskId)
|
||||
{
|
||||
_logger.Debug(_dbHelper.GetTaskInfoByTid(taskId));
|
||||
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbHelper.GetTaskInfoByTid(taskId)) ?? [] ;
|
||||
return JsonSerializer.Deserialize<List<TaskInfo>>(_dbHelper.GetTaskInfoByTid(taskId)) ?? [];
|
||||
}
|
||||
|
||||
//public bool DeleteTask(HttpContext c)
|
||||
|
|
|
@ -122,7 +122,9 @@
|
|||
[0, "排队中"],
|
||||
[1, "进行中"],
|
||||
[2, "错误"],
|
||||
[3, "已完成"]
|
||||
[3, "已完成"],
|
||||
[4, "已缓存"],
|
||||
[5, "已被清理"]
|
||||
])
|
||||
data = [];
|
||||
$.ajax({
|
||||
|
@ -159,7 +161,7 @@
|
|||
data.forEach(item => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${item.status == 3 ? `<a href="/Download/${item.tid}">${item.file_name}</a>` : item.file_name}</td>
|
||||
<td>${item.status == 3 || item.status == 4 ? `<a href="/Download/${item.tid}">${item.file_name}</a>` : item.file_name}</td>
|
||||
<td class="hidden-on-small">${formatBytes(item.size)}</td>
|
||||
<td>${item.add_time}</td>
|
||||
<td>${statusStrDict.get(item.status)}</td>
|
||||
|
|
Loading…
Reference in a new issue