From 0ba41e7f4fa79f13a018df8b0fbe57d124491d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix?= Date: Fri, 5 May 2017 20:18:38 -0300 Subject: [PATCH] Added deferring behavior --- Sources/fswatcher.swift | 67 +++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/Sources/fswatcher.swift b/Sources/fswatcher.swift index 90614bf..db5e07b 100644 --- a/Sources/fswatcher.swift +++ b/Sources/fswatcher.swift @@ -1,4 +1,5 @@ import Dispatch +import Foundation import inotify public typealias FileDescriptor = Int @@ -60,7 +61,9 @@ public class FileSystemWatcher { private var watchDescriptors: [WatchDescriptor] private var shouldStopWatching: Bool = false - public init() { + private let deferringDelay : Double + + public init(deferringDelay : Double = 2.0) { dispatchQueue = DispatchQueue(label: "inotify.queue", qos: .background, attributes: [.initiallyInactive, .concurrent]) fileDescriptor = FileDescriptor(inotify_init()) @@ -69,6 +72,8 @@ public class FileSystemWatcher { } watchDescriptors = [WatchDescriptor]() + + self.deferringDelay = deferringDelay } public func start() { @@ -100,37 +105,59 @@ public class FileSystemWatcher { watchDescriptors.append(WatchDescriptor(watchDescriptor)) wds.append(WatchDescriptor(watchDescriptor)) + // For deferred execution + var lastTimeStamp = Date() + dispatchQueue.async { let bufferLength = 32 let buffer = UnsafeMutablePointer.allocate(capacity: bufferLength) - while !self.shouldStopWatching { - var currentIndex: Int = 0 - let readLength = read(Int32(self.fileDescriptor), buffer, bufferLength) + var fileSystemEvent : FileSystemEvent? - while currentIndex < readLength { - let event = withUnsafePointer(to: &buffer[currentIndex]) { - return $0.withMemoryRebound(to: inotify_event.self, capacity: 1) { - return $0.pointee + while !self.shouldStopWatching { + // IF it's been more than 2 seconds since the last callback, + // run the callback again. + if(lastTimeStamp.timeIntervalSinceNow < -self.deferringDelay) { + lastTimeStamp = Date() + + // This checks if there exists an event + // before sending it. It's very important, + // because it makes the first run possible. + if let lastEvent = fileSystemEvent { + self.dispatchQueue.asyncAfter(deadline: .now() + self.deferringDelay) { + callback(lastEvent) } } + } + // IF NOT, then we defer the events until enough time passes + // for the callback window to open again + else { + var currentIndex: Int = 0 + let readLength = read(Int32(self.fileDescriptor), buffer, bufferLength) + + while currentIndex < readLength { + let event = withUnsafePointer(to: &buffer[currentIndex]) { + return $0.withMemoryRebound(to: inotify_event.self, capacity: 1) { + return $0.pointee + } + } - if event.len > 0 { - let fileSystemEvent = FileSystemEvent( - watchDescriptor: WatchDescriptor(event.wd), - name: "", // String(cString: event.name), // value of type 'inotify_event' has no member 'name' - mask: event.mask, - cookie: event.cookie, - length: event.len - ) - - self.dispatchQueue.async { - callback(fileSystemEvent) + if event.len > 0 { + fileSystemEvent = FileSystemEvent( + watchDescriptor: WatchDescriptor(event.wd), + name: "", // String(cString: event.name), // value of type 'inotify_event' has no member 'name' + mask: event.mask, + cookie: event.cookie, + length: event.len + ) } + + currentIndex += MemoryLayout.stride + Int(event.len) } - currentIndex += MemoryLayout.stride + Int(event.len) } + + } } }