核心功能: - ✅ Categories/Series双视图管理(category_view.rs + import_markdown.rs) - ✅ FUSE Multi-Volume支持(tree_type参数) - ✅ SSH/SFTP/SCP/rsync协议完整实现(4042行) - ✅ NFS/SMB Module Phase 1-3完成 - ✅ Archive Module Phase 1-4完成(2916行) - ✅ Download Center API完整实现 - ✅ S3兼容API实现(560行) Git配置修正: - ✅ 删除错误origin(gitea.momentry.ddns.net) - ✅ 删除m5max128(指向机器名) - ✅ 设置origin = m5max128gitea.momentry.ddns.net/admin/markbase - ✅ 设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase 数据清理: - ✅ 删除38个临时SQLite(保留accusys.sqlite、demo.sqlite) - ✅ 删除.bak、test_*.bin、调试脚本等临时文件 - ✅ 删除临时目录(build/、download files/、raid_test/等) - ✅ 更新.gitignore排除临时文件 架构优化: - 52个文件修改,2434行新增,4739行删除 - Workspace成员整合(16个crate) - 数据库状态:accusys.sqlite保留(主demo测试) 远程同步: - ✅ 准备推送到m5max128gitea(远程Gitea) - ✅ 准备推送到m4minigitea(本地Gitea)
360 lines
12 KiB
Swift
360 lines
12 KiB
Swift
import Foundation
|
|
import SQLite3
|
|
|
|
public class FileTreeImporter {
|
|
|
|
// MarkBase FileTree Importer
|
|
// Imports warren.sqlite file_nodes to MarkBaseFS Frame Index Table
|
|
// Maps file_nodes → frame_records
|
|
|
|
private var markBaseDB: OpaquePointer?
|
|
private var markBaseFSDB: OpaquePointer?
|
|
|
|
private let markBaseDBPath: String = "/Users/accusys/markbase/data/users/warren.sqlite"
|
|
private let markBaseFSDBPath: String
|
|
|
|
private var importedNodes: Int = 0
|
|
private var importedFiles: Int = 0
|
|
private var importedFolders: Int = 0
|
|
|
|
public init(markBaseFSDBPath: String) {
|
|
self.markBaseFSDBPath = markBaseFSDBPath
|
|
|
|
print("FileTreeImporter initializing...")
|
|
print(" - MarkBase DB: \(markBaseDBPath)")
|
|
print(" - MarkBaseFS DB: \(markBaseFSDBPath)")
|
|
}
|
|
|
|
public func importFileTree() -> Bool {
|
|
print("\n=== Importing MarkBase FileTree to MarkBaseFS ===")
|
|
|
|
// Open databases
|
|
if !openMarkBaseDB() {
|
|
return false
|
|
}
|
|
|
|
if !openMarkBaseFSDB() {
|
|
closeMarkBaseDB()
|
|
return false
|
|
}
|
|
|
|
// Import file_nodes
|
|
importFileNodes()
|
|
|
|
// Import file_registry
|
|
importFileRegistry()
|
|
|
|
// Import file_locations
|
|
importFileLocations()
|
|
|
|
// Report results
|
|
reportImportResults()
|
|
|
|
// Close databases
|
|
closeMarkBaseDB()
|
|
closeMarkBaseFSDB()
|
|
|
|
return true
|
|
}
|
|
|
|
// MARK: - Database Operations
|
|
|
|
private func openMarkBaseDB() -> Bool {
|
|
if sqlite3_open(markBaseDBPath, &markBaseDB) != SQLITE_OK {
|
|
print("Error opening MarkBase database: \(markBaseDBPath)")
|
|
return false
|
|
}
|
|
|
|
print("MarkBase database opened successfully")
|
|
return true
|
|
}
|
|
|
|
private func openMarkBaseFSDB() -> Bool {
|
|
if sqlite3_open(markBaseFSDBPath, &markBaseFSDB) != SQLITE_OK {
|
|
print("Error opening MarkBaseFS database: \(markBaseFSDBPath)")
|
|
return false
|
|
}
|
|
|
|
print("MarkBaseFS database opened successfully")
|
|
return true
|
|
}
|
|
|
|
private func closeMarkBaseDB() {
|
|
if markBaseDB != nil {
|
|
sqlite3_close(markBaseDB)
|
|
markBaseDB = nil
|
|
}
|
|
}
|
|
|
|
private func closeMarkBaseFSDB() {
|
|
if markBaseFSDB != nil {
|
|
sqlite3_close(markBaseFSDB)
|
|
markBaseFSDB = nil
|
|
}
|
|
}
|
|
|
|
// MARK: - Import Operations
|
|
|
|
private func importFileNodes() {
|
|
print("\nImporting file_nodes...")
|
|
|
|
let selectQuery = "SELECT node_id, label, parent_id, node_type, file_size, sha256 FROM file_nodes;"
|
|
|
|
var statement: OpaquePointer?
|
|
|
|
if sqlite3_prepare_v2(markBaseDB, selectQuery, -1, &statement, nil) == SQLITE_OK {
|
|
|
|
while sqlite3_step(statement) == SQLITE_ROW {
|
|
let nodeId = String(cString: sqlite3_column_text(statement, 0))
|
|
let label = String(cString: sqlite3_column_text(statement, 1))
|
|
|
|
// Handle NULL parent_id (Home folder has no parent)
|
|
let parentId: String
|
|
if let parentIdPtr = sqlite3_column_text(statement, 2) {
|
|
parentId = String(cString: parentIdPtr)
|
|
} else {
|
|
parentId = "root"
|
|
}
|
|
|
|
let nodeType = String(cString: sqlite3_column_text(statement, 3))
|
|
let fileSize = sqlite3_column_int(statement, 4)
|
|
|
|
// Handle NULL sha256 (folders don't have sha256)
|
|
let sha256: String
|
|
if let sha256Ptr = sqlite3_column_text(statement, 5) {
|
|
sha256 = String(cString: sha256Ptr)
|
|
} else {
|
|
sha256 = ""
|
|
}
|
|
|
|
// Insert to MarkBaseFS frame_records
|
|
insertToFrameRecords(
|
|
nodeId: nodeId,
|
|
label: label,
|
|
parentId: parentId,
|
|
nodeType: nodeType,
|
|
fileSize: Int(fileSize),
|
|
sha256: sha256
|
|
)
|
|
|
|
importedNodes += 1
|
|
|
|
if nodeType == "folder" {
|
|
importedFolders += 1
|
|
} else {
|
|
importedFiles += 1
|
|
}
|
|
|
|
if importedNodes % 1000 == 0 {
|
|
print(" - Imported \(importedNodes) nodes...")
|
|
}
|
|
}
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
|
|
print("file_nodes import complete: \(importedNodes) nodes")
|
|
}
|
|
|
|
private func importFileRegistry() {
|
|
print("\nImporting file_registry...")
|
|
|
|
let selectQuery = "SELECT file_uuid, original_name, file_size, file_type FROM file_registry;"
|
|
|
|
var statement: OpaquePointer?
|
|
var registryCount: Int = 0
|
|
|
|
if sqlite3_prepare_v2(markBaseDB, selectQuery, -1, &statement, nil) == SQLITE_OK {
|
|
|
|
while sqlite3_step(statement) == SQLITE_ROW {
|
|
let fileUuid = String(cString: sqlite3_column_text(statement, 0))
|
|
let originalName = String(cString: sqlite3_column_text(statement, 1))
|
|
let fileSize = sqlite3_column_int(statement, 2)
|
|
let fileType = String(cString: sqlite3_column_text(statement, 3))
|
|
|
|
// Insert to video_metadata (using file_uuid as video_id)
|
|
insertToVideoMetadata(
|
|
videoId: fileUuid,
|
|
videoName: originalName,
|
|
fileSize: Int(fileSize),
|
|
fileType: fileType
|
|
)
|
|
|
|
registryCount += 1
|
|
}
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
|
|
print("file_registry import complete: \(registryCount) files")
|
|
}
|
|
|
|
private func importFileLocations() {
|
|
print("\nImporting file_locations...")
|
|
|
|
let selectQuery = "SELECT file_uuid, location, label FROM file_locations;"
|
|
|
|
var statement: OpaquePointer?
|
|
var locationCount: Int = 0
|
|
|
|
if sqlite3_prepare_v2(markBaseDB, selectQuery, -1, &statement, nil) == SQLITE_OK {
|
|
|
|
while sqlite3_step(statement) == SQLITE_ROW {
|
|
let fileUuid = String(cString: sqlite3_column_text(statement, 0))
|
|
let location = String(cString: sqlite3_column_text(statement, 1))
|
|
let label = String(cString: sqlite3_column_text(statement, 2))
|
|
|
|
// Store location as frame_file path
|
|
updateFrameLocation(fileUuid: fileUuid, location: location)
|
|
|
|
locationCount += 1
|
|
}
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
|
|
print("file_locations import complete: \(locationCount) locations")
|
|
}
|
|
|
|
// MARK: - Insert Operations
|
|
|
|
private func insertToFrameRecords(nodeId: String, label: String, parentId: String, nodeType: String, fileSize: Int, sha256: String) {
|
|
let insertQuery = """
|
|
INSERT INTO frame_records (frame_id, video_id, frame_index, frame_file, frame_offset, frame_size, frame_checksum)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?);
|
|
"""
|
|
|
|
var statement: OpaquePointer?
|
|
|
|
if sqlite3_prepare_v2(markBaseFSDB, insertQuery, -1, &statement, nil) == SQLITE_OK {
|
|
// frame_id = node_id
|
|
sqlite3_bind_text(statement, 1, (nodeId as NSString).utf8String, -1, nil)
|
|
|
|
// video_id = parent_id (treating parent folder as video)
|
|
sqlite3_bind_text(statement, 2, (parentId as NSString).utf8String, -1, nil)
|
|
|
|
// frame_index = 0 (all nodes are frame 0 for now)
|
|
sqlite3_bind_int(statement, 3, 0)
|
|
|
|
// frame_file = label (filename)
|
|
sqlite3_bind_text(statement, 4, (label as NSString).utf8String, -1, nil)
|
|
|
|
// frame_offset = 0
|
|
sqlite3_bind_int(statement, 5, 0)
|
|
|
|
// frame_size = file_size
|
|
sqlite3_bind_int(statement, 6, Int32(fileSize))
|
|
|
|
// frame_checksum = sha256
|
|
sqlite3_bind_text(statement, 7, (sha256 as NSString).utf8String, -1, nil)
|
|
|
|
if sqlite3_step(statement) != SQLITE_DONE {
|
|
print("Error inserting frame_record: \(nodeId)")
|
|
}
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
}
|
|
|
|
private func insertToVideoMetadata(videoId: String, videoName: String, fileSize: Int, fileType: String) {
|
|
let insertQuery = """
|
|
INSERT INTO video_metadata (video_id, video_name, total_frames)
|
|
VALUES (?, ?, ?);
|
|
"""
|
|
|
|
var statement: OpaquePointer?
|
|
|
|
if sqlite3_prepare_v2(markBaseFSDB, insertQuery, -1, &statement, nil) == SQLITE_OK {
|
|
sqlite3_bind_text(statement, 1, (videoId as NSString).utf8String, -1, nil)
|
|
sqlite3_bind_text(statement, 2, (videoName as NSString).utf8String, -1, nil)
|
|
sqlite3_bind_int(statement, 3, 1) // total_frames = 1
|
|
|
|
sqlite3_step(statement)
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
}
|
|
|
|
private func updateFrameLocation(fileUuid: String, location: String) {
|
|
let updateQuery = """
|
|
UPDATE frame_records SET frame_file = ? WHERE frame_id = ?;
|
|
"""
|
|
|
|
var statement: OpaquePointer?
|
|
|
|
if sqlite3_prepare_v2(markBaseFSDB, updateQuery, -1, &statement, nil) == SQLITE_OK {
|
|
sqlite3_bind_text(statement, 1, (location as NSString).utf8String, -1, nil)
|
|
sqlite3_bind_text(statement, 2, (fileUuid as NSString).utf8String, -1, nil)
|
|
|
|
sqlite3_step(statement)
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
}
|
|
|
|
// MARK: - Report
|
|
|
|
private func reportImportResults() {
|
|
print("\n=== Import Results ===")
|
|
print(" - Total nodes imported: \(importedNodes)")
|
|
print(" - Folders imported: \(importedFolders)")
|
|
print(" - Files imported: \(importedFiles)")
|
|
print(" - Success rate: \(String(format: "%.1f", Double(importedNodes) / Double(importedNodes + importedFiles) * 100))%")
|
|
|
|
print("\n=== Import Complete ===")
|
|
}
|
|
|
|
// MARK: - Test
|
|
|
|
public func testImport() {
|
|
print("\n=== FileTreeImporter Test ===")
|
|
|
|
// Test 1: Check MarkBase database
|
|
print("Test 1: Check MarkBase database")
|
|
if openMarkBaseDB() {
|
|
let countQuery = "SELECT COUNT(*) FROM file_nodes;"
|
|
var statement: OpaquePointer?
|
|
|
|
if sqlite3_prepare_v2(markBaseDB, countQuery, -1, &statement, nil) == SQLITE_OK {
|
|
if sqlite3_step(statement) == SQLITE_ROW {
|
|
let count = sqlite3_column_int(statement, 0)
|
|
print(" - file_nodes count: \(count)")
|
|
print(" - Result: ✅ SUCCESS")
|
|
}
|
|
}
|
|
|
|
sqlite3_finalize(statement)
|
|
closeMarkBaseDB()
|
|
}
|
|
|
|
// Test 2: Import test
|
|
print("\nTest 2: Import test")
|
|
let testDBPath = "/tmp/test_import.sqlite"
|
|
|
|
// Create test database
|
|
if sqlite3_open(testDBPath, &markBaseFSDB) == SQLITE_OK {
|
|
// Create tables
|
|
let createTableQuery = """
|
|
CREATE TABLE IF NOT EXISTS frame_records (
|
|
frame_id TEXT PRIMARY KEY,
|
|
video_id TEXT,
|
|
frame_index INTEGER,
|
|
frame_file TEXT,
|
|
frame_offset INTEGER,
|
|
frame_size INTEGER,
|
|
frame_checksum TEXT
|
|
);
|
|
"""
|
|
|
|
sqlite3_exec(markBaseFSDB, createTableQuery, nil, nil, nil)
|
|
|
|
print(" - Test database created")
|
|
print(" - Result: ✅ SUCCESS")
|
|
|
|
sqlite3_close(markBaseFSDB)
|
|
markBaseFSDB = nil
|
|
}
|
|
|
|
print("\n=== FileTreeImporter Test Complete ===")
|
|
}
|
|
} |