@@ -24,6 +24,7 @@ extension KeyKeyUserDBKit {
2424 public init ( path: String ) throws {
2525 self . path = path
2626 self . actor = . init( label: " KeyKeyUserDBQueue. \( UUID ( ) . uuidString) " )
27+ self . inMemoryData = nil
2728
2829 // sbooth/CSQLite is built with SQLITE_OMIT_AUTOINIT, so we need to call sqlite3_initialize() first.
2930 #if !canImport(Darwin)
@@ -44,6 +45,66 @@ extension KeyKeyUserDBKit {
4445 self . db = dbPointer
4546 }
4647
48+ /// 從記憶體中的資料開啟資料庫(無需寫入臨時檔案)
49+ /// - Parameter data: 解密後的資料庫二進位資料
50+ /// - Throws: `DatabaseError` 如果開啟失敗
51+ public init ( data: Data ) throws {
52+ self . path = nil
53+ self . actor = . init( label: " KeyKeyUserDBQueue. \( UUID ( ) . uuidString) " )
54+
55+ // sbooth/CSQLite is built with SQLITE_OMIT_AUTOINIT, so we need to call sqlite3_initialize() first.
56+ #if !canImport(Darwin)
57+ sqlite3_initialize ( )
58+ #endif
59+
60+ // 開啟一個記憶體資料庫
61+ var dbPointer : OpaquePointer ?
62+ guard sqlite3_open ( " :memory: " , & dbPointer) == SQLITE_OK else {
63+ let errorMessage : String
64+ if let dbPointer {
65+ errorMessage = String ( cString: sqlite3_errmsg ( dbPointer) )
66+ sqlite3_close ( dbPointer)
67+ } else {
68+ errorMessage = " Unknown error "
69+ }
70+ throw DatabaseError . openFailed ( message: errorMessage)
71+ }
72+
73+ // 複製 data 到可變的記憶體區塊(sqlite3_deserialize 需要)
74+ // 使用 sqlite3_malloc64 分配記憶體,讓 SQLite 管理生命週期
75+ let dataSize = Int64 ( data. count)
76+ guard let buffer = sqlite3_malloc64 ( UInt64 ( dataSize) ) else {
77+ sqlite3_close ( dbPointer)
78+ throw DatabaseError . openFailed ( message: " Failed to allocate memory for database " )
79+ }
80+
81+ // 複製資料到緩衝區
82+ _ = data. withUnsafeBytes { bytes in
83+ memcpy ( buffer, bytes. baseAddress, data. count)
84+ }
85+
86+ // 使用 sqlite3_deserialize 載入資料庫
87+ // SQLITE_DESERIALIZE_FREEONCLOSE: 當資料庫關閉時,SQLite 會自動釋放緩衝區
88+ // SQLITE_DESERIALIZE_RESIZEABLE: 允許資料庫調整大小(雖然我們只讀取)
89+ let result = sqlite3_deserialize (
90+ dbPointer,
91+ " main " ,
92+ buffer. assumingMemoryBound ( to: UInt8 . self) ,
93+ dataSize,
94+ dataSize,
95+ UInt32 ( SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE)
96+ )
97+
98+ guard result == SQLITE_OK else {
99+ let errorMessage = String ( cString: sqlite3_errmsg ( dbPointer) )
100+ sqlite3_close ( dbPointer)
101+ throw DatabaseError . openFailed ( message: " Failed to deserialize database: \( errorMessage) " )
102+ }
103+
104+ self . db = dbPointer
105+ self . inMemoryData = nil // 記憶體由 SQLite 管理,不需要保留引用
106+ }
107+
47108 deinit {
48109 actor . sync {
49110 if let db {
@@ -57,6 +118,22 @@ extension KeyKeyUserDBKit {
57118 /// 候選字覆蓋記錄的預設權重
58119 public static let candidateOverrideProbability : Double = 114.514
59120
121+ /// 從加密的資料庫檔案載入到記憶體資料庫(無需寫入臨時檔案)
122+ /// - Parameters:
123+ /// - url: 加密資料庫檔案的 URL
124+ /// - decryptor: 用於解密的 SEEDecryptor 實例(預設使用預設密鑰)
125+ /// - Returns: 已開啟的記憶體資料庫
126+ /// - Throws: `DecryptionError` 或 `DatabaseError`
127+ public static func openEncrypted(
128+ at url: URL ,
129+ decryptor: SEEDecryptor = . init( )
130+ ) throws
131+ -> UserDatabase {
132+ let encryptedData = try Data ( contentsOf: url)
133+ let decryptedData = try decryptor. decrypt ( encryptedData: encryptedData)
134+ return try UserDatabase ( data: decryptedData)
135+ }
136+
60137 // MARK: - Public Methods
61138
62139 /// 讀取所有使用者單元圖
@@ -216,8 +293,10 @@ extension KeyKeyUserDBKit {
216293 // MARK: Private
217294
218295 private nonisolated ( unsafe) let db: OpaquePointer ?
219- private let path : String
296+ private let path : String ?
220297 private let actor : DispatchQueue
298+ /// 保留記憶體資料的引用(如果需要的話)
299+ private let inMemoryData : Data ?
221300 }
222301}
223302
0 commit comments