From bb799766223a6388e476f320ad74720c802b2d83 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Fri, 13 Feb 2009 14:41:47 +0100 Subject: [PATCH] Fixes #552 - Don't try to use DBs with a too new schema version --- src/core/abstractsqlstorage.cpp | 27 +++++----- src/core/abstractsqlstorage.h | 2 +- src/core/core.cpp | 94 +++++++++++++++++++-------------- src/core/core.h | 66 +++++++++++------------ src/core/storage.h | 12 +++-- 5 files changed, 112 insertions(+), 89 deletions(-) diff --git a/src/core/abstractsqlstorage.cpp b/src/core/abstractsqlstorage.cpp index c2d5e980..7e5dee59 100644 --- a/src/core/abstractsqlstorage.cpp +++ b/src/core/abstractsqlstorage.cpp @@ -83,36 +83,39 @@ void AbstractSqlStorage::addConnectionToPool() { } } -bool AbstractSqlStorage::init(const QVariantMap &settings) { +Storage::State AbstractSqlStorage::init(const QVariantMap &settings) { Q_UNUSED(settings) + QSqlDatabase db = logDb(); if(!db.isValid() || !db.isOpen()) - return false; + return NotAvailable; if(installedSchemaVersion() == -1) { qCritical() << "Storage Schema is missing!"; - return false; + return NeedsSetup; } if(installedSchemaVersion() > schemaVersion()) { qCritical() << "Installed Schema is newer then any known Version."; - return false; + return NotAvailable; } - + if(installedSchemaVersion() < schemaVersion()) { qWarning() << qPrintable(tr("Installed Schema (version %1) is not up to date. Upgrading to version %2...").arg(installedSchemaVersion()).arg(schemaVersion())); - if(!upgradeDb()) - return false; + if(!upgradeDb()) { + qWarning() << qPrintable(tr("Upgrade failed...")); + return NotAvailable; + } } - + quInfo() << "Storage Backend is ready. Quassel Schema Version:" << installedSchemaVersion(); - return true; + return IsReady; } QString AbstractSqlStorage::queryString(const QString &queryName, int version) { if(version == 0) version = schemaVersion(); - + QFileInfo queryInfo(QString(":/SQL/%1/%2/%3.sql").arg(displayName()).arg(version).arg(queryName)); if(!queryInfo.exists() || !queryInfo.isFile() || !queryInfo.isReadable()) { qCritical() << "Unable to read SQL-Query" << queryName << "for engine" << displayName(); @@ -124,7 +127,7 @@ QString AbstractSqlStorage::queryString(const QString &queryName, int version) { return QString(); QString query = QTextStream(&queryFile).readAll(); queryFile.close(); - + return query.trimmed(); } @@ -219,7 +222,7 @@ bool AbstractSqlStorage::watchQuery(QSqlQuery &query) { qCritical() << " Error Message:" << query.lastError().text(); qCritical() << " Driver Message:" << query.lastError().driverText(); qCritical() << " DB Message:" << query.lastError().databaseText(); - + return false; } return true; diff --git a/src/core/abstractsqlstorage.h b/src/core/abstractsqlstorage.h index e3a64816..e3b4ec4c 100644 --- a/src/core/abstractsqlstorage.h +++ b/src/core/abstractsqlstorage.h @@ -35,7 +35,7 @@ public: virtual ~AbstractSqlStorage(); protected: - virtual bool init(const QVariantMap &settings = QVariantMap()); + virtual State init(const QVariantMap &settings = QVariantMap()); inline virtual void sync() {}; QSqlDatabase logDb(); diff --git a/src/core/core.cpp b/src/core/core.cpp index aa1b7d48..e1a53600 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -48,7 +48,9 @@ void Core::destroy() { instanceptr = 0; } -Core::Core() : storage(0) { +Core::Core() + : _storage(0) +{ _startTime = QDateTime::currentDateTime().toUTC(); // for uptime :) Quassel::loadTranslation(QLocale::system()); @@ -131,25 +133,23 @@ Core::Core() : storage(0) { // Register storage backends here! registerStorageBackend(new SqliteStorage(this)); - if(!_storageBackends.count()) { - qWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting...")); - qWarning() << qPrintable(tr("Currently, Quassel only supports SQLite3. You need to build your\n" - "Qt library with the sqlite plugin enabled in order for quasselcore\n" - "to work.")); - exit(1); // TODO make this less brutal (especially for mono client -> popup) - } connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage())); _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes } void Core::init() { - configured = false; - CoreSettings cs; - - if(!(configured = initStorage(cs.storageSettings().toMap()))) { + _configured = initStorage(cs.storageSettings().toMap()); + + if(!_configured) { + if(!_storageBackends.count()) { + qWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting...")); + qWarning() << qPrintable(tr("Currently, Quassel only supports SQLite3. You need to build your\n" + "Qt library with the sqlite plugin enabled in order for quasselcore\n" + "to work.")); + exit(1); // TODO make this less brutal (especially for mono client -> popup) + } qWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup."; - } connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); @@ -178,7 +178,7 @@ void Core::saveState() { } void Core::restoreState() { - if(!instance()->configured) { + if(!instance()->_configured) { // qWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!")); return; } @@ -226,13 +226,14 @@ QString Core::setupCore(QVariantMap setupData) { if(user.isEmpty() || password.isEmpty()) { return tr("Admin user or password not set."); } - if(!initStorage(setupData, true)) { + _configured = initStorage(setupData, true); + if(!_configured) { return tr("Could not setup storage!"); } CoreSettings s; s.setStorageSettings(setupData); quInfo() << qPrintable(tr("Creating admin user...")); - storage->addUser(user, password); + _storage->addUser(user, password); startListening(); // TODO check when we need this return QString(); } @@ -257,42 +258,55 @@ void Core::unregisterStorageBackend(Storage *backend) { // old db settings: // "Type" => "sqlite" bool Core::initStorage(QVariantMap dbSettings, bool setup) { + _storage = 0; + QString backend = dbSettings["Backend"].toString(); if(backend.isEmpty()) { - //qWarning() << "No storage backend selected!"; - return configured = false; + return false; } + Storage *storage = 0; if(_storageBackends.contains(backend)) { storage = _storageBackends[backend]; } else { qCritical() << "Selected storage backend is not available:" << backend; - return configured = false; + return false; } - if(!storage->init(dbSettings)) { - if(!setup || !(storage->setup(dbSettings) && storage->init(dbSettings))) { - qCritical() << "Could not init storage!"; - storage = 0; - return configured = false; + + Storage::State storageState = storage->init(dbSettings); + switch(storageState) { + case Storage::NeedsSetup: + if(!setup) + return false; // trigger setup process + if(storage->setup(dbSettings)) + return initStorage(dbSettings, false); + // if setup wasn't successfull we mark the backend as unavailable + case Storage::NotAvailable: + qCritical() << "Selected storage backend is not available:" << backend; + storage->deleteLater(); + _storageBackends.remove(backend); + storage = 0; + return false; + case Storage::IsReady: + // delete all other backends + foreach(Storage *s, _storageBackends.values()) { + if(s != storage) s->deleteLater(); } + _storageBackends.clear(); + connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &))); } - // delete all other backends - foreach(Storage *s, _storageBackends.values()) { - if(s != storage) s->deleteLater(); - } - _storageBackends.clear(); - - connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &))); - return configured = true; + _storage = storage; + return true; } void Core::syncStorage() { - if(storage) storage->sync(); + if(_storage) + _storage->sync(); } /*** Storage Access ***/ bool Core::createNetwork(UserId user, NetworkInfo &info) { - NetworkId networkId = instance()->storage->createNetwork(user, info); + NetworkId networkId = instance()->_storage->createNetwork(user, info); if(!networkId.isValid()) return false; @@ -405,7 +419,7 @@ void Core::incomingConnection() { blocksizes.insert(socket, (quint32)0); quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString()); - if(!configured) { + if(!_configured) { stopListening(tr("Closing server for basic setup.")); } } @@ -480,7 +494,7 @@ void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) { reply["LoginEnabled"] = true; // check if we are configured, start wizard otherwise - if(!configured) { + if(!_configured) { reply["Configured"] = false; QList backends; foreach(Storage *backend, _storageBackends.values()) { @@ -536,7 +550,7 @@ void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) { SignalProxy::writeDataToDevice(socket, reply); } else if(msg["MsgType"] == "ClientLogin") { QVariantMap reply; - UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); + UserId uid = _storage->validateUser(msg["User"].toString(), msg["Password"].toString()); if(uid == 0) { reply["MsgType"] = "ClientLoginReject"; reply["Error"] = tr("Invalid username or password!
The username/password combination you supplied could not be found in the database."); @@ -588,7 +602,7 @@ void Core::clientDisconnected() { // make server listen again if still not configured - if (!configured) { + if (!_configured) { startListening(); } @@ -613,12 +627,12 @@ void Core::setupClientSession(QTcpSocket *socket, UserId uid) { } void Core::setupInternalClientSession(SignalProxy *proxy) { - if(!configured) { + if(!_configured) { stopListening(); setupCoreForInternalUsage(); } - UserId uid = storage->internalUser(); + UserId uid = _storage->internalUser(); // Find or create session for validated user SessionThread *sess; diff --git a/src/core/core.h b/src/core/core.h index c0916c9b..2c1fa07d 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -65,7 +65,7 @@ class Core : public QObject { * \param data The Value */ static inline void setUserSetting(UserId userId, const QString &settingName, const QVariant &data) { - instance()->storage->setUserSetting(userId, settingName, data); + instance()->_storage->setUserSetting(userId, settingName, data); } //! Retrieve a persistent user setting @@ -76,21 +76,21 @@ class Core : public QObject { * \return the Value of the Setting or the default value if it is unset. */ static inline QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &data = QVariant()) { - return instance()->storage->getUserSetting(userId, settingName, data); + return instance()->_storage->getUserSetting(userId, settingName, data); } /* Identity handling */ static inline IdentityId createIdentity(UserId user, CoreIdentity &identity) { - return instance()->storage->createIdentity(user, identity); + return instance()->_storage->createIdentity(user, identity); } static bool updateIdentity(UserId user, const CoreIdentity &identity) { - return instance()->storage->updateIdentity(user, identity); + return instance()->_storage->updateIdentity(user, identity); } static void removeIdentity(UserId user, IdentityId identityId) { - instance()->storage->removeIdentity(user, identityId); + instance()->_storage->removeIdentity(user, identityId); } static QList identities(UserId user) { - return instance()->storage->identities(user); + return instance()->_storage->identities(user); } //! Create a Network in the Storage and store it's Id in the given NetworkInfo @@ -110,7 +110,7 @@ class Core : public QObject { * \return true if successfull. */ static inline bool updateNetwork(UserId user, const NetworkInfo &info) { - return instance()->storage->updateNetwork(user, info); + return instance()->_storage->updateNetwork(user, info); } //! Permanently remove a Network and all the data associated with it. @@ -121,7 +121,7 @@ class Core : public QObject { * \return true if successfull. */ static inline bool removeNetwork(UserId user, const NetworkId &networkId) { - return instance()->storage->removeNetwork(user, networkId); + return instance()->_storage->removeNetwork(user, networkId); } //! Returns a list of all NetworkInfos for the given UserId user @@ -131,7 +131,7 @@ class Core : public QObject { * \return QList. */ static inline QList networks(UserId user) { - return instance()->storage->networks(user); + return instance()->_storage->networks(user); } //! Get the NetworkId for a network name. @@ -142,7 +142,7 @@ class Core : public QObject { * \return The NetworkId corresponding to the given network. */ static inline NetworkId networkId(UserId user, const QString &network) { - return instance()->storage->getNetworkId(user, network); + return instance()->_storage->getNetworkId(user, network); } //! Get a list of Networks to restore @@ -152,7 +152,7 @@ class Core : public QObject { * \param user The User Id in question */ static inline QList connectedNetworks(UserId user) { - return instance()->storage->connectedNetworks(user); + return instance()->_storage->connectedNetworks(user); } //! Update the connected state of a network @@ -163,7 +163,7 @@ class Core : public QObject { * \param isConnected whether the network is connected or not */ static inline void setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected) { - return instance()->storage->setNetworkConnected(user, networkId, isConnected); + return instance()->_storage->setNetworkConnected(user, networkId, isConnected); } //! Get a hash of channels with their channel keys for a given network @@ -174,7 +174,7 @@ class Core : public QObject { * \param networkId The Id of the network */ static inline QHash persistentChannels(UserId user, const NetworkId &networkId) { - return instance()->storage->persistentChannels(user, networkId); + return instance()->_storage->persistentChannels(user, networkId); } //! Update the connected state of a channel @@ -186,7 +186,7 @@ class Core : public QObject { * \param isJoined whether the channel is connected or not */ static inline void setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined) { - return instance()->storage->setChannelPersistent(user, networkId, channel, isJoined); + return instance()->_storage->setChannelPersistent(user, networkId, channel, isJoined); } //! Update the key of a channel @@ -198,7 +198,7 @@ class Core : public QObject { * \param key The key of the channel (possibly empty) */ static inline void setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key) { - return instance()->storage->setPersistentChannelKey(user, networkId, channel, key); + return instance()->_storage->setPersistentChannelKey(user, networkId, channel, key); } //! retrieve last known away message for session restore @@ -208,7 +208,7 @@ class Core : public QObject { * \param networkId The Id of the network */ static inline QString awayMessage(UserId user, NetworkId networkId) { - return instance()->storage->awayMessage(user, networkId); + return instance()->_storage->awayMessage(user, networkId); } //! Make away message persistent for session restore @@ -219,7 +219,7 @@ class Core : public QObject { * \param awayMsg The current away message of own user */ static inline void setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg) { - return instance()->storage->setAwayMessage(user, networkId, awayMsg); + return instance()->_storage->setAwayMessage(user, networkId, awayMsg); } //! retrieve last known user mode for session restore @@ -229,7 +229,7 @@ class Core : public QObject { * \param networkId The Id of the network */ static inline QString userModes(UserId user, NetworkId networkId) { - return instance()->storage->userModes(user, networkId); + return instance()->_storage->userModes(user, networkId); } //! Make our user modes persistent for session restore @@ -240,7 +240,7 @@ class Core : public QObject { * \param userModes The current user modes of own user */ static inline void setUserModes(UserId user, NetworkId networkId, const QString &userModes) { - return instance()->storage->setUserModes(user, networkId, userModes); + return instance()->_storage->setUserModes(user, networkId, userModes); } //! Get the unique BufferInfo for the given combination of network and buffername for a user. @@ -254,7 +254,7 @@ class Core : public QObject { * \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found */ static inline BufferInfo bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer = "", bool create = true) { - return instance()->storage->bufferInfo(user, networkId, type, buffer, create); + return instance()->_storage->bufferInfo(user, networkId, type, buffer, create); } //! Get the unique BufferInfo for a bufferId @@ -264,7 +264,7 @@ class Core : public QObject { * \return The BufferInfo corresponding to the given buffer id, or an invalid BufferInfo if not found. */ static inline BufferInfo getBufferInfo(UserId user, const BufferId &bufferId) { - return instance()->storage->getBufferInfo(user, bufferId); + return instance()->_storage->getBufferInfo(user, bufferId); } //! Store a Message in the backlog. @@ -274,7 +274,7 @@ class Core : public QObject { * \return The globally unique id for the stored message */ static inline MsgId storeMessage(const Message &message) { - return instance()->storage->logMessage(message); + return instance()->_storage->logMessage(message); } //! Request a certain number messages stored in a given buffer. @@ -285,7 +285,7 @@ class Core : public QObject { * \return The requested list of messages */ static inline QList requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) { - return instance()->storage->requestMsgs(user, bufferId, first, last, limit); + return instance()->_storage->requestMsgs(user, bufferId, first, last, limit); } //! Request a certain number of messages across all buffers @@ -295,7 +295,7 @@ class Core : public QObject { * \return The requested list of messages */ static inline QList requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) { - return instance()->storage->requestAllMsgs(user, first, last, limit); + return instance()->_storage->requestAllMsgs(user, first, last, limit); } //! Request a list of all buffers known to a user. @@ -306,7 +306,7 @@ class Core : public QObject { * \return A list of the BufferInfos for all buffers as requested */ static inline QList requestBuffers(UserId user) { - return instance()->storage->requestBuffers(user); + return instance()->_storage->requestBuffers(user); } //! Request a list of BufferIds for a given NetworkId @@ -317,7 +317,7 @@ class Core : public QObject { * \return List of BufferIds belonging to the Network */ static inline QList requestBufferIdsForNetwork(UserId user, NetworkId networkId) { - return instance()->storage->requestBufferIdsForNetwork(user, networkId); + return instance()->_storage->requestBufferIdsForNetwork(user, networkId); } //! Remove permanently a buffer and it's content from the storage backend @@ -329,7 +329,7 @@ class Core : public QObject { * \return true if successfull */ static inline bool removeBuffer(const UserId &user, const BufferId &bufferId) { - return instance()->storage->removeBuffer(user, bufferId); + return instance()->_storage->removeBuffer(user, bufferId); } //! Rename a Buffer @@ -340,7 +340,7 @@ class Core : public QObject { * \return true if successfull */ static inline bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) { - return instance()->storage->renameBuffer(user, bufferId, newName); + return instance()->_storage->renameBuffer(user, bufferId, newName); } //! Merge the content of two Buffers permanently. This cannot be reversed! @@ -351,7 +351,7 @@ class Core : public QObject { * \return true if successfulln */ static inline bool mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) { - return instance()->storage->mergeBuffersPermanently(user, bufferId1, bufferId2); + return instance()->_storage->mergeBuffersPermanently(user, bufferId1, bufferId2); } //! Update the LastSeenDate for a Buffer @@ -363,7 +363,7 @@ class Core : public QObject { * \param MsgId The Message id of the message that has been just seen */ static inline void setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) { - return instance()->storage->setBufferLastSeenMsg(user, bufferId, msgId); + return instance()->_storage->setBufferLastSeenMsg(user, bufferId, msgId); } //! Get a Hash of all last seen message ids @@ -373,7 +373,7 @@ class Core : public QObject { * \param user The Owner of the buffers */ static inline QHash bufferLastSeenMsgIds(UserId user) { - return instance()->storage->bufferLastSeenMsgIds(user); + return instance()->_storage->bufferLastSeenMsgIds(user); } const QDateTime &startTime() const { return _startTime; } @@ -424,7 +424,7 @@ private: void unregisterStorageBackend(Storage *); QHash sessions; - Storage *storage; + Storage *_storage; QTimer _storageSyncTimer; #ifdef HAVE_SSL @@ -440,7 +440,7 @@ private: QDateTime _startTime; - bool configured; + bool _configured; }; #endif diff --git a/src/core/storage.h b/src/core/storage.h index cc3d0393..1cb2ee82 100644 --- a/src/core/storage.h +++ b/src/core/storage.h @@ -31,10 +31,16 @@ class Storage : public QObject { Q_OBJECT - public: +public: Storage(QObject *parent = 0); virtual ~Storage() {}; + enum State { + IsReady, // ready to go + NeedsSetup, // need basic setup (ask the user for input) + NotAvailable // remove the storage backend from the list of avaliable backends + }; + public slots: /* General */ @@ -62,9 +68,9 @@ public slots: //! Initialize the storage provider /** \param settings Hostname, port, username, password, ... - * \return True if and only if the storage provider was initialized successfully. + * \return the State the storage backend is now in (see Storage::State) */ - virtual bool init(const QVariantMap &settings = QVariantMap()) = 0; + virtual State init(const QVariantMap &settings = QVariantMap()) = 0; //! Makes temp data persistent /** This Method is periodically called by the Quassel Core to make temporary -- 2.20.1