2026-01-27 14:12:17 -06:00
|
|
|
import Foundation
|
|
|
|
|
|
2026-03-02 11:32:04 +00:00
|
|
|
final class ConfigFileWatcher: @unchecked Sendable, SimpleFileWatcherOwner {
|
2026-01-27 14:12:17 -06:00
|
|
|
private let url: URL
|
|
|
|
|
private let watchedDir: URL
|
|
|
|
|
private let targetPath: String
|
|
|
|
|
private let targetName: String
|
2026-03-02 11:32:04 +00:00
|
|
|
let watcher: SimpleFileWatcher
|
2026-01-27 14:12:17 -06:00
|
|
|
|
|
|
|
|
init(url: URL, onChange: @escaping () -> Void) {
|
|
|
|
|
self.url = url
|
|
|
|
|
self.watchedDir = url.deletingLastPathComponent()
|
|
|
|
|
self.targetPath = url.path
|
|
|
|
|
self.targetName = url.lastPathComponent
|
2026-02-15 20:07:12 +00:00
|
|
|
let watchedDirPath = self.watchedDir.path
|
|
|
|
|
let targetPath = self.targetPath
|
|
|
|
|
let targetName = self.targetName
|
2026-03-02 11:32:04 +00:00
|
|
|
self.watcher = SimpleFileWatcher(CoalescingFSEventsWatcher(
|
2026-02-15 20:07:12 +00:00
|
|
|
paths: [watchedDirPath],
|
|
|
|
|
queueLabel: "ai.openclaw.configwatcher",
|
|
|
|
|
shouldNotify: { _, eventPaths in
|
|
|
|
|
guard let eventPaths else { return true }
|
|
|
|
|
let paths = unsafeBitCast(eventPaths, to: NSArray.self)
|
|
|
|
|
for case let path as String in paths {
|
|
|
|
|
if path == targetPath { return true }
|
|
|
|
|
if path.hasSuffix("/\(targetName)") { return true }
|
|
|
|
|
if path == watchedDirPath { return true }
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
},
|
2026-03-02 11:32:04 +00:00
|
|
|
onChange: onChange))
|
2026-01-27 14:12:17 -06:00
|
|
|
}
|
|
|
|
|
}
|