diff --git a/src/core/message.cpp b/src/core/message.cpp index e65708ce6..18e897e88 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -97,7 +97,41 @@ Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) { *result = true; } - return message; + return message; +} + +QDataStream& operator<<(QDataStream& out, const Message& myObj) { + out << myObj.m_accountId + << myObj.m_customHash + << myObj.m_customId + << myObj.m_feedId + << myObj.m_id + << myObj.m_isImportant + << myObj.m_isRead; + + return out; +} + +QDataStream& operator>>(QDataStream& in, Message& myObj) { + int accountId; + QString customHash; + QString customId; + QString feedId; + int id; + bool isImportant; + bool isRead; + + in >> accountId >> customHash >> customId >> feedId >> id >> isImportant >> isRead; + + myObj.m_accountId = accountId; + myObj.m_customHash = customHash; + myObj.m_customId = customId; + myObj.m_feedId = feedId; + myObj.m_id = id; + myObj.m_isImportant = isImportant; + myObj.m_isRead = isRead; + + return in; } uint qHash(Message key, uint seed) { diff --git a/src/core/message.h b/src/core/message.h index 459b77e5b..d65084afa 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -23,6 +23,7 @@ #include #include #include +#include // Represents single enclosure. @@ -79,6 +80,11 @@ class Message { } }; +// Serialize message state. +// NOTE: This is used for persistent caching of message state changes. +QDataStream& operator<<(QDataStream& out, const Message& myObj); +QDataStream& operator>>(QDataStream& in, Message& myObj); + uint qHash(Message key, uint seed); uint qHash(const Message& key); diff --git a/src/miscellaneous/feedreader.cpp b/src/miscellaneous/feedreader.cpp index ecf64c1fe..fa86c2dd1 100755 --- a/src/miscellaneous/feedreader.cpp +++ b/src/miscellaneous/feedreader.cpp @@ -83,14 +83,17 @@ void FeedReader::updateFeeds(const QList& feeds) { if (m_feedDownloader == nullptr) { m_feedDownloader = new FeedDownloader(); m_feedDownloaderThread = new QThread(); + // Downloader setup. qRegisterMetaType>("QList"); m_feedDownloader->moveToThread(m_feedDownloaderThread); - connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater); + + connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater); connect(m_feedDownloader, &FeedDownloader::updateFinished, this, &FeedReader::feedUpdatesFinished); connect(m_feedDownloader, &FeedDownloader::updateProgress, this, &FeedReader::feedUpdatesProgress); connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted); connect(m_feedDownloader, &FeedDownloader::updateFinished, qApp->feedUpdateLock(), &Mutex::unlock); + // Connections are made, start the feed downloader thread. m_feedDownloaderThread->start(); } @@ -149,10 +152,12 @@ DatabaseCleaner* FeedReader::databaseCleaner() { if (m_dbCleaner == nullptr) { m_dbCleaner = new DatabaseCleaner(); m_dbCleanerThread = new QThread(); + // Downloader setup. qRegisterMetaType("CleanerOrders"); m_dbCleaner->moveToThread(m_dbCleanerThread); connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater())); + // Connections are made, start the feed downloader thread. m_dbCleanerThread->start(); } @@ -211,8 +216,8 @@ void FeedReader::checkServicesForAsyncOperations() { checkServicesForAsyncOperations(false); } -void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { - if (m_cacheSaveFutureWatcher->future().isRunning()) { +void FeedReader::checkServicesForAsyncOperations(bool wait_for_future, bool do_on_this_thread) { + if (!do_on_this_thread && m_cacheSaveFutureWatcher->future().isRunning()) { qDebug("Previous future is still running."); // If we want to wait for future synchronously, we want to make sure that @@ -223,25 +228,34 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { } else { qWarning("Some cached service data are being saved now, so aborting this saving cycle."); - // Some cache saving is now running. + + // Some cache saving is now running. return; } } - QFuture future = QtConcurrent::run([&] { - foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) { - // Store any cached data. - service->saveAllCachedData(); - } - }); + if (do_on_this_thread) { + foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) { + // Store any cached data. + service->saveAllCachedData(); + } + } + else { + QFuture future = QtConcurrent::run([&] { + foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) { + // Store any cached data. + service->saveAllCachedData(); + } + }); - if (wait_for_future) { - qDebug("Waiting for saving of cached service data to finish."); - future.waitForFinished(); - } - else { - m_cacheSaveFutureWatcher->setFuture(future); - } + if (wait_for_future) { + qDebug("Waiting for saving of cached service data to finish."); + future.waitForFinished(); + } + else { + m_cacheSaveFutureWatcher->setFuture(future); + } + } } void FeedReader::asyncCacheSaveFinished() { @@ -257,9 +271,9 @@ void FeedReader::quit() { m_autoUpdateTimer->stop(); } - checkServicesForAsyncOperations(true); + checkServicesForAsyncOperations(false, true); - // Close worker threads. + // Close worker threads. if (m_feedDownloaderThread != nullptr && m_feedDownloaderThread->isRunning()) { m_feedDownloader->stopRunningUpdate(); diff --git a/src/miscellaneous/feedreader.h b/src/miscellaneous/feedreader.h index 77ea6756c..30a2578e0 100755 --- a/src/miscellaneous/feedreader.h +++ b/src/miscellaneous/feedreader.h @@ -79,7 +79,7 @@ class FeedReader : public QObject { // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); void checkServicesForAsyncOperations(); - void checkServicesForAsyncOperations(bool wait_for_future); + void checkServicesForAsyncOperations(bool wait_for_future, bool do_on_this_thread = false); void asyncCacheSaveFinished(); signals: diff --git a/src/services/abstract/cacheforserviceroot.cpp b/src/services/abstract/cacheforserviceroot.cpp index 57d29b802..ea29eccf4 100755 --- a/src/services/abstract/cacheforserviceroot.cpp +++ b/src/services/abstract/cacheforserviceroot.cpp @@ -17,9 +17,11 @@ #include "services/abstract/cacheforserviceroot.h" +#include "miscellaneous/application.h" #include "miscellaneous/mutex.h" #include +#include CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new Mutex(QMutex::NonRecursive, nullptr)), @@ -77,10 +79,24 @@ void CacheForServiceRoot::saveCacheToFile(int accId) { m_cacheSaveMutex->lock(); // Save to file. + const QString file_cache = qApp->userDataPath() + QDir::separator() + QString::number(accId) + "-cached-msgs.dat"; + if (isEmpty()) { + QFile::remove(file_cache); + } + else { + QFile file(file_cache); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QDataStream stream(&file); + stream << m_cachedStatesImportant << m_cachedStatesRead; + file.flush(); + file.close(); + } + + clearCache(); + } - clearCache(); m_cacheSaveMutex->unlock(); } @@ -94,6 +110,22 @@ void CacheForServiceRoot::loadCacheFromFile(int accId) { clearCache(); // Load from file. + const QString file_cache = qApp->userDataPath() + QDir::separator() + QString::number(accId) + "-cached-msgs.dat"; + + QFile file(file_cache); + + if (file.exists()) { + if (file.open(QIODevice::ReadOnly)) { + QDataStream stream(&file); + stream >> m_cachedStatesImportant >> m_cachedStatesRead; + file.flush(); + file.close(); + } + + file.remove(); + } + + // TODO: TODO m_cacheSaveMutex->unlock(); } @@ -101,7 +133,7 @@ void CacheForServiceRoot::loadCacheFromFile(int accId) { QPair, QMap>> CacheForServiceRoot::takeMessageCache() { m_cacheSaveMutex->lock(); - if (m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty()) { + if (isEmpty()) { // No cached changes. m_cacheSaveMutex->unlock(); @@ -118,5 +150,9 @@ QPair, QMapunlock(); - return QPair, QMap>>(cached_data_read, cached_data_imp); + return QPair, QMap>>(cached_data_read, cached_data_imp); +} + +bool CacheForServiceRoot::isEmpty() const { + return m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty(); } diff --git a/src/services/abstract/cacheforserviceroot.h b/src/services/abstract/cacheforserviceroot.h index 74034abc2..4320af252 100755 --- a/src/services/abstract/cacheforserviceroot.h +++ b/src/services/abstract/cacheforserviceroot.h @@ -46,6 +46,10 @@ class CacheForServiceRoot { Mutex* m_cacheSaveMutex; QMap m_cachedStatesRead; QMap> m_cachedStatesImportant; + + private: + bool isEmpty() const; + void clearCache(); }; #endif // CACHEFORSERVICEROOT_H diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index dd87a0656..e3f3c0ae8 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -473,3 +473,33 @@ bool RootItem::removeChild(int index) { return false; } } + +QDataStream& operator>>(QDataStream& in, RootItem::ReadStatus& myObj) { + int obj; + in >> obj; + + myObj = (RootItem::ReadStatus)obj; + + return in; +} + +QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj) { + out << (int)myObj; + + return out; +} + +QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj) { + int obj; + in >> obj; + + myObj = (RootItem::Importance)obj; + + return in; +} + +QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj) { + out << (int)myObj; + + return out; +} diff --git a/src/services/abstract/rootitem.h b/src/services/abstract/rootitem.h index 0a6532df8..933c989df 100755 --- a/src/services/abstract/rootitem.h +++ b/src/services/abstract/rootitem.h @@ -236,4 +236,12 @@ class RootItem : public QObject { RootItem* m_parentItem; }; +QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj); + +QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj); + +QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj); + +QDataStream& operator>>(QDataStream& in, RootItem::ReadStatus& myObj); + #endif // ROOTITEM_H diff --git a/src/services/owncloud/owncloudserviceroot.cpp b/src/services/owncloud/owncloudserviceroot.cpp index 0cb2a9ca4..746e037a7 100755 --- a/src/services/owncloud/owncloudserviceroot.cpp +++ b/src/services/owncloud/owncloudserviceroot.cpp @@ -92,6 +92,7 @@ RecycleBin* OwnCloudServiceRoot::recycleBin() const { void OwnCloudServiceRoot::start(bool freshly_activated) { Q_UNUSED(freshly_activated) loadFromDatabase(); + //loadCacheFromFile(accountId()); if (qApp->isFirstRun(QSL("3.1.1")) || (childCount() == 1 && child(0)->kind() == RootItemKind::Bin)) { syncIn(); @@ -99,6 +100,7 @@ void OwnCloudServiceRoot::start(bool freshly_activated) { } void OwnCloudServiceRoot::stop() { + //saveCacheToFile(accountId()); } QString OwnCloudServiceRoot::code() const {