初次提交

This commit is contained in:
root 2024-11-19 22:51:07 +08:00
commit 5fd60ad9f3
22 changed files with 956 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
src/bin
src/.vs
src/obj
src/.config
*.user

1
README.md Normal file
View file

@ -0,0 +1 @@
### 文件代理下载工具

108
src/Config/AppConfig.cs Normal file
View file

@ -0,0 +1,108 @@
using Serilog;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace iFileProxy.Config
{
public class AppConfig
{
static readonly Serilog.ILogger _logger = Log.Logger.ForContext<AppConfig>();
readonly static JsonSerializerOptions options = new()
{
ReadCommentHandling = JsonCommentHandling.Skip, // 允许注释
AllowTrailingCommas = true // 允许尾随逗号
};
[JsonPropertyName("Download")]
public DownloadOptions DownloadOptions { get; set; } = new();
[JsonPropertyName("Security")]
public SecurityOptions SecurityOptions { get; set; } = new();
[JsonPropertyName("Database")]
public Database Database { get; set; }
public static AppConfig? GetCurrConfig(string configPath)
{
if (File.Exists(configPath))
{
try
{
return JsonSerializer.Deserialize<AppConfig>(File.ReadAllText(configPath),options);
}
catch (Exception)
{
_logger.Error("Config Parse Error!");
throw;
}
}
else
_logger.Fatal($"Config File: {configPath} not exists!");
return null;
}
}
public class DownloadOptions
{
public string SavePath { get; set; } = "./proxy_tmp/";
public uint ThreadNum { get; set; } = 1;
public uint MaxAllowedFileSize { get; set; }
public uint MaxParallelTasks { get; set; } = 4;
public string Aria2cPath { get; set; } = "./bin/aria2c";
}
public class SecurityOptions
{
public List<string> BlockedHost { get; set; } = [];
public List<string> BlockedFileName { get; set; } = [];
public List<string> BlockedClientIP { get; set; } = [];
public int DailyRequestLimitPerIP { get; set; } = -1;
}
public partial class Database
{
[JsonPropertyName("Common")]
public Common Common { get; set; }
[JsonPropertyName("Databases")]
public DB[] Databases { get; set; }
}
public partial class Common
{
[JsonPropertyName("Host")]
public string Host { get; set; }
[JsonPropertyName("Port")]
public int Port { get; set; } = 3306;
[JsonPropertyName("User")]
public string User { get; set; }
[JsonPropertyName("Password")]
public string Password { get; set; }
}
public partial class DB
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("Host")]
public string Host { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("Port")]
public long? Port { get; set; } = 3306;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("User")]
public string User { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("Password")]
public string Password { get; set; }
[JsonPropertyName("DatabaseName")]
public string DatabaseName { get; set; }
[JsonPropertyName("Description")]
public string Description { get; set; }
}
}

View file

@ -0,0 +1,36 @@
using iFileProxy.Models;
using iFileProxy.Services;
using Microsoft.AspNetCore.Mvc;
namespace iFileProxy.Controllers
{
public class iProxyController : ControllerBase
{
static readonly TaskManager taskManager = new ();
[HttpPost]
[Route("/AddOfflineTask")]
public ActionResult<CommonRsp> AddOfflineTask()
{
return taskManager.AddTask(HttpContext) switch
{
TaskAddState.Success => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.Success, message = "succ" }),
TaskAddState.Fail => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.Fail, message = "unkown error!" }),
TaskAddState.ErrUrlRepeat => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrUrlRepeat, message = "此url已经在任务队列中,请勿重复提交" }),
TaskAddState.ErrTaskIdRepeat => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrTaskIdRepeat, message = "TaskIdRepeat!!!" }),
TaskAddState.ErrUrlInvalid => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrUrlInvalid, message = "非法Url" }),
TaskAddState.ErrDbFail => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.ErrDbFail, message = "数据库数据提交失败!" }),
_ => (ActionResult<CommonRsp>)Ok(new CommonRsp() { retcode = (int)TaskAddState.Success, message = "succ default" }),
};
}
[HttpPost]
[HttpGet]
[Route("/GetMyTasks")]
public ActionResult<CommonRsp> GetMyTasks()
{
return Ok(new CommonRsp() { retcode = 0, message = "succ" });
}
}
}

63
src/ErrorHandler.cs Normal file
View file

@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Components;
namespace iFileProxy
{
using iFileProxy.Models;
using Microsoft.AspNetCore.Http;
using System;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
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." }));
}
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = HttpStatusCode.InternalServerError; // 500 if unexpected
switch (exception)
{
case NotImplementedException:
code = HttpStatusCode.NotImplemented; // 501
break;
case UnauthorizedAccessException:
code = HttpStatusCode.Unauthorized; // 401
break;
case ArgumentException:
code = HttpStatusCode.BadRequest; // 400
break;
// Add more cases for different types of exceptions
}
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(JsonSerializer.Serialize(new CommonRsp { retcode = 1, message = "server internal error" }));
}
}
}

View file

@ -0,0 +1,153 @@
using iFileProxy.Config;
using Serilog;
using System.Data;
using System.Text.Json;
using MySql.Data.MySqlClient;
using iFileProxy.Models;
namespace iFileProxy.Helpers
{
public class DatabaseHelper
{
Database _db;
AppConfig _appConfig;
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<DatabaseHelper>();
Dictionary<string, DB> _dbDictionary = new Dictionary<string, DB>();
public DatabaseHelper(AppConfig appConfig)
{
_logger.Information("Initializing DatabaseHelper...");
_db = appConfig.Database;
_appConfig = appConfig;
try
{
_logger.Information("Done.");
}
catch (Exception e)
{
_logger.Fatal($"程序异常: {e.Message}");
}
LoadDbDict();
}
/// <summary>
/// 加载数据库描述字典
/// </summary>
public void LoadDbDict()
{
foreach (DB item in _db.Databases)
{
_dbDictionary.Add(item.Description, item);
_logger.Debug($"Db Config: {item.Description} <=> {item.DatabaseName} Loaded.");
}
}
/// <summary>
/// 获取一个指定数据库的连接
/// </summary>
/// <param name="db_desc">数据库描述字段 对应AppConfig的description字段</param>
/// <returns></returns>
/// <exception cref="Exception">若某些不允许为空的字段出现空值 则抛出此异常</exception>
///
public MySqlConnection GetDBConn(string db_desc)
{
if (!_dbDictionary.TryGetValue(db_desc, out DB Db))
{
throw new Exception($"未找到与 {db_desc} 相匹配的数据库配置");
}
var db_user = Db.User ?? _db.Common.User;
var db_password = Db.Password ?? _db.Common.Password;
var db_host = Db.Host ?? _db.Common.Host;
var db_port = Db.Port ?? _db.Common.Port;
if (db_user == null || db_password == null || db_host == null || db_port == null)
throw new NoNullAllowedException("数据库配置获取失败,不允许为空的字段出现空值");
string db_connstr = $"server={db_host};user={db_user};database={Db.DatabaseName};port={db_port};password={db_password};Pooling=true;MaximumPoolSize=500;";
MySqlConnection conn;
try
{
conn = new MySqlConnection(db_connstr);
conn.Open();
}
catch (Exception ex)
{
_logger.Fatal($"获取Mysql连接时出现异常:{ex.Message}");
throw;
}
return conn;
}
/// <summary>
/// 获取一个json格式的数据表
/// </summary>
/// <param name="sql"></param>
/// <param name="conn"></param>
/// <returns></returns>
public static string GetTableData(string sql, MySqlConnection conn)
{
DataTable dataTable = new DataTable();
using (MySqlCommand queryAllUser = new MySqlCommand(sql, conn))
{
using (MySqlDataAdapter adapter = new MySqlDataAdapter(queryAllUser))
adapter.Fill(dataTable);
}
return JsonSerializer.Serialize(dataTable);
}
public bool InsertTaskData(TaskInfo taskInfo)
{
_logger.Debug(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)";
MySqlConnection conn = GetDBConn("iFileProxy_Db");
try
{
using MySqlCommand sqlCmd = new MySqlCommand(sql, conn);
sqlCmd.Parameters.AddWithValue("@tid", taskInfo.TaskId);
sqlCmd.Parameters.AddWithValue("@file_name", taskInfo.FileName);
sqlCmd.Parameters.AddWithValue("@client_ip", taskInfo.ClientIp);
sqlCmd.Parameters.AddWithValue("@add_time", taskInfo.AddTime.ToString("yyyy-MM-dd HH:mm:ss"));
sqlCmd.Parameters.AddWithValue("@update_time", taskInfo.UpdateTime.ToString("yyyy-MM-dd HH:mm:ss"));
sqlCmd.Parameters.AddWithValue("@status", taskInfo.Status);
sqlCmd.Parameters.AddWithValue("@url", taskInfo.Url);
sqlCmd.Parameters.AddWithValue("@size", taskInfo.Size);
sqlCmd.Parameters.AddWithValue("@hash", taskInfo.Hash);
sqlCmd.ExecuteNonQuery();
}
catch (Exception)
{
_logger.Fatal($"插入数据时出现问题");
throw;
}
finally
{
conn.Close();
}
return true;
}
public void TryInitialDB()
{
string sql = "ALTER TABLE `t_region_config` ADD COLUMN `stop_server_info_str` varchar(255) CHARACTER SET utf8mb4 NOT NULL AFTER `stop_server_config_str`";
MySqlConnection conn = GetDBConn("deploy_config");
try
{
using MySqlCommand cmd = new(sql, conn);
cmd.ExecuteNonQuery();
}
catch { }
finally
{
conn.Close();
}
}
}
}

View file

@ -0,0 +1,62 @@
using iFileProxy.Models;
using System.Net.Http.Headers;
using System.Text.Json;
namespace iFileProxy.Helpers
{
public class FileDownloadHelper
{
public static DownloadFileInfo GetDownloadFileInfo(string url)
{
var fileInfo = new DownloadFileInfo();
var _httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Head, url))
{
using (var response = _httpClient.Send(request))
{
response.EnsureSuccessStatusCode();
// 获取文件大小
if (response.Content.Headers.TryGetValues("Content-Length", out var values))
{
if (long.TryParse(values.First(), out long fileSize))
{
fileInfo.Size = fileSize;
}
else
fileInfo.Size = -1;
}
else
fileInfo.Size = -1;
// 获取文件名,优先从 Content-Disposition 中提取,如果没有再从 URL 提取
fileInfo.FileName = ExtractFileNameFromContentDisposition(response.Content.Headers.ContentDisposition)
?? ExtractFileNameFromUrl(url);
}
}
return fileInfo;
}
private static string ExtractFileNameFromContentDisposition(ContentDispositionHeaderValue contentDisposition)
{
if (contentDisposition != null)
{
// 检查是否有文件名
var fileName = contentDisposition.FileName ?? contentDisposition.FileNameStar;
return fileName;
}
return null;
}
private static string ExtractFileNameFromUrl(string url)
{
// 从 URL 中提取文件名,通常是 URL 路径的最后一部分
Uri uri = new Uri(url);
string fileName = Path.GetFileName(uri.LocalPath);
return fileName;
}
}
}

View file

@ -0,0 +1,34 @@
using System.Net.Http;
using System.Text.RegularExpressions;
namespace iFileProxy.Helpers
{
public class MasterHelper
{
/// <summary>
/// 检测链接是否为合法的网址格式
/// </summary>
/// <param name="uri">待检测的链接</param>
/// <returns></returns>
public static bool CheckUrlIsValid(string? uri)
{
try
{
if (string.IsNullOrWhiteSpace(uri))
return false;
var regex = @"(http://)?([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
Regex re = new Regex(regex);
return re.IsMatch(uri);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return false;
}
}
}

9
src/Models/CommonRsp.cs Normal file
View file

@ -0,0 +1,9 @@
namespace iFileProxy.Models
{
public class CommonRsp
{
public string message { get; set; }
public object data { get; set; }
public int retcode { get; set; }
}
}

37
src/Models/Db.cs Normal file
View file

@ -0,0 +1,37 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace iFileProxy.Models
{
public class TaskInfo
{
[JsonPropertyName("id")]
public uint Id { get; set; }
[JsonPropertyName("tid")]
public string TaskId { get; set; }
[JsonPropertyName("file_name")]
public string FileName { get; set; }
[JsonPropertyName("client_ip")]
public string? ClientIp { get; set; }
[JsonPropertyName("add_time")]
public DateTime AddTime { get; set; }
[JsonPropertyName("update_time")]
public DateTime UpdateTime { get; set; }
[JsonPropertyName("status")]
public TaskState Status { get; set; }
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("size")]
public long Size { get; set; }
[JsonPropertyName("hash")]
public string Hash { get; set; }
}
}

21
src/Models/Task.cs Normal file
View file

@ -0,0 +1,21 @@
namespace iFileProxy.Models
{
public enum TaskState {
NoInit = 0, // 还未初始化
Running = 1, // 正在进行
Error = 2, // 任务执行时候发生错误 已经结束
End = 3, // 任务正常结束
}
public enum TaskAddState {
Success = 0,
Fail = 1,
ErrUrlRepeat = 2,
ErrTaskIdRepeat = 3,
ErrUrlInvalid = 4,
ErrDbFail = 5
}
public class DownloadFileInfo {
public string FileName { get; set; }
public long Size { get; set; }
}
}

54
src/Program.cs Normal file
View file

@ -0,0 +1,54 @@
using Serilog;
namespace iFileProxy
{
public class Program
{
public static void Main(string[] args)
{
SerilogConfig.CreateLogger();
Serilog.ILogger logger = Log.Logger.ForContext<Program>();
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Host.UseSerilog(logger: Log.Logger);
var app = builder.Build();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagCtx, httpCtx) =>
{
diagCtx.Set("ClientIp", httpCtx.Connection.RemoteIpAddress?.ToString());
diagCtx.Set("contentType", httpCtx.Request.ContentType);
diagCtx.Set("queryString", httpCtx.Request.QueryString);
};
});
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseMiddleware<ErrorHandlerMiddleware>(); // ´íÎó´¦ÀíÖмä¼þ
app.MapControllers();
app.Run();
}
}
}

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>false</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>e343bd8a-27ed-47e2-b50d-e3000730e65e</ProjectGuid>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:9876",
"sslPort": 44309
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5098",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7272;http://localhost:5098",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

54
src/SerilogConfig.cs Normal file
View file

@ -0,0 +1,54 @@
namespace iFileProxy
{
using Serilog;
using Serilog.Events;
using Serilog.Filters;
using System.Net;
public static class SerilogConfig
{
public static void CreateLogger()
{
var filePath = Path.Combine(AppContext.BaseDirectory, $"logs/dispatch.api.log");
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console(
outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType}{NewLine} {Exception}")
.WriteTo.File(filePath,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{SourceContext}] {ClientIp} {Message:lj} {contentType} {queryString}{NewLine}{Exception}",
rollingInterval: RollingInterval.Day,
fileSizeLimitBytes: 1073741824) //1GB
.Enrich.WithProperty("node_ip", GetIpAddress())
.CreateLogger();
}
public static void RefreshLogger()
{
if (Log.Logger != null)
{
Log.CloseAndFlush();
}
CreateLogger();
}
private static string GetIpAddress()
{
string ipAddress = "127.0.0.1";
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ip in ips)
{
if (ip.AddressFamily.ToString().ToLower().Equals("internetwork"))
{
ipAddress = ip.ToString();
return ipAddress;
}
}
return ipAddress;
}
}
}

154
src/Services/TaskManager.cs Normal file
View file

@ -0,0 +1,154 @@
using iFileProxy.Config;
using iFileProxy.Helpers;
using iFileProxy.Models;
using Serilog;
using System.Diagnostics;
using System.Security.Policy;
namespace iFileProxy.Services
{
/// <summary>
/// 下载任务管理器
/// </summary>
public class TaskManager
{
private readonly static Serilog.ILogger _logger = Log.Logger.ForContext<TaskManager>();
private readonly AppConfig? _appConfig = AppConfig.GetCurrConfig("iFileProxy.json");
private readonly DatabaseHelper _dbHelper;
private Dictionary<string, TaskInfo> runningTasks = [];
public TaskManager()
{
_logger.Information("Initializing TaskManager...");
if (_appConfig != null)
_dbHelper = new DatabaseHelper(_appConfig);
else
{
_logger.Fatal($"Failed to load application configuration");
Environment.Exit(1);
}
_logger.Information("TaskManager init succ.");
}
/// <summary>
/// 添加一个新的下载任务
/// </summary>
/// <param name="c">HttpContext</param>
/// <returns></returns>
public TaskAddState AddTask(HttpContext c)
{
// 尝试从 X-Forwarded-For 请求头获取客户端IP地址
string? clientIp = c.Request.Headers["X-Forwarded-For"].FirstOrDefault();
// 如果 X-Forwarded-For 头不存在,回退到 RemoteIpAddress
if (string.IsNullOrEmpty(clientIp))
{
clientIp = c.Connection.RemoteIpAddress?.ToString();
}
string? t_url = c.Request.Query["url"].FirstOrDefault();
foreach (var t in runningTasks)
{
if (t.Value.Url == t_url)
{
return TaskAddState.ErrUrlRepeat;
}
}
if (!MasterHelper.CheckUrlIsValid(t_url))
return TaskAddState.ErrUrlInvalid;
DownloadFileInfo fileInfo = FileDownloadHelper.GetDownloadFileInfo(t_url);
TaskInfo taskInfo = new()
{
Url = t_url,
TaskId = Guid.NewGuid().ToString(),
AddTime = DateTime.Now,
FileName = fileInfo.FileName,
ClientIp = clientIp,
Size = fileInfo.Size,
Status = TaskState.Running,
UpdateTime = DateTime.Now
} ;
if (_dbHelper.InsertTaskData(taskInfo))
{
StartTask(taskInfo);
_logger.Debug("数据插入成功");
return TaskAddState.Success;
}
else
return TaskAddState.ErrDbFail;
}
public async void StartTask(TaskInfo task_info)
{
if (runningTasks.ContainsKey(task_info.TaskId))
{
_logger.Error($"指定的task已经存在!!!");
return;
}
Process aria2c = new();
aria2c.StartInfo = new ProcessStartInfo
{
FileName = _appConfig.DownloadOptions.Aria2cPath,
WorkingDirectory = _appConfig.DownloadOptions.SavePath,
Arguments = $"-x {_appConfig.DownloadOptions.ThreadNum} -s {_appConfig.DownloadOptions.ThreadNum} {task_info.Url}",
RedirectStandardOutput = true ,
RedirectStandardError = true ,
RedirectStandardInput = true ,
UseShellExecute = false,
Environment = { { "TaskId", task_info.TaskId } }
};
try
{
aria2c.Start();
aria2c.BeginOutputReadLine();
aria2c.BeginErrorReadLine();
aria2c.OutputDataReceived += Aria2c_OutputDataReceived;
aria2c.ErrorDataReceived += Aria2c_ErrorDataReceived;
runningTasks.Add(task_info.TaskId, task_info);
await aria2c.WaitForExitAsync();
if (aria2c.ExitCode != 0)
_logger.Error($"task: {task_info.TaskId} 进程退出状态异常 ExitCode: {aria2c.ExitCode}");
else
runningTasks.Remove(task_info.TaskId);
}
catch (Exception)
{
_logger.Fatal("执行下载任务时候出现致命问题");
throw;
}
}
private void Aria2c_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null || e.Data.Trim() == "")
return;
Process c = (Process)sender;
_logger.Error($"[TaskId: {c.StartInfo.Environment["TaskId"]}] {e.Data}");
}
private void Aria2c_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null || e.Data.Trim() == "")
return;
Process c = (Process)sender;
_logger.Debug($"[TaskId: {c.StartInfo.Environment["TaskId"]}] {e.Data}");
}
//public bool DeleteTask(HttpContext c)
//{
//}
//public bool UpdateTaskStatus(HttpContext c)
//{
//}
//public List<TaskInfo> GetAllTaskInfo(HttpContext c)
//{
//}
//public TaskInfo GetTaskInfo(HttpContext c)
//{
//}
}
}

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
src/appsettings.json Normal file
View file

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

18
src/iFileProxy.csproj Normal file
View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="9.1.0" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
</Project>

6
src/iFileProxy.http Normal file
View file

@ -0,0 +1,6 @@
@iFileProxy_HostAddress = http://localhost:5098
GET {{iFileProxy_HostAddress}}/weatherforecast/
Accept: application/json
###

35
src/iFileProxy.json Normal file
View file

@ -0,0 +1,35 @@
{
"Database": {
"Common": {
"Host": "47.243.56.137",
"Port": 3306,
"User": "iFileProxy",
"Password": "i4TwYJeEt5pRfJze"
},
"Databases": [
{
"DatabaseName": "iFileProxy",
"Description": "iFileProxy_Db"
}
]
},
"Download": {
"SavePath": "./download/", //
"ThreadNum": 4, // 线
"MaxAllowedFileSize": 65536, //
"MaxParallelTasks": 4, //
"Aria2cPath": "./lib/aria2c"
},
"Security": {
"BlockedHost": [ //
"github.com"
],
"BlockedFileName": [ //
"a.txt"
],
"BlockedClientIP": [ // 使IP
"127.0.0.1"
],
"DailyRequestLimitPerIP": 200 // IP
}
}

25
src/iFileProxy.sln Normal file
View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iFileProxy", "iFileProxy.csproj", "{E343BD8A-27ED-47E2-B50D-E3000730E65E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E343BD8A-27ED-47E2-B50D-E3000730E65E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E343BD8A-27ED-47E2-B50D-E3000730E65E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E343BD8A-27ED-47E2-B50D-E3000730E65E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E343BD8A-27ED-47E2-B50D-E3000730E65E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B34F63CF-43DA-4E66-885E-5B935910E00E}
EndGlobalSection
EndGlobal