diff options
author | Javier S. Pedro <maemo@javispedro.com> | 2013-04-01 15:04:58 +0200 |
---|---|---|
committer | Javier S. Pedro <maemo@javispedro.com> | 2013-04-01 15:04:58 +0200 |
commit | 5ef8b38e55c1883224fe1f01f47aba45b7b42666 (patch) | |
tree | 67a873c6a7c5263d202793314c3b3a61543fbb40 /board.cpp | |
download | tapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.tar.gz tapasboard-5ef8b38e55c1883224fe1f01f47aba45b7b42666.zip |
initial import
Diffstat (limited to 'board.cpp')
-rw-r--r-- | board.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/board.cpp b/board.cpp new file mode 100644 index 0000000..887b3c6 --- /dev/null +++ b/board.cpp @@ -0,0 +1,220 @@ +#include <QtCore/QRegExp> +#include <QtCore/QDateTime> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtSql/QSqlQuery> +#include <QtSql/QSqlError> + +#include "global.h" +#include "action.h" +#include "fetchboardconfigaction.h" +#include "fetchforumsaction.h" +#include "xmlrpcinterface.h" +#include "board.h" + +Board::Board(const QString& forumUrl, QObject *parent) : + QObject(parent), _url(forumUrl), _slug(createSlug(forumUrl)), + _db(QSqlDatabase::addDatabase("QSQLITE", _slug)), + _iface(new XmlRpcInterface(QUrl(_url), this)) +{ + _db.setDatabaseName(QDir::toNativeSeparators(getDbPathFor(_slug))); + qDebug() << "Opening database file" << _db.databaseName() << "for" << _url; + if (!_db.open()) { + qWarning() << "Could not open database file" << _db.databaseName() << ":" + << _db.lastError().text(); + } + initializeDb(); + fetchConfigIfOutdated(); + fetchForumsIfOutdated(); +} + +void Board::enqueueAction(Action *action) +{ + connect(action, SIGNAL(finished(Action*)), SLOT(handleActionFinished(Action*))); + connect(action, SIGNAL(error(Action*,QString)), SLOT(handleActionError(Action*,QString))); + + _queue.enqueue(action); + + if (_queue.size() == 1) { + // There were no actions queued, so start by executing this one. + executeActionFromQueue(); + } +} + +QString Board::getConfig(const QString &key) const +{ + QSqlQuery query(_db); + query.prepare("SELECT key, value FROM config WHERE key = :key"); + query.bindValue(":key", key); + if (!query.exec()) { + qWarning() << "Could not get configuration key:" << key; + return QString(); + } + if (query.next()) { + return query.value(1).toString(); + } + return QString(); +} + +void Board::setConfig(const QString &key, const QString &value) +{ + QSqlQuery query(_db); + query.prepare("INSERT OR REPLACE INTO config (key, value) VALUES (:key, :value)"); + query.bindValue(":key", key); + query.bindValue(":value", value); + if (!query.exec()) { + qWarning() << "Could not set configuration key" << key << ":" << query.lastError().text(); + } + notifyConfigChanged(); +} + +int Board::rootForumId() const +{ + QSqlQuery query(_db); + query.exec("SELECT forum_id FROM forums WHERE parent_id = -1"); + if (query.next()) { + return query.value(0).toInt(); + } else { + return -1; + } +} + +void Board::notifyConfigChanged() +{ + emit configChanged(); +} + +void Board::notifyForumsChanged() +{ + emit forumsChanged(); +} + +void Board::notifyForumTopicsChanged(int forumId, int start, int end) +{ + qDebug() << "ForumTopics Changed" << forumId << start << end; + emit forumTopicsChanged(forumId, start, end); +} + +QString Board::createSlug(const QString &forumUrl) +{ + static const QRegExp regexp("[^a-z0-9]+"); + QString url = forumUrl.toLower(); + url.replace(regexp, "_"); + return url; +} + +QString Board::getDbDir() +{ + QString path; + +#ifdef Q_OS_LINUX + char * xdg_cache_dir = getenv("XDG_CACHE_HOME"); + if (xdg_cache_dir) { + path = QString::fromLocal8Bit(xdg_cache_dir) + "/tapasboard"; + } else { + path = QDir::homePath() + "/.cache/tapasboard"; + } + if (!QDir().mkpath(path)) { + qWarning() << "Failed to create directory for databases:" << path; + } +#endif + + return path; +} + +QString Board::getDbPathFor(const QString &slug) +{ + return getDbDir() + "/" + slug + ".sqlite"; +} + +bool Board::initializeDb() +{ + QSqlQuery q(_db); + if (!q.exec("CREATE TABLE IF NOT EXISTS config (key TEXT PRIMARY KEY, value TEXT)")) { + qWarning() << "Could not create config table:" << q.lastError().text(); + return false; + } + + if (!q.exec("CREATE TABLE IF NOT EXISTS forums (forum_id INTEGER PRIMARY KEY, forum_name TEXT, description TEXT, parent_id INT, logo_url TEXT, new_post BOOL, is_protected BOOL, is_subscribed BOOL, can_subscribe BOOL, url TEXT, sub_only BOOL, sort_index INT UNIQUE)")) { + qWarning() << "Could not create forums table:" << q.lastError().text(); + return false; + } + if (!q.exec("CREATE INDEX IF NOT EXISTS forums_parent ON forums (parent_id)")) { + qWarning() << "Could not create forums table:" << q.lastError().text(); + return false; + } + + if (!q.exec("CREATE TABLE IF NOT EXISTS topics (forum_id INTEGER, topic_id INTEGER PRIMARY KEY, topic_title TEXT, topic_author_id INTEGER, topic_author_name TEXT, is_subscribed BOOL, is_closed BOOL, icon_url TEXT, last_reply_time TEXT, new_post BOOL, last_update_time TEXT)")) { + qWarning() << "Could not create topics table:" << q.lastError().text(); + return false; + } + if (!q.exec("CREATE INDEX IF NOT EXISTS topics_forum ON topics (forum_id)")) { + qWarning() << "Could not create topics_forum index:" << q.lastError().text(); + return false; + } + if (!q.exec("CREATE INDEX IF NOT EXISTS topics_time ON topics (last_reply_time)")) { + qWarning() << "Could not create topics_time index:" << q.lastError().text(); + return false; + } + + return true; +} + +bool Board::removeFromActionQueue(Action *action) +{ + if (_queue.isEmpty()) return false; + Action *head = _queue.head(); + if (_queue.removeOne(action)) { + if (!_queue.isEmpty() && head != _queue.head()) { + // The head action was removed; advance the queue. + executeActionFromQueue(); + } + action->deleteLater(); + return true; + } + return false; +} + +void Board::executeActionFromQueue() +{ + if (!_queue.empty()) { + Action *head = _queue.head(); + head->execute(); + } +} + +void Board::fetchConfigIfOutdated() +{ + if (_iface->isAccessible()) { + // Only fetch if network is accessible and data is >48h old. + QDateTime last_fetch = QDateTime::fromString( + getConfig("last_config_fetch"), Qt::ISODate); + if (!last_fetch.isValid() || last_fetch.daysTo(QDateTime::currentDateTimeUtc()) >= BOARD_CONFIG_TTL) { + enqueueAction(new FetchBoardConfigAction(this)); + } + } + +} + +void Board::fetchForumsIfOutdated() +{ + if (_iface->isAccessible()) { + // Only fetch if network is accessible and data is >48h old. + QDateTime last_fetch = QDateTime::fromString( + getConfig("last_forums_fetch"), Qt::ISODate); + if (!last_fetch.isValid() || last_fetch.daysTo(QDateTime::currentDateTimeUtc()) >= BOARD_LIST_TTL) { + enqueueAction(new FetchForumsAction(this)); + } + } +} + +void Board::handleActionFinished(Action *action) +{ + removeFromActionQueue(action); +} + +void Board::handleActionError(Action *action, const QString& message) +{ + qWarning() << "Action failed:" << message; + removeFromActionQueue(action); +} |