using System;
|
using System.Collections.Generic;
|
using System.Data.SQLite;
|
using System.IO;
|
|
namespace DeviceService.Driver
|
{
|
/// <summary>
|
/// 驱动信息 SQLite 持久化:数据库文件位于 应用根目录\Config\Drivers.db。
|
///
|
/// 表结构:
|
/// - DriverPackage:已加载的驱动包(Driver 根目录下的一个子文件夹)
|
/// - DriverType:驱动包内带 [DriverDesc] 注解的驱动类型((类型, 品牌) 定位)
|
///
|
/// 所有操作失败仅通过 log 上报,不会中断驱动加载流程。
|
/// </summary>
|
public sealed class DriverDatabase
|
{
|
private static readonly object _staticSync = new object();
|
private static DriverDatabase _instance;
|
|
public static DriverDatabase Instance
|
{
|
get
|
{
|
lock (_staticSync)
|
{
|
return _instance ??= new DriverDatabase();
|
}
|
}
|
}
|
|
/// <summary>配置目录:应用根目录\Config。</summary>
|
public static string ConfigDirectory =>
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config");
|
|
/// <summary>数据库文件路径。</summary>
|
public static string DatabasePath =>
|
Path.Combine(ConfigDirectory, "Drivers.db");
|
|
private readonly object _sync = new object();
|
private bool _initialized;
|
|
private DriverDatabase()
|
{
|
}
|
|
/// <summary>确保 Config 目录与库表结构存在。失败返回 false 并通过 log 上报。</summary>
|
private bool EnsureReady(Action<string> log)
|
{
|
if (_initialized)
|
{
|
return true;
|
}
|
|
try
|
{
|
if (!Directory.Exists(ConfigDirectory))
|
{
|
Directory.CreateDirectory(ConfigDirectory);
|
}
|
|
using (var conn = Open())
|
using (var cmd = conn.CreateCommand())
|
{
|
cmd.CommandText = @"
|
CREATE TABLE IF NOT EXISTS DriverPackage (
|
Folder TEXT PRIMARY KEY,
|
Directory TEXT NOT NULL,
|
AssemblyCount INTEGER NOT NULL DEFAULT 0,
|
ScanTime TEXT NOT NULL
|
);
|
CREATE TABLE IF NOT EXISTS DriverType (
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
PackageFolder TEXT NOT NULL,
|
AssemblyFile TEXT NOT NULL,
|
FullName TEXT NOT NULL,
|
DriverType TEXT,
|
Brand TEXT,
|
UNIQUE(PackageFolder, FullName)
|
);
|
CREATE INDEX IF NOT EXISTS IX_DriverType_Type_Brand ON DriverType(DriverType, Brand);";
|
cmd.ExecuteNonQuery();
|
}
|
|
_initialized = true;
|
return true;
|
}
|
catch (Exception ex)
|
{
|
log?.Invoke($"[驱动库] 初始化失败({DatabasePath}): {ex.Message}");
|
return false;
|
}
|
}
|
|
private SQLiteConnection Open()
|
{
|
var conn = new SQLiteConnection($"Data Source={DatabasePath};Version=3;");
|
conn.Open();
|
return conn;
|
}
|
|
/// <summary>写入(覆盖)一个驱动包及其内部全部驱动类型的记录。</summary>
|
public void SavePackage(DriverPackage package, Action<string> log = null)
|
{
|
if (package == null)
|
{
|
return;
|
}
|
|
if (!EnsureReady(log))
|
{
|
return;
|
}
|
|
try
|
{
|
lock (_sync)
|
{
|
using (var conn = Open())
|
using (var tx = conn.BeginTransaction())
|
{
|
ExecuteNonQuery(conn, "DELETE FROM DriverType WHERE PackageFolder = @f",
|
tx, ("@f", package.Folder));
|
ExecuteNonQuery(conn, "DELETE FROM DriverPackage WHERE Folder = @f",
|
tx, ("@f", package.Folder));
|
|
var assemblies = package.Assemblies ?? new DriverAssemblyInfo[0];
|
ExecuteNonQuery(conn,
|
"INSERT INTO DriverPackage(Folder, Directory, AssemblyCount, ScanTime) VALUES(@f, @d, @c, @t)",
|
tx,
|
("@f", package.Folder),
|
("@d", package.Directory ?? string.Empty),
|
("@c", assemblies.Length.ToString()),
|
("@t", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
|
|
int typeCount = 0;
|
foreach (var asm in assemblies)
|
{
|
foreach (var type in asm.Types ?? new DriverTypeInfo[0])
|
{
|
ExecuteNonQuery(conn,
|
@"INSERT OR REPLACE INTO DriverType(PackageFolder, AssemblyFile, FullName, DriverType, Brand)
|
VALUES(@p, @a, @n, @t, @b)",
|
tx,
|
("@p", package.Folder),
|
("@a", asm.FileName ?? string.Empty),
|
("@n", type.FullName ?? string.Empty),
|
("@t", type.DriverType ?? string.Empty),
|
("@b", type.Brand ?? string.Empty));
|
typeCount++;
|
}
|
}
|
|
tx.Commit();
|
log?.Invoke($"[驱动库] 已保存 {package.Folder}({assemblies.Length} 个 dll,{typeCount} 个驱动类型)");
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
log?.Invoke($"[驱动库] 保存 {package.Folder} 失败: {ex.Message}");
|
}
|
}
|
|
/// <summary>删除一个驱动包(及其全部驱动类型)的记录。</summary>
|
public void RemovePackage(string folder, Action<string> log = null)
|
{
|
if (string.IsNullOrEmpty(folder) || !EnsureReady(log))
|
{
|
return;
|
}
|
|
try
|
{
|
lock (_sync)
|
{
|
using (var conn = Open())
|
using (var tx = conn.BeginTransaction())
|
{
|
ExecuteNonQuery(conn, "DELETE FROM DriverType WHERE PackageFolder = @f", tx, ("@f", folder));
|
ExecuteNonQuery(conn, "DELETE FROM DriverPackage WHERE Folder = @f", tx, ("@f", folder));
|
tx.Commit();
|
}
|
}
|
|
log?.Invoke($"[驱动库] 已移除 {folder} 的记录");
|
}
|
catch (Exception ex)
|
{
|
log?.Invoke($"[驱动库] 移除 {folder} 失败: {ex.Message}");
|
}
|
}
|
|
/// <summary>读取库中全部驱动类型记录(供界面/查询使用)。</summary>
|
public IReadOnlyList<DriverTypeInfo> LoadDriverTypes(Action<string> log = null)
|
{
|
var result = new List<DriverTypeInfo>();
|
if (!EnsureReady(log))
|
{
|
return result;
|
}
|
|
try
|
{
|
lock (_sync)
|
{
|
using (var conn = Open())
|
using (var cmd = conn.CreateCommand())
|
{
|
cmd.CommandText = "SELECT PackageFolder, AssemblyFile, FullName, DriverType, Brand FROM DriverType ORDER BY DriverType, Brand, FullName";
|
using (var reader = cmd.ExecuteReader())
|
{
|
while (reader.Read())
|
{
|
result.Add(new DriverTypeInfo
|
{
|
FullName = GetString(reader, "FullName"),
|
DriverType = GetString(reader, "DriverType"),
|
Brand = GetString(reader, "Brand")
|
});
|
}
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
log?.Invoke($"[驱动库] 读取驱动类型失败: {ex.Message}");
|
}
|
|
return result;
|
}
|
|
private static void ExecuteNonQuery(SQLiteConnection conn, string sql, SQLiteTransaction tx,
|
params (string Name, string Value)[] parameters)
|
{
|
using (var cmd = conn.CreateCommand())
|
{
|
cmd.Transaction = tx;
|
cmd.CommandText = sql;
|
foreach (var (name, value) in parameters)
|
{
|
cmd.Parameters.AddWithValue(name, value);
|
}
|
|
cmd.ExecuteNonQuery();
|
}
|
}
|
|
private static string GetString(SQLiteDataReader reader, string column)
|
{
|
var value = reader[column];
|
return value == DBNull.Value ? string.Empty : value.ToString();
|
}
|
}
|
}
|