Working on safer msg downloading/saving.
This commit is contained in:
parent
a259cba741
commit
d9311ae5d2
10 changed files with 44 additions and 64 deletions
|
@ -27,12 +27,14 @@
|
|||
|
||||
|
||||
FeedDownloader::FeedDownloader(QObject *parent)
|
||||
: QObject(parent), m_results(FeedDownloadResults()), m_feedsUpdated(0), m_feedsToUpdate(0),
|
||||
: QObject(parent), m_results(FeedDownloadResults()), m_msgUpdateMutex(new QMutex()), m_feedsUpdated(0), m_feedsToUpdate(0),
|
||||
m_feedsUpdating(0), m_feedsTotalCount(0), m_stopUpdate(false) {
|
||||
qRegisterMetaType<FeedDownloadResults>("FeedDownloadResults");
|
||||
}
|
||||
|
||||
FeedDownloader::~FeedDownloader() {
|
||||
m_msgUpdateMutex->unlock();
|
||||
delete m_msgUpdateMutex;
|
||||
qDebug("Destroying FeedDownloader instance.");
|
||||
}
|
||||
|
||||
|
@ -79,7 +81,7 @@ void FeedDownloader::updateFeeds(const QList<Feed*> &feeds) {
|
|||
break;
|
||||
}
|
||||
|
||||
connect(feeds.at(i), SIGNAL(updated(int)), this, SLOT(oneFeedUpdateFinished(int)),
|
||||
connect(feeds.at(i), &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished,
|
||||
(Qt::ConnectionType) (Qt::UniqueConnection | Qt::AutoConnection));
|
||||
QThreadPool::globalInstance()->start(feeds.at(i));
|
||||
|
||||
|
@ -92,14 +94,24 @@ void FeedDownloader::stopRunningUpdate() {
|
|||
m_stopUpdate = true;
|
||||
}
|
||||
|
||||
void FeedDownloader::oneFeedUpdateFinished(int updated_messages) {
|
||||
const Feed *feed = qobject_cast<Feed*>(sender());
|
||||
void FeedDownloader::oneFeedUpdateFinished(const QList<Message> &messages) {
|
||||
Feed *feed = qobject_cast<Feed*>(sender());
|
||||
|
||||
disconnect(feed, SIGNAL(updated(int)), this, SLOT(oneFeedUpdateFinished(int)));
|
||||
disconnect(feed, &Feed::messagesObtained, this, &FeedDownloader::oneFeedUpdateFinished);
|
||||
|
||||
m_feedsUpdated++;
|
||||
m_feedsUpdating--;
|
||||
|
||||
// Now make sure, that messages are actually stored to SQL in a locked state.
|
||||
|
||||
qDebug().nospace() << "Saving messages of feed "
|
||||
<< feed->customId() << " in thread: \'"
|
||||
<< QThread::currentThreadId() << "\'.";
|
||||
|
||||
m_msgUpdateMutex->lock();
|
||||
int updated_messages = messages.isEmpty() ? 0 : feed->updateMessages(messages);
|
||||
m_msgUpdateMutex->unlock();
|
||||
|
||||
if (updated_messages > 0) {
|
||||
m_results.appendUpdatedFeed(QPair<QString,int>(feed->title(), updated_messages));
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <QPair>
|
||||
|
||||
#include "core/message.h"
|
||||
|
||||
|
||||
class Feed;
|
||||
|
||||
|
@ -70,7 +72,7 @@ class FeedDownloader : public QObject {
|
|||
void stopRunningUpdate();
|
||||
|
||||
private slots:
|
||||
void oneFeedUpdateFinished(int updated_messages);
|
||||
void oneFeedUpdateFinished(const QList<Message> &messages);
|
||||
|
||||
signals:
|
||||
// Emitted if feed updates started.
|
||||
|
@ -90,6 +92,7 @@ class FeedDownloader : public QObject {
|
|||
void finalizeUpdate();
|
||||
|
||||
FeedDownloadResults m_results;
|
||||
QMutex *m_msgUpdateMutex;
|
||||
|
||||
int m_feedsUpdated;
|
||||
int m_feedsToUpdate;
|
||||
|
|
|
@ -47,9 +47,7 @@ int main(int argc, char *argv[]) {
|
|||
QObject::tr("LANG_AUTHOR");
|
||||
|
||||
// Ensure that ini format is used as application settings storage on Mac OS.
|
||||
#ifdef Q_OS_MAC
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
#endif
|
||||
|
||||
// Setup debug output system.
|
||||
qInstallMessageHandler(Debugging::debugHandler);
|
||||
|
@ -65,6 +63,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
// Register needed metatypes.
|
||||
qRegisterMetaType<QList<Message> >("QList<Message>");
|
||||
qRegisterMetaType<QList<RootItem*> >("QList<RootItem*>");
|
||||
|
||||
// Add an extra path for non-system icon themes and set current icon theme
|
||||
|
@ -114,7 +113,7 @@ int main(int argc, char *argv[]) {
|
|||
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadAllExpandStates();
|
||||
|
||||
// Setup single-instance behavior.
|
||||
QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString)));
|
||||
QObject::connect(&application, &Application::messageReceived, &application, &Application::processExecutionMessage);
|
||||
|
||||
if (qApp->isFirstRun() || qApp->isFirstRun(APP_VERSION)) {
|
||||
qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.\n\nPlease, check NEW stuff included in this\n"
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
Application::Application(const QString &id, int &argc, char **argv)
|
||||
: QtSingleApplication(id, argc, argv),
|
||||
m_updateFeedsLock(nullptr), m_updateMessagesLock(nullptr), m_feedServices(QList<ServiceEntryPoint*>()), m_userActions(QList<QAction*>()), m_mainForm(nullptr),
|
||||
m_updateFeedsLock(nullptr), m_feedServices(QList<ServiceEntryPoint*>()), m_userActions(QList<QAction*>()), m_mainForm(nullptr),
|
||||
m_trayIcon(nullptr), m_settings(nullptr), m_system(nullptr), m_skins(nullptr),
|
||||
m_localization(nullptr), m_icons(nullptr), m_database(nullptr), m_downloadManager(nullptr) {
|
||||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
|
||||
|
@ -127,16 +127,6 @@ Mutex *Application::feedUpdateLock() {
|
|||
return m_updateFeedsLock.data();
|
||||
}
|
||||
|
||||
Mutex *Application::messageUpdateLock() {
|
||||
if (m_updateMessagesLock.isNull()) {
|
||||
// NOTE: Cannot use parent hierarchy because this method can be usually called
|
||||
// from any thread.
|
||||
m_updateMessagesLock.reset(new Mutex());
|
||||
}
|
||||
|
||||
return m_updateMessagesLock.data();
|
||||
}
|
||||
|
||||
void Application::backupDatabaseSettings(bool backup_database, bool backup_settings,
|
||||
const QString &target_path, const QString &backup_name) {
|
||||
if (!QFileInfo(target_path).isWritable()) {
|
||||
|
|
|
@ -113,7 +113,6 @@ class Application : public QtSingleApplication {
|
|||
|
||||
// Access to application-wide close lock.
|
||||
Mutex *feedUpdateLock();
|
||||
Mutex *messageUpdateLock();
|
||||
|
||||
inline FormMain *mainForm() {
|
||||
return m_mainForm;
|
||||
|
@ -187,7 +186,6 @@ class Application : public QtSingleApplication {
|
|||
// tries to lock the lock for writing), then no other
|
||||
// action will be allowed to lock for reading.
|
||||
QScopedPointer<Mutex> m_updateFeedsLock;
|
||||
QScopedPointer<Mutex> m_updateMessagesLock;
|
||||
|
||||
QList<ServiceEntryPoint*> m_feedServices;
|
||||
QList<QAction*> m_userActions;
|
||||
|
|
|
@ -101,7 +101,9 @@ void IconFactory::loadCurrentIconTheme() {
|
|||
|
||||
// Display list of installed themes.
|
||||
qDebug("Installed icon themes are: %s.",
|
||||
qPrintable(QStringList(installed_themes).replaceInStrings(QRegExp(QSL("^|$")), QSL("\'")).join(QSL(", "))));
|
||||
qPrintable(QStringList(installed_themes)
|
||||
.replaceInStrings(QRegExp(QSL("^|$")), QSL("\'"))
|
||||
.replaceInStrings(QRegExp(QSL("^\\'$")), QSL("\'\'")).join(QSL(", "))));
|
||||
|
||||
if (installed_themes.contains(theme_name_from_settings)) {
|
||||
// Desired icon theme is installed and can be loaded.
|
||||
|
@ -111,7 +113,7 @@ void IconFactory::loadCurrentIconTheme() {
|
|||
else {
|
||||
// Desired icon theme is not currently available.
|
||||
// Install "default" icon theme instead.
|
||||
qDebug("Icon theme '%s' cannot be loaded because it is not installed. No icon theme (or default icon theme) is loaded now.",
|
||||
qWarning("Icon theme '%s' cannot be loaded because it is not installed. No icon theme (or default icon theme) is loaded now.",
|
||||
qPrintable(theme_name_from_settings));
|
||||
QIcon::setThemeName(APP_NO_THEME);
|
||||
}
|
||||
|
|
|
@ -44,11 +44,13 @@ void Localization::loadActiveLanguage() {
|
|||
qDebug("Starting to load active localization. Desired localization is '%s'.", qPrintable(desired_localization));
|
||||
|
||||
if (app_translator->load(QLocale(desired_localization), "rssguard", QSL("-"), APP_LANG_PATH)) {
|
||||
const QString real_loaded_locale = app_translator->translate("QObject", "LANG_ABBREV");
|
||||
|
||||
Application::installTranslator(app_translator);
|
||||
qDebug("Application localization '%s' loaded successfully, specifically sublocalization '%s' was loaded.",
|
||||
qPrintable(desired_localization),
|
||||
qPrintable(app_translator->translate("QObject", "LANG_ABBREV")));
|
||||
desired_localization = app_translator->translate("QObject", "LANG_ABBREV");
|
||||
qPrintable(real_loaded_locale));
|
||||
desired_localization = real_loaded_locale;
|
||||
}
|
||||
else {
|
||||
qWarning("Application localization '%s' was not loaded. Loading '%s' instead.",
|
||||
|
|
|
@ -59,7 +59,7 @@ void SkinFactory::loadCurrentSkin() {
|
|||
}
|
||||
}
|
||||
|
||||
qFatal("Failed to load selected or default skin(s). Quitting!");
|
||||
qFatal("Failed to load selected or default skin. Quitting!");
|
||||
}
|
||||
|
||||
void SkinFactory::loadSkinFromData(const Skin &skin) {
|
||||
|
|
|
@ -88,17 +88,6 @@ void Feed::setCountOfUnreadMessages(int count_unread_messages) {
|
|||
m_unreadCount = count_unread_messages;
|
||||
}
|
||||
|
||||
int Feed::update() {
|
||||
QList<Message> msgs = obtainNewMessages();
|
||||
|
||||
if (msgs.size() > 0) {
|
||||
return updateMessages(msgs);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::setAutoUpdateInitialInterval(int auto_update_interval) {
|
||||
// If new initial auto-update interval is set, then
|
||||
// we should reset time that remains to the next auto-update.
|
||||
|
@ -134,9 +123,13 @@ void Feed::updateCounts(bool including_total_count) {
|
|||
}
|
||||
|
||||
void Feed::run() {
|
||||
qDebug().nospace() << "Updating feed " << customId() << " in thread: \'" << QThread::currentThreadId() << "\'.";
|
||||
qDebug().nospace() << "Downloading new messages for feed "
|
||||
<< customId() << " in thread: \'"
|
||||
<< QThread::currentThreadId() << "\'.";
|
||||
|
||||
emit updated(update());
|
||||
QList<Message> msgs = obtainNewMessages();
|
||||
|
||||
emit messagesObtained(msgs);
|
||||
}
|
||||
|
||||
int Feed::updateMessages(const QList<Message> &messages) {
|
||||
|
@ -144,13 +137,6 @@ int Feed::updateMessages(const QList<Message> &messages) {
|
|||
int account_id = getParentServiceRoot()->accountId();
|
||||
bool anything_updated = false;
|
||||
bool ok;
|
||||
|
||||
// MySQL seems to be more error prone with transactions when called
|
||||
// from more threads in the same time. SQLite does not have that limitation.
|
||||
if (qApp->database()->activeDatabaseDriver() == DatabaseFactory::MYSQL) {
|
||||
qApp->messageUpdateLock()->lock();
|
||||
}
|
||||
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
int updated_messages = DatabaseQueries::updateMessages(database, messages, custom_id, account_id, url(),
|
||||
&anything_updated, &ok);
|
||||
|
@ -176,9 +162,5 @@ int Feed::updateMessages(const QList<Message> &messages) {
|
|||
getParentServiceRoot()->itemChanged(items_to_update);
|
||||
}
|
||||
|
||||
if (qApp->database()->activeDatabaseDriver() == DatabaseFactory::MYSQL) {
|
||||
qApp->messageUpdateLock()->unlock();
|
||||
}
|
||||
|
||||
return updated_messages;
|
||||
}
|
||||
|
|
|
@ -61,13 +61,6 @@ class Feed : public RootItem, public QRunnable {
|
|||
void setCountOfAllMessages(int count_all_messages);
|
||||
void setCountOfUnreadMessages(int count_unread_messages);
|
||||
|
||||
// Performs synchronous update and returns number of newly updated messages.
|
||||
// NOTE: This is called from worker thread, not from main UI thread.
|
||||
// NOTE: This should COMPLETELY download ALL messages from online source
|
||||
// into locale "Messages" table, INCLUDING contents (or excerpts) of those
|
||||
// messages.
|
||||
int update();
|
||||
|
||||
QVariant data(int column, int role) const;
|
||||
|
||||
int autoUpdateInitialInterval() const;
|
||||
|
@ -95,19 +88,18 @@ class Feed : public RootItem, public QRunnable {
|
|||
m_url = url;
|
||||
}
|
||||
|
||||
int updateMessages(const QList<Message> &messages);
|
||||
void updateCounts(bool including_total_count);
|
||||
|
||||
// Runs update in thread (thread pooled).
|
||||
void run();
|
||||
|
||||
protected:
|
||||
private:
|
||||
// Performs synchronous obtaining of new messages for this feed.
|
||||
virtual QList<Message> obtainNewMessages() = 0;
|
||||
|
||||
private:
|
||||
int updateMessages(const QList<Message> &messages);
|
||||
|
||||
signals:
|
||||
void updated(int updated_messages);
|
||||
void messagesObtained(QList<Message> messages);
|
||||
|
||||
private:
|
||||
QString m_url;
|
||||
|
|
Loading…
Add table
Reference in a new issue