using iFileProxy.Config; using Serilog; using System.Data; using System.Text.Json; using MySql.Data.MySqlClient; using iFileProxy.Models; using Newtonsoft.Json; namespace iFileProxy.Helpers { public class DatabaseHelper { Database _db; AppConfig _appConfig; private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); Dictionary _dbDictionary = []; 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(); } /// /// 加载数据库描述字典 /// public void LoadDbDict() { foreach (DB item in _db.Databases) { _dbDictionary.Add(item.Description, item); _logger.Debug($"Db Config: {item.Description} <=> {item.DatabaseName} Loaded."); } } /// /// 获取一个指定数据库的连接 /// /// 数据库描述字段 对应AppConfig的description字段 /// /// 若某些不允许为空的字段出现空值 则抛出此异常 /// public MySqlConnection GetAndOpenDBConn(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; } public bool TestDbConfig() { foreach (var db in _dbDictionary) { _logger.Information($"[程序启动前配置验证] 正在测试数据库配置: {db.Key} ..."); MySqlConnection dbConn = new(); try { dbConn = GetAndOpenDBConn(db.Key); _logger.Information($"succ."); } catch (Exception) { _logger.Fatal($"=========== 数据库: {db.Key} 测试失败! ==========="); return false; } finally { dbConn.Close(); } } return true; } /// /// 获取一个json格式的数据表 /// /// /// /// public static string QueryTableData(MySqlCommand sqlCmd) { DataTable dataTable = new(); using (MySqlDataAdapter adapter = new (sqlCmd)) adapter.Fill(dataTable); return JsonConvert.SerializeObject(dataTable); } /// /// 获取一个json格式的数据表 /// /// /// /// 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); } /// /// 内部查询数据专用 当此方法暴露给C端可能造成sql注入等安全问题 /// /// SQL语句 /// 配置文件中的Description字段 /// 影响的行数 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"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new (sql,conn); sqlCmd.Parameters.AddWithValue("@ip_addr", ipAddr); return QueryTableData(sqlCmd); } catch (Exception e) { _logger.Error($"无法获取任务列表: {e.Message}"); throw; } finally { conn.Close(); } } public string GetTaskInfoByTid(string tid) { string sql = $"SELECT * FROM t_tasks_info WHERE `tid` =@tid"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new(sql, conn); sqlCmd.Parameters.AddWithValue("@tid", tid); return QueryTableData(sqlCmd); } catch (Exception e) { _logger.Error($"无法获取任务信息: {e.Message}"); throw; } 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? r = JsonConvert.DeserializeObject>(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`, `tag`) " + "VALUES (@tid, @file_name, @client_ip, @add_time, @update_time, @status, @url, @size, @hash, @tag)"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new(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.Parameters.AddWithValue("@tag", taskInfo.Tag); sqlCmd.ExecuteNonQuery(); } catch (Exception) { _logger.Fatal($"插入数据时出现问题"); throw; } finally { conn.Close(); } return true; } public bool UpdateFieldsData(string fieldsName, string key,string val) { string sql = $"UPDATE t_tasks_info set `{fieldsName}` = @Data WHERE `tid` = @tid"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new(sql, conn); sqlCmd.Parameters.AddWithValue("@Data",val); sqlCmd.Parameters.AddWithValue("@tid",key); if (sqlCmd.ExecuteNonQuery() == 1) { return true; } else return false; } catch (Exception) { _logger.Fatal($"Task Data update error."); throw; } finally { conn.Close(); } } public bool UpdateTaskStatus(TaskInfo taskInfo) { string sql = @"UPDATE t_tasks_info set `status` = @status , update_time = Now() WHERE `tid` = @tid"; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand sqlCmd = new (sql, conn); sqlCmd.Parameters.AddWithValue("@status", taskInfo.Status); sqlCmd.Parameters.AddWithValue("@tid", taskInfo.TaskId); if (sqlCmd.ExecuteNonQuery() >= 1) { _logger.Debug($"Task: {taskInfo.TaskId} Status Change to {taskInfo.Status}"); return true; } else _logger.Warning($"Task: {taskInfo.TaskId} Status Change Failed."); return false; } catch (Exception) { _logger.Fatal($"Task status update error."); throw; } finally { conn.Close (); } } public bool UpdateTaskHash(TaskInfo taskInfo) { return UpdateFieldsData("hash", taskInfo.TaskId, MasterHelper.GetFileHash(Path.Combine(_appConfig.DownloadOptions.SavePath, taskInfo.FileName), FileHashAlgorithm.MD5)); } public void TryInitialDB() { string sql = """ CREATE TABLE `t_tasks_info` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增键', `tid` varchar(48) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务id', `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `client_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户端IP', `add_time` datetime NOT NULL COMMENT '任务在何时被添加', `update_time` datetime NOT NULL COMMENT '任务状态更新时间', `status` int(11) NULL DEFAULT NULL COMMENT '任务状态', `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件url', `size` int(11) NULL DEFAULT NULL COMMENT '文件大小', `hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件hash', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; """; MySqlConnection conn = GetAndOpenDBConn("iFileProxy_Db"); try { using MySqlCommand cmd = new(sql, conn); cmd.ExecuteNonQuery(); } catch (Exception) { _logger.Error($"Db Init Fai.l"); throw; } finally { conn.Close(); } } } }