diff options
Diffstat (limited to 'src/core/FileWatcher.cpp')
-rw-r--r-- | src/core/FileWatcher.cpp | 107 |
1 files changed, 65 insertions, 42 deletions
diff --git a/src/core/FileWatcher.cpp b/src/core/FileWatcher.cpp index ae7878191..1b39e597d 100644 --- a/src/core/FileWatcher.cpp +++ b/src/core/FileWatcher.cpp @@ -19,6 +19,7 @@ #include "FileWatcher.h" #include "core/Clock.h" +#include <QCryptographicHash> #include <QFileInfo> #ifdef Q_OS_LINUX @@ -27,36 +28,23 @@ namespace { - const int FileChangeDelay = 500; - const int TimerResolution = 100; + const int FileChangeDelay = 200; } // namespace -DelayingFileWatcher::DelayingFileWatcher(QObject* parent) +FileWatcher::FileWatcher(QObject* parent) : QObject(parent) , m_ignoreFileChange(false) { - connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onWatchedFileChanged())); - connect(&m_fileUnblockTimer, SIGNAL(timeout()), this, SLOT(observeFileChanges())); - connect(&m_fileChangeDelayTimer, SIGNAL(timeout()), this, SIGNAL(fileChanged())); + connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), SLOT(onWatchedFileChanged())); + connect(&m_fileChangeDelayTimer, SIGNAL(timeout()), SIGNAL(fileChanged())); + connect(&m_fileChecksumTimer, SIGNAL(timeout()), SLOT(checkFileChecksum())); m_fileChangeDelayTimer.setSingleShot(true); - m_fileUnblockTimer.setSingleShot(true); + m_fileIgnoreDelayTimer.setSingleShot(true); } -void DelayingFileWatcher::restart() +void FileWatcher::start(const QString& filePath, int checksumInterval) { - m_fileWatcher.addPath(m_filePath); -} - -void DelayingFileWatcher::stop() -{ - m_fileWatcher.removePath(m_filePath); -} - -void DelayingFileWatcher::start(const QString& filePath) -{ - if (!m_filePath.isEmpty()) { - m_fileWatcher.removePath(m_filePath); - } + stop(); #if defined(Q_OS_LINUX) struct statfs statfsBuf; @@ -74,45 +62,80 @@ void DelayingFileWatcher::start(const QString& filePath) #endif m_fileWatcher.addPath(filePath); + m_filePath = filePath; + m_fileChecksum = calculateChecksum(); + m_fileChecksumTimer.start(checksumInterval); + m_ignoreFileChange = false; +} - if (!filePath.isEmpty()) { - m_filePath = filePath; +void FileWatcher::stop() +{ + if (!m_filePath.isEmpty()) { + m_fileWatcher.removePath(m_filePath); } + m_filePath.clear(); + m_fileChecksum.clear(); + m_fileChangeDelayTimer.stop(); } -void DelayingFileWatcher::ignoreFileChanges() +void FileWatcher::pause() { m_ignoreFileChange = true; m_fileChangeDelayTimer.stop(); } -void DelayingFileWatcher::observeFileChanges(bool delayed) +void FileWatcher::resume() { - int timeout = 0; - if (delayed) { - timeout = FileChangeDelay; - } else { - m_ignoreFileChange = false; - start(m_filePath); - } - if (timeout > 0 && !m_fileUnblockTimer.isActive()) { - m_fileUnblockTimer.start(timeout); + m_ignoreFileChange = false; + // Add a short delay to start in the next event loop + if (!m_fileIgnoreDelayTimer.isActive()) { + m_fileIgnoreDelayTimer.start(0); } } -void DelayingFileWatcher::onWatchedFileChanged() +void FileWatcher::onWatchedFileChanged() { - if (m_ignoreFileChange) { - // the client forcefully silenced us + // Don't notify if we are ignoring events or already started a notification chain + if (shouldIgnoreChanges()) { return; } - if (m_fileChangeDelayTimer.isActive()) { - // we are waiting to fire the delayed fileChanged event, so nothing - // to do here + + m_fileChecksum = calculateChecksum(); + m_fileChangeDelayTimer.start(0); +} + +bool FileWatcher::shouldIgnoreChanges() +{ + return m_filePath.isEmpty() || m_ignoreFileChange || m_fileIgnoreDelayTimer.isActive() + || m_fileChangeDelayTimer.isActive(); +} + +bool FileWatcher::hasSameFileChecksum() +{ + return calculateChecksum() == m_fileChecksum; +} + +void FileWatcher::checkFileChecksum() +{ + if (shouldIgnoreChanges()) { return; } - m_fileChangeDelayTimer.start(FileChangeDelay); + if (!hasSameFileChecksum()) { + onWatchedFileChanged(); + } +} + +QByteArray FileWatcher::calculateChecksum() +{ + QFile file(m_filePath); + if (file.open(QFile::ReadOnly)) { + QCryptographicHash hash(QCryptographicHash::Sha256); + if (hash.addData(&file)) { + return hash.result(); + } + } + return {}; } BulkFileWatcher::BulkFileWatcher(QObject* parent) @@ -281,7 +304,7 @@ void BulkFileWatcher::observeFileChanges(bool delayed) { int timeout = 0; if (delayed) { - timeout = TimerResolution; + timeout = FileChangeDelay; } else { const QDateTime current = Clock::currentDateTimeUtc(); for (const QString& key : m_watchedFilesIgnored.keys()) { |