MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

核心功能:
-  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)
This commit is contained in:
Warren
2026-06-12 12:59:54 +08:00
parent 4cb7e80568
commit 1300a4e223
4559 changed files with 195840 additions and 4244 deletions

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>MarkBaseFS</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.accusys.markbase.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MarkBaseFS</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>14.0</string>
<key>LSUIElement</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2026 Accusys, Inc. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>25F71</string>
<key>CFBundleDisplayName</key>
<string>MarkBaseFS</string>
<key>CFBundleExecutable</key>
<string>com.accusys.markbase.fskitmodule</string>
<key>CFBundleIdentifier</key>
<string>com.accusys.markbase.fskitmodule</string>
<key>CFBundleName</key>
<string>MarkBaseFS FSKit Module</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>25F70</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>26.5</string>
<key>DTSDKBuild</key>
<string>25F70</string>
<key>DTSDKName</key>
<string>macosx26.5</string>
<key>DTXcode</key>
<string>2650</string>
<key>DTXcodeBuild</key>
<string>17F42</string>
<key>EXAppExtensionAttributes</key>
<dict>
<key>EXExtensionPointIdentifier</key>
<string>com.apple.fskit.fsmodule</string>
<key>EXExtensionPrincipalClass</key>
<string>MarkBaseFSModule</string>
<key>FSMediaTypes</key>
<dict>
<key>B8A9778D-F1AF-41A0-B7FF-C360A7878CD3</key>
<dict>
<key>FSMediaProperties</key>
<dict>
<key>Content Hint</key>
<string>B8A9778D-F1AF-41A0-B7FF-C360A7878CD3</string>
<key>Leaf</key>
<true/>
</dict>
<key>FSProbeArguments</key>
<string>-p</string>
<key>FSProbeExecutable</key>
<string>MarkBaseFSProbe</string>
<key>FSProbeOrder</key>
<integer>2000</integer>
</dict>
</dict>
<key>FSPersonalities</key>
<dict>
<key>MarkBaseFS</key>
<dict>
<key>FSFormatOptions</key>
<dict>
<key>shortOptions</key>
<string>NRI:S:a:b:c:n:s:v:</string>
</dict>
<key>FSMountOptions</key>
<dict>
<key>shortOptions</key>
<string>dnqS:y</string>
</dict>
</dict>
</dict>
<key>FSRequiresSecurityScopedPathURLResources</key>
<false/>
<key>FSShortName</key>
<string>markbasefs</string>
<key>FSSupportedSchemes</key>
<array>
<string>markbasefs</string>
</array>
<key>FSSupportsBlockResources</key>
<false/>
<key>FSSupportsGenericURLResources</key>
<true/>
<key>FSSupportsPathURLs</key>
<false/>
</dict>
<key>LSMinimumSystemVersion</key>
<string>15.4</string>
</dict>
</plist>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.accusys.markbase.fskitmodule</string>
<key>CFBundleName</key>
<string>MarkBaseFS FSKit Module</string>
<key>CFBundleDisplayName</key>
<string>MarkBaseFS</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleExecutable</key>
<string>com.accusys.markbase.fskitmodule</string>
<key>EXAppExtensionAttributes</key>
<dict>
<key>EXExtensionPointIdentifier</key>
<string>com.apple.fskit.fsmodule</string>
<key>EXExtensionPrincipalClass</key>
<string>MarkBaseFSModule</string>
<key>FSShortName</key>
<string>markbasefs</string>
<key>FSMediaTypes</key>
<dict/>
<key>FSPersonalities</key>
<dict/>
<key>FSSupportedSchemes</key>
<array>
<string>markbasefs</string>
</array>
<key>FSSupportsBlockResources</key>
<false/>
<key>FSSupportsGenericURLResources</key>
<true/>
<key>FSSupportsPathURLs</key>
<false/>
<key>FSRequiresSecurityScopedPathURLResources</key>
<false/>
</dict>
<key>LSMinimumSystemVersion</key>
<string>15.4</string>
</dict>
</plist>

View File

@@ -0,0 +1,61 @@
import Foundation
import FSKit
@available(macOS 15.4, *)
public class MarkBaseFSModule: NSObject, FSUnaryFileSystemOperations, @unchecked Sendable {
// MarkBaseFS FSKit Module Entry Point
// Implements FSUnaryFileSystemOperations protocol
public required override init() {
super.init()
print("MarkBaseFSModule initializing...")
}
// MARK: - FSUnaryFileSystemOperations
public func probeResource(_ resource: FSResource, replyHandler: @escaping (FSProbeResult?, Error?) -> Void) {
print("MarkBaseFSModule probeResource() called")
// Create probe result
let result = FSProbeResult()
result.matchResult = .usable
print(" - Resource probe complete: usable")
replyHandler(result, nil)
}
public func loadResource(_ resource: FSResource, options: FSTaskOptions, replyHandler: @escaping (FSVolume?, Error?) -> Void) {
print("MarkBaseFSModule loadResource() called")
// Create Volume.Identifier
let volumeID = FSVolume.Identifier()
// Create Volume Name
let volumeName = FSFileName(string: "MarkBaseFS")
// Create Volume (using MarkBaseFSVolumeFSKit)
let volume = MarkBaseFSVolumeFSKit(volumeID: volumeID, volumeName: volumeName)
print(" - Volume created: \(volumeID.uuid)")
replyHandler(volume, nil)
}
public func unloadResource(_ resource: FSResource, options: FSTaskOptions, replyHandler: @escaping (Error?) -> Void) {
print("MarkBaseFSModule unloadResource() called")
print(" - Resource unloaded successfully")
replyHandler(nil)
}
// MARK: - Optional Methods
public func didFinishLoading() {
print("MarkBaseFSModule didFinishLoading() called")
print(" - Module loaded by FSKit daemon")
print(" - Ready to receive FSKit requests")
}
}

View File

@@ -0,0 +1,36 @@
import Foundation
import FSKit
@available(macOS 15.4, *)
public class MarkBaseFSVolumeFSKit: FSVolume, @unchecked Sendable {
// MarkBaseFS Volume (Simplified)
// Implements FSVolume for FSKit Module
private var supportedCapabilities: FSVolume.SupportedCapabilities
public init(volumeID: FSVolume.Identifier, volumeName: FSFileName) {
// Initialize supported capabilities
self.supportedCapabilities = FSVolume.SupportedCapabilities()
// Configure supported capabilities
supportedCapabilities.supportsPersistentObjectIDs = true
supportedCapabilities.supportsSymbolicLinks = true
supportedCapabilities.supportsHardLinks = true
supportedCapabilities.supportsSparseFiles = true
supportedCapabilities.supports2TBFiles = true
// Initialize FSVolume
super.init(volumeID: volumeID, volumeName: volumeName)
print("MarkBaseFSVolumeFSKit initializing...")
print(" - Volume ID: \(volumeID.uuid)")
print(" - Volume Name: MarkBaseFS")
}
// MARK: - FSVolume Properties
public var supportedVolumeCapabilities: FSVolume.SupportedCapabilities {
return supportedCapabilities
}
}

View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Resources/MarkBaseFS.xfskitmodule/Info.plist</key>
<data>
MorQJuzEpGXT4HttAfBQFrxfraI=
</data>
<key>Resources/MarkBaseFS.xfskitmodule/MarkBaseFSModule.swift</key>
<data>
onzcikiMin40bPuGuthdCG1gIRo=
</data>
<key>Resources/MarkBaseFS.xfskitmodule/MarkBaseFSVolume.swift</key>
<data>
P57gRn48tyPs0DNo7QK5rlWo2gs=
</data>
<key>Resources/MarkBaseFS.xfskitmodule/entitlements.plist</key>
<data>
hJx2QVQzL1bI9Owakvl5ZC+GL+g=
</data>
</dict>
<key>files2</key>
<dict>
<key>Resources/MarkBaseFS.xfskitmodule/Info.plist</key>
<dict>
<key>hash2</key>
<data>
zr1hYvu5iVcFOrO/QgM+Uj3vLezPInwjSEuAXv0c8eI=
</data>
</dict>
<key>Resources/MarkBaseFS.xfskitmodule/MarkBaseFSModule.swift</key>
<dict>
<key>hash2</key>
<data>
RhpjkCcbRNJEWeXGIOOcQYOXhrYbCQ8pQZuHRZiZBVM=
</data>
</dict>
<key>Resources/MarkBaseFS.xfskitmodule/MarkBaseFSVolume.swift</key>
<dict>
<key>hash2</key>
<data>
QMmCTjehwcvYUWvee26RFj3v5V0UnPXkQx240bfsKYY=
</data>
</dict>
<key>Resources/MarkBaseFS.xfskitmodule/entitlements.plist</key>
<dict>
<key>hash2</key>
<data>
welSYeJ3oySjKDmpg1McoShAUg2LlViq/bs5EgHQJ3Y=
</data>
</dict>
</dict>
<key>rules</key>
<dict>
<key>^Resources/</key>
<true/>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^.*</key>
<true/>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^[^/]+$</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>

Binary file not shown.

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.fskit.fsmodule</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

Binary file not shown.

View File

@@ -0,0 +1,20 @@
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
var menuBarController: MenuBarController?
func applicationDidFinishLaunching(_ aNotification: Notification) {
menuBarController = MenuBarController()
menuBarController?.setupMenuBar()
print("MarkBaseFS Host App started")
}
func applicationWillTerminate(_ aNotification: Notification) {
print("MarkBaseFS Host App terminating")
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View File

@@ -0,0 +1,99 @@
import Foundation
import SQLite3
class DatabaseConfig {
private var currentDatabasePath: String = "/Users/accusys/markbase/data/users/warren.sqlite"
func getCurrentDatabasePath() -> String {
return currentDatabasePath
}
func setDatabasePath(_ path: String) {
currentDatabasePath = path
}
func validateDatabase(path: String) -> Bool {
let fileManager = FileManager.default
if !fileManager.fileExists(atPath: path) {
print("Database file not found: \(path)")
return false
}
var db: OpaquePointer?
let result = sqlite3_open(path, &db)
if result != SQLITE_OK {
print("Failed to open database: \(path)")
return false
}
var statement: OpaquePointer?
let query = "SELECT name FROM sqlite_master WHERE type='table' AND name='file_nodes'"
if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
if sqlite3_step(statement) == SQLITE_ROW {
sqlite3_finalize(statement)
sqlite3_close(db)
print("Database validated: \(path)")
return true
}
}
sqlite3_finalize(statement)
sqlite3_close(db)
print("Database validation failed: file_nodes table not found")
return false
}
func getNodeCount() -> Int {
var db: OpaquePointer?
let result = sqlite3_open(currentDatabasePath, &db)
if result != SQLITE_OK {
print("Failed to open database for node count")
return 0
}
var statement: OpaquePointer?
let query = "SELECT COUNT(*) FROM file_nodes"
var count: Int = 0
if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
if sqlite3_step(statement) == SQLITE_ROW {
count = Int(sqlite3_column_int64(statement, 0))
}
}
sqlite3_finalize(statement)
sqlite3_close(db)
return count
}
func checkIntegrity() -> Bool {
var db: OpaquePointer?
let result = sqlite3_open(currentDatabasePath, &db)
if result != SQLITE_OK {
return false
}
var statement: OpaquePointer?
let query = "PRAGMA integrity_check"
if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
if sqlite3_step(statement) == SQLITE_ROW {
let text = String(cString: sqlite3_column_text(statement, 0))
sqlite3_finalize(statement)
sqlite3_close(db)
return text == "ok"
}
}
sqlite3_finalize(statement)
sqlite3_close(db)
return false
}
}

View File

@@ -0,0 +1,29 @@
import Cocoa
class MenuBarController {
private var statusItem: NSStatusItem?
private var statusMenu: StatusMenu?
private var mountService: MountService?
private var statusMonitor: StatusMonitor?
func setupMenuBar() {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
if let button = statusItem?.button {
button.image = NSImage(systemSymbolName: "folder.fill", accessibilityDescription: "MarkBaseFS")
button.image?.isTemplate = true
}
mountService = MountService()
statusMonitor = StatusMonitor()
statusMenu = StatusMenu(mountService: mountService!, statusMonitor: statusMonitor!)
statusItem?.menu = statusMenu?.createMenu()
statusMonitor?.startMonitoring()
}
func updateStatus(_ status: String) {
statusMenu?.updateStatusText(status)
}
}

View File

@@ -0,0 +1,82 @@
import Foundation
import FSKit
enum MountError: Error {
case extensionNotAvailable
case mountFailed(String)
case unmountFailed(String)
case invalidPath
}
class MountService {
private var currentMountPoint: URL?
private let defaultMountPoint = URL(fileURLWithPath: "/Volumes/MarkBase_warren")
private let fsClient = FSClient.shared
func mount() -> Result<Void, MountError> {
print("Attempting to mount MarkBaseFS...")
fsClient.fetchInstalledExtensions { extensions, error in
if let error = error {
print("ERROR fetching extensions: \(error)")
return
}
guard let extensions = extensions else {
print("ERROR: No extensions returned")
return
}
print("Found \(extensions.count) FSKit Extensions")
let markbaseExtension = extensions.filter { $0.bundleIdentifier.contains("markbase") }
if markbaseExtension.isEmpty {
print("ERROR: MarkBaseFS Extension not found")
return
}
print("MarkBaseFS Extension found: \(markbaseExtension.first!.bundleIdentifier)")
}
let mountPoint = defaultMountPoint
if !FileManager.default.fileExists(atPath: mountPoint.path) {
do {
try FileManager.default.createDirectory(at: mountPoint, withIntermediateDirectories: true)
print("Created mount point: \(mountPoint.path)")
} catch {
print("ERROR creating mount point: \(error)")
return .failure(.invalidPath)
}
}
currentMountPoint = mountPoint
print("Mount successful (placeholder - will use FSKit API)")
return .success(())
}
func unmount() -> Result<Void, MountError> {
print("Attempting to unmount MarkBaseFS...")
guard let mountPoint = currentMountPoint else {
print("No active mount")
return .failure(.unmountFailed("No active mount"))
}
print("Unmounting: \(mountPoint.path)")
currentMountPoint = nil
print("Unmount successful (placeholder - will use FSKit API)")
return .success(())
}
func getMountStatus() -> String {
if currentMountPoint != nil {
return "Mounted at \(currentMountPoint!.path)"
} else {
return "Unmounted"
}
}
}

View File

@@ -0,0 +1,98 @@
import Cocoa
import UniformTypeIdentifiers
class SettingsWindow: NSWindowController {
private var databasePathField: NSTextField?
private var mountPointField: NSTextField?
convenience init() {
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 400, height: 200),
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
window.title = "MarkBaseFS Settings"
window.center()
self.init(window: window)
setupUI()
}
private func setupUI() {
guard let window = window else { return }
let contentView = NSView(frame: window.contentRect(forFrameRect: window.frame))
let databaseLabel = NSTextField(frame: NSRect(x: 20, y: 150, width: 100, height: 24))
databaseLabel.stringValue = "Database Path:"
databaseLabel.isEditable = false
databaseLabel.isBezeled = false
databaseLabel.drawsBackground = false
contentView.addSubview(databaseLabel)
databasePathField = NSTextField(frame: NSRect(x: 120, y: 150, width: 200, height: 24))
databasePathField?.stringValue = DatabaseConfig().getCurrentDatabasePath()
contentView.addSubview(databasePathField!)
let browseButton = NSButton(frame: NSRect(x: 330, y: 150, width: 50, height: 24))
browseButton.title = "Browse"
browseButton.bezelStyle = .rounded
browseButton.target = self
browseButton.action = #selector(browseDatabase)
contentView.addSubview(browseButton)
let mountLabel = NSTextField(frame: NSRect(x: 20, y: 100, width: 100, height: 24))
mountLabel.stringValue = "Mount Point:"
mountLabel.isEditable = false
mountLabel.isBezeled = false
mountLabel.drawsBackground = false
contentView.addSubview(mountLabel)
mountPointField = NSTextField(frame: NSRect(x: 120, y: 100, width: 260, height: 24))
mountPointField?.stringValue = "/Volumes/MarkBase_warren"
contentView.addSubview(mountPointField!)
let applyButton = NSButton(frame: NSRect(x: 200, y: 20, width: 80, height: 24))
applyButton.title = "Apply"
applyButton.bezelStyle = .rounded
applyButton.target = self
applyButton.action = #selector(applySettings)
contentView.addSubview(applyButton)
let cancelButton = NSButton(frame: NSRect(x: 300, y: 20, width: 80, height: 24))
cancelButton.title = "Cancel"
cancelButton.bezelStyle = .rounded
cancelButton.target = self
cancelButton.action = #selector(cancelSettings)
contentView.addSubview(cancelButton)
window.contentView = contentView
}
@objc func browseDatabase() {
let openPanel = NSOpenPanel()
if let sqliteType = UTType(filenameExtension: "sqlite") {
openPanel.allowedContentTypes = [sqliteType]
}
openPanel.allowsMultipleSelection = false
if openPanel.runModal() == .OK {
if let url = openPanel.url {
databasePathField?.stringValue = url.path
}
}
}
@objc func applySettings() {
print("Settings applied")
close()
}
@objc func cancelSettings() {
print("Settings cancelled")
close()
}
}

View File

@@ -0,0 +1,115 @@
import Cocoa
class StatusMenu: NSMenu {
private let mountService: MountService
private let statusMonitor: StatusMonitor
private var statusMenuItem: NSMenuItem?
private var mountMenuItem: NSMenuItem?
private var unmountMenuItem: NSMenuItem?
init(mountService: MountService, statusMonitor: StatusMonitor) {
self.mountService = mountService
self.statusMonitor = statusMonitor
super.init(title: "MarkBaseFS")
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createMenu() -> NSMenu {
let menu = NSMenu()
statusMenuItem = NSMenuItem(title: "Status: Unmounted", action: nil, keyEquivalent: "")
statusMenuItem?.isEnabled = false
menu.addItem(statusMenuItem!)
menu.addItem(NSMenuItem.separator())
let infoItem = NSMenuItem(title: "Nodes: 0", action: nil, keyEquivalent: "")
infoItem.isEnabled = false
menu.addItem(infoItem)
menu.addItem(NSMenuItem.separator())
mountMenuItem = NSMenuItem(title: "Mount", action: #selector(mountAction), keyEquivalent: "m")
mountMenuItem?.target = self
menu.addItem(mountMenuItem!)
unmountMenuItem = NSMenuItem(title: "Unmount", action: #selector(unmountAction), keyEquivalent: "u")
unmountMenuItem?.target = self
unmountMenuItem?.isEnabled = false
menu.addItem(unmountMenuItem!)
menu.addItem(NSMenuItem.separator())
let settingsItem = NSMenuItem(title: "Settings...", action: #selector(openSettings), keyEquivalent: "s")
settingsItem.target = self
menu.addItem(settingsItem)
menu.addItem(NSMenuItem.separator())
let quitItem = NSMenuItem(title: "Quit", action: #selector(quitAction), keyEquivalent: "q")
quitItem.target = self
menu.addItem(quitItem)
return menu
}
func updateStatusText(_ text: String) {
statusMenuItem?.title = "Status: \(text)"
}
@objc func mountAction() {
print("Mount action triggered")
let result = mountService.mount()
switch result {
case .success:
updateStatusText("Mounted")
mountMenuItem?.isEnabled = false
unmountMenuItem?.isEnabled = true
print("Mount successful")
case .failure(let error):
print("Mount failed: \(error)")
showAlert(title: "Mount Failed", message: error.localizedDescription)
}
}
@objc func unmountAction() {
print("Unmount action triggered")
let result = mountService.unmount()
switch result {
case .success:
updateStatusText("Unmounted")
mountMenuItem?.isEnabled = true
unmountMenuItem?.isEnabled = false
print("Unmount successful")
case .failure(let error):
print("Unmount failed: \(error)")
showAlert(title: "Unmount Failed", message: error.localizedDescription)
}
}
@objc func openSettings() {
print("Open settings")
let settingsWindow = SettingsWindow()
settingsWindow.showWindow(nil)
}
@objc func quitAction() {
print("Quit action")
NSApplication.shared.terminate(nil)
}
private func showAlert(title: String, message: String) {
let alert = NSAlert()
alert.messageText = title
alert.informativeText = message
alert.alertStyle = .warning
alert.addButton(withTitle: "OK")
alert.runModal()
}
}

View File

@@ -0,0 +1,45 @@
import Foundation
import SQLite3
class StatusMonitor {
private var timer: Timer?
private let databaseConfig = DatabaseConfig()
private var nodeCount: Int = 0
private var lastUpdateTime: Date = Date()
func startMonitoring() {
print("Starting status monitoring...")
updateStats()
timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { _ in
self.updateStats()
}
}
func stopMonitoring() {
timer?.invalidate()
timer = nil
print("Status monitoring stopped")
}
func updateStats() {
nodeCount = databaseConfig.getNodeCount()
lastUpdateTime = Date()
print("Stats updated: \(nodeCount) nodes")
}
func getNodeCount() -> Int {
return nodeCount
}
func getLastUpdateTime() -> Date {
return lastUpdateTime
}
func getDatabasePath() -> String {
return databaseConfig.getCurrentDatabasePath()
}
}

View File

@@ -0,0 +1,6 @@
import Cocoa
let appDelegate = AppDelegate()
NSApplication.shared.delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

View File

@@ -0,0 +1,21 @@
import Foundation
print("MarkBaseFS Host App - Test Compile")
print("Sources directory exists")
let files = [
"main.swift",
"AppDelegate.swift",
"MenuBarController.swift",
"StatusMenu.swift",
"MountService.swift",
"StatusMonitor.swift",
"DatabaseConfig.swift",
"SettingsWindow.swift"
]
for file in files {
print(" - \(file)")
}
print("\nAll source files created successfully")