diff --git a/Class/AsyncHttpServer.cs b/Class/AsyncHttpServer.cs index c756313..af21fd1 100644 --- a/Class/AsyncHttpServer.cs +++ b/Class/AsyncHttpServer.cs @@ -79,12 +79,23 @@ namespace ForwardingServerUI.Class URL, deserializedPerson.Terminal, "", ""); }); //记录请求指令 - LogGing.LINKDATA(URL, "[COMMAND]" + deserializedPerson.User, Regex.Replace( + string AESDATA = Regex.Replace( AES.AesDecrypt(deserializedPerson.Terminal, deserializedPerson.Dat) , @"\\u[0-9A-Fa-f]{4}", match => { return Regex.Unescape(match.Value); - })); + }); + //记录 + Dictionary userlog = new Dictionary(); + userlog.Add("User", deserializedPerson.User); + userlog.Add("LastLoginIP", deserializedPerson.IP); + userlog.Add("IP", client.IP); + userlog.Add("LastLoginTerminal", deserializedPerson.Terminal); + userlog.Add("Note", AESDATA); + userlog.Add("Enterprise", URL); + userlog.Add("Time", DateTime.Now.ToString("yyyy-MM-dd dd:HH:mm:ss:fff")); + MainWindowViewModel.SQLiteHelpers.InsertData("ActionLog", userlog); + LogGing.LINKDATA(URL, "[COMMAND]" + deserializedPerson.User, AESDATA); // 创建一个 秒的延时任务 Task delayTask = Task.Delay(15000); diff --git a/Class/AsyncTcpServer.cs b/Class/AsyncTcpServer.cs index 457474c..5060a58 100644 --- a/Class/AsyncTcpServer.cs +++ b/Class/AsyncTcpServer.cs @@ -98,6 +98,15 @@ namespace ForwardingServerUI.Class return Regex.Unescape(match.Value); }); + Dictionary userlog = new Dictionary(); + userlog.Add("User", drEmployee["User"]); + userlog.Add("LastLoginIP", drEmployee["IP"]); + userlog.Add("LastLoginTerminal", drEmployee["Terminal"]); + userlog.Add("Note", decodedData); + userlog.Add("Enterprise", drEmployee["Enterprise"]); + userlog.Add("Time", DateTime.Now.ToString("yyyy-MM-dd dd:HH:mm:ss:fff")); + SQLiteHelpers.InsertData("ActionLog", userlog); + LogGing.LINKDATA(drEmployee["Enterprise"].ToString()!,"[REPLY]"+ drEmployee["User"].ToString()!, decodedData); } } diff --git a/Class/SqliteHelper.cs b/Class/SqliteHelper.cs new file mode 100644 index 0000000..4786b17 --- /dev/null +++ b/Class/SqliteHelper.cs @@ -0,0 +1,504 @@ +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace ForwardingServerUI.Class +{ + public class ClsLock : IDisposable + { + private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + + public IDisposable Read() + { + _lock.EnterReadLock(); + return new DisposableAction(() => _lock.ExitReadLock()); + } + + public void Dispose() => _lock?.Dispose(); + + private class DisposableAction : IDisposable + { + private readonly Action _action; + public DisposableAction(Action action) => _action = action; + public void Dispose() => _action?.Invoke(); + } + } + + public class SqliteHelper + { + #region 字段 + private SqliteTransaction? dbTrans = null!; + private static readonly Dictionary RWL = new Dictionary(); + private readonly string mDataFile; + private readonly string mPassWord = ""; + private readonly string lockName = ""; + private SqliteConnection mConn = null!; + #endregion + + #region 构造函数 + public SqliteHelper(string dataFile) + { + this.mDataFile = dataFile ?? throw new ArgumentNullException(nameof(dataFile)); + this.mDataFile = dataFile; // 注意:原代码有两次赋值,保留逻辑 + if (!RWL.ContainsKey(dataFile)) + { + lockName = dataFile; + RWL.Add(dataFile, new ClsLock()); + } + } + + public SqliteHelper(string dataFile, string PassWord) + { + this.mDataFile = dataFile ?? throw new ArgumentNullException(nameof(dataFile)); + this.mPassWord = PassWord ?? throw new ArgumentNullException(nameof(PassWord)); + this.mDataFile = dataFile; + if (!RWL.ContainsKey(dataFile)) + { + lockName = dataFile; + RWL.Add(dataFile, new ClsLock()); + } + } + #endregion + + #region 打开/关闭 数据库 + // 注意:Microsoft.Data.Sqlite.Core 不支持连接字符串构建器,需手动拼接 + // 加密支持通常需要 Microsoft.Data.Sqlite.Core + SQLitePCLRaw.bundle_green (且加密功能可能受限) + + public void Open() + { + // 构建连接字符串 + var connectionString = $"Data Source={mDataFile}"; + if (!string.IsNullOrWhiteSpace(mPassWord)) + { + connectionString += $";Password={mPassWord}"; // 注意:原生 Microsoft.Data.Sqlite 不支持加密 + // 如果需要加密,通常需要使用 SQLitePCLRaw 的特定提供程序或第三方库 + } + + mConn = new SqliteConnection(connectionString); + + // 如果文件不存在,Open() 会自动创建数据库文件 + // 但表结构需要你自己执行 CREATE TABLE + mConn.Open(); + + Console.WriteLine("The database was opened successfully"); + } + + public void Close() + { + if (this.mConn != null) + { + try + { + this.mConn.Close(); + // 注意:不要在这里移除 RWL,因为这是静态的,可能影响其他实例 + // if (RWL.ContainsKey(LockName)) { RWL.Remove(LockName); } + } + catch + { + Console.WriteLine("Shutdown failed"); + } + } + Console.WriteLine("The database was shut down successfully"); + } + #endregion + + #region 事务 + public void BeginTrain() + { + EnsureConnection(); + dbTrans = mConn.BeginTransaction(); + } + + public void DBCommit() + { + try + { + dbTrans?.Commit(); + dbTrans?.Dispose(); + dbTrans = null; // 提交后置空 + } + catch (Exception) + { + dbTrans?.Rollback(); + dbTrans?.Dispose(); + dbTrans = null; + } + } + #endregion + + #region 工具 + // OpenConnection 逻辑已合并到 Open() 方法中,因为 SqliteConnection 构造函数只接受字符串 + + public SqliteConnection Connection + { + get { return mConn; } + private set { mConn = value ?? throw new ArgumentNullException(); } + } + + protected void EnsureConnection() + { + if (this.mConn == null) + { + throw new Exception("SQLiteManager.Connection=null"); + } + if (mConn.State != ConnectionState.Open) + { + mConn.Open(); + } + } + + public string GetDataFile() => this.mDataFile; + + public bool TableExists(string table) + { + if (string.IsNullOrEmpty(table)) return false; + EnsureConnection(); + + // 注意:参数化查询在表名/列名上无效,这里使用字符串拼接(需确保table变量安全) + // 或者使用 PRAGMA table_info(table_name) + var sql = $"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='{table}'"; + + using (var cmd = new SqliteCommand(sql, Connection)) + { + var result = cmd.ExecuteScalar(); + return Convert.ToInt32(result) > 0; + } + } + + public bool Vacuum() + { + try + { + using (var Command = new SqliteCommand("VACUUM", Connection)) + { + Command.ExecuteNonQuery(); + } + return true; + } + catch (Exception) // SqliteException + { + return false; + } + } + + /// + /// 将 IDataReader 转换为 DataSet + /// + /// 已经执行了查询的 DataReader + /// 包含数据的 DataSet + public DataSet ReaderToDataSet(IDataReader reader) + { + DataSet ds = new DataSet(); + + do + { + DataTable schemaTable = reader.GetSchemaTable()!; + DataTable dataTable = new DataTable(); + + if (schemaTable != null) + { + // 创建列 + foreach (DataRow schemaRow in schemaTable.Rows) + { + string colName = schemaRow["ColumnName"].ToString()!; + Type dataType = (Type)schemaRow["DataType"]; + + // 防止列名重复 + string uniqueColName = colName; + int i = 1; + while (dataTable.Columns.Contains(uniqueColName)) + { + uniqueColName = colName + i++; + } + + DataColumn column = new DataColumn(uniqueColName, dataType); + dataTable.Columns.Add(column); + } + + // 读取行 + while (reader.Read()) + { + object[] values = new object[dataTable.Columns.Count]; + for (int i = 0; i < dataTable.Columns.Count; i++) + { + values[i] = reader.IsDBNull(i) ? DBNull.Value : reader.GetValue(i); + } + dataTable.Rows.Add(values); + } + } + else + { + // 如果没有 Schema (例如 "SELECT 1" 这种标量查询) + // 需要手动创建列 + for (int i = 0; i < reader.FieldCount; i++) + { + dataTable.Columns.Add("Column" + i); + } + while (reader.Read()) + { + object[] values = new object[reader.FieldCount]; + reader.GetValues(values); + dataTable.Rows.Add(values); + } + } + + ds.Tables.Add(dataTable); + } while (reader.NextResult()); // 处理多个结果集 + + return ds; + } + + #endregion + + + #region 执行SQL (Reader & Scalar) + + public SqliteDataReader? ExecuteReader(string sql, SqliteParameter[]? paramArr) + { + if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql)); + EnsureConnection(); + + // 注意:using 语句会立即释放 Reader,导致无法读取 + // 这里的 RWL 锁在 using 外部处理,或者调用方自己处理锁 + // 这里简化逻辑,直接返回 Reader,调用方需自行管理连接状态 + var cmd = new SqliteCommand(sql, Connection); + + if (paramArr != null) + { + cmd.Parameters.AddRange(paramArr); + } + + // CommandBehavior.CloseConnection 确保 Reader 关闭时连接也关闭 + // 但这里我们管理连接,所以不加 + try + { + // 注意:不要在这里 Dispose Command,否则 Reader 会失效 + // 返回 Reader,由调用方在读取完毕后关闭 + return cmd.ExecuteReader(); + } + catch(Exception ex) + { + Console.WriteLine("[SQLITE_ExecuteReader:err]" + ex.ToString()); + cmd?.Dispose(); + return null; + } + } + + public DataSet? ExecuteDataSet(string sql, SqliteParameter[]? paramArr) + { + var dat = ExecuteReader(sql, paramArr); + if (dat == null) + { + return null; + } + return ReaderToDataSet(dat); + } + + // ExecuteScalar + public object? ExecuteScalar(string sql, SqliteParameter[]? paramArr) + { + if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql)); + EnsureConnection(); + + using (RWL[lockName].Read()) + { + using (var cmd = new SqliteCommand(sql, Connection)) + { + if (paramArr != null) + { + cmd.Parameters.AddRange(paramArr); + } + try + { + return cmd.ExecuteScalar(); + } + catch (Exception ex) + { + Console.WriteLine("[SQLITE_ExecuteScalar:err]" + ex.ToString()); + return null; + } + } + } + } + + // QueryOne (返回字典或对象) + public Dictionary? QueryOne(string table, string conditionCol, object conditionVal) + { + if (string.IsNullOrEmpty(table)) return null; + EnsureConnection(); + + string sql = $"SELECT * FROM [{table}]"; // 使用 [] 防止关键字冲突 + var parameters = new List(); + + if (!string.IsNullOrEmpty(conditionCol)) + { + sql += $" WHERE [{conditionCol}] = @{conditionCol}"; + parameters.Add(new SqliteParameter($"@{conditionCol}", conditionVal)); + } + + using (var cmd = new SqliteCommand(sql, Connection)) + { + cmd.Parameters.AddRange(parameters.ToArray()); + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + var dict = new Dictionary(); + for (int i = 0; i < reader.FieldCount; i++) + { + var value = reader.GetValue(i); + if (value == DBNull.Value) value = null; + dict[reader.GetName(i)] = value; + } + return dict; + } + } + } + return null; + } + #endregion + + #region 增 删 改 + // 注意:参数前缀统一为 @ + + public int InsertData(string table, Dictionary entity) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException(nameof(table)); + EnsureConnection(); + + string sql = BuildInsert(table, entity); + var parameters = BuildParamArray(entity); + return ExecuteNonQuery(sql, parameters); + } + + public int Update(string table, Dictionary entity, string where, SqliteParameter[]? whereParams) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException(nameof(table)); + EnsureConnection(); + + string sql = BuildUpdate(table, entity); + var parameters = BuildParamArray(entity); + + if (!string.IsNullOrEmpty(where)) + { + sql += " WHERE " + where; + if (whereParams != null) + { + var combined = new SqliteParameter[parameters.Length + whereParams.Length]; + parameters.CopyTo(combined, 0); + whereParams.CopyTo(combined, parameters.Length); + parameters = combined; + } + } + + return ExecuteNonQuery(sql, parameters); + } + + public int Delete(string table, string where, SqliteParameter[]? whereParams) + { + if (string.IsNullOrEmpty(table)) return 0; + EnsureConnection(); + + string sql = $"DELETE FROM [{table}]"; + if (!string.IsNullOrEmpty(where)) + { + sql += " WHERE " + where; + } + + return ExecuteNonQuery(sql, whereParams); + } + + public int ExecuteNonQuery(string sql, SqliteParameter[]? paramArr) + { + if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql)); + EnsureConnection(); + + using (RWL[lockName].Read()) // 注意:写操作通常建议用 Write 锁 + { + using (var cmd = new SqliteCommand(sql, Connection)) + { + if (paramArr != null) + { + cmd.Parameters.AddRange(paramArr); + } + try + { + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Console.WriteLine("[SQLITE_ExecuteScalar:err]" + ex.ToString()); + return 0; + } + } + } + } + + // 构建 SQL 和 参数的方法保持不变,仅泛型类型变更 + private SqliteParameter[] BuildParamArray(Dictionary entity) + { + var list = new List(); + foreach (string key in entity.Keys) + { + // 注意:参数名必须包含 @ 前缀 + list.Add(new SqliteParameter($"@{key}", entity[key])); + } + return list.ToArray(); + } + + private string BuildInsert(string table, Dictionary entity) + { + var buf = new StringBuilder(); + buf.Append("INSERT INTO ").Append(table).Append(" ("); + var cols = new List(); + var vals = new List(); + foreach (string key in entity.Keys) + { + cols.Add(key); + vals.Add($"@{key}"); + } + buf.Append(string.Join(",", cols)).Append(") VALUES ("); + buf.Append(string.Join(",", vals)).Append(")"); + return buf.ToString(); + } + + private string BuildUpdate(string table, Dictionary entity) + { + var buf = new StringBuilder(); + buf.Append("UPDATE ").Append(table).Append(" SET "); + var sets = new List(); + foreach (string key in entity.Keys) + { + sets.Add($"{key} = @{key}"); + } + buf.Append(string.Join(",", sets)); + return buf.ToString(); + } + + // 辅助方法:DataRow 转 Dictionary (由于没有 DataTable,通常直接从 Reader 转) + // 这里保留原方法签名,但实际使用中可能需要调整 + public Dictionary DataTableToDictionary(DataTable dataTable) + { + var result = new Dictionary(); + if (dataTable.Rows.Count > 0) + { + var row = dataTable.Rows[0]; + foreach (DataColumn column in dataTable.Columns) + { + var value = row[column]; + if (value == DBNull.Value) value = null; + result[column.ColumnName] = value; + } + } + return result; + } + #endregion + } +} diff --git a/ForwardingServerUI.csproj b/ForwardingServerUI.csproj index 47b632e..569b4e1 100644 --- a/ForwardingServerUI.csproj +++ b/ForwardingServerUI.csproj @@ -10,6 +10,8 @@ + + diff --git a/MainWindowViewModel.cs b/MainWindowViewModel.cs index 7a8f645..581b100 100644 --- a/MainWindowViewModel.cs +++ b/MainWindowViewModel.cs @@ -5,6 +5,7 @@ using ForwardingServerUI.Class; using System; using System.Collections.Generic; using System.Data; +using System.Reflection.PortableExecutable; using System.Text; using TouchSocket.Sockets; @@ -26,10 +27,16 @@ namespace ForwardingServerUI [ObservableProperty] public static DataTable _userTable = new(); + public static SqliteHelper SQLiteHelpers = null!; //定义数据库 + private readonly string DBAddress = Environment.CurrentDirectory + "\\DB\\DB.db"; //数据库路径 + public static DataTable ActionLog = new DataTable(); public static readonly object TableLock = new object(); public async void Data() { + SQLiteHelpers = new SqliteHelper(DBAddress); //数据库连接路径 + SQLiteHelpers.Open(); //打开数据库 + _machineTable.Columns.Add("ID", typeof(string)); _machineTable.Columns.Add("IP", typeof(string)); _machineTable.Columns.Add("Start", typeof(int)); @@ -38,7 +45,6 @@ namespace ForwardingServerUI _machineTable.Columns.Add("HeartbeatTime", typeof(string)); _machineTable.Columns.Add("MachineVer", typeof(string)); - _userTable.Columns.Add("ID", typeof(string)); _userTable.Columns.Add("IP", typeof(string)); _userTable.Columns.Add("User", typeof(string));