1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

Handle sync and api state before and after login/logout

This commit is contained in:
Laurent Cozic 2017-01-11 11:14:57 +01:00
parent 5c7581ae1d
commit a1bffbb5e5
17 changed files with 185 additions and 11 deletions

View File

@ -22,7 +22,8 @@ SOURCES += \
models/basemodel.cpp \
models/setting.cpp \
paths.cpp \
window.cpp
window.cpp \
filters.cpp
RESOURCES += qml.qrc \
database.qrc
@ -59,7 +60,8 @@ HEADERS += \
models/setting.h \
paths.h \
constants.h \
window.h
window.h \
filters.h
DISTFILES += \
AndroidManifest.xml

View File

@ -6,6 +6,12 @@ LoginPageForm {
id: root
function onShown() {
root.apiBaseUrl = settings.valueString("api.baseUrl");
root.email = settings.valueString("user.email");
root.password = "";
}
Connections {
target: root
onLoginButtonClicked: {

View File

@ -9,6 +9,10 @@ Item {
property alias currentFolderIndex: folderList.currentIndex
property alias currentNoteIndex: noteList.currentIndex
function onShown() {
}
RowLayout {
id: layout
anchors.fill: parent
@ -94,4 +98,12 @@ Item {
onClicked: appRoot.syncButtonClicked()
}
Button {
id: logoutButton
text: "Logout"
anchors.right: syncButton.left
anchors.top: parent.top
onClicked: dispatcher.logoutClicked()
}
}

View File

@ -48,6 +48,8 @@ Item {
print("Switching to page: " + pageName);
var page = pageByName(pageName);
page.visible = true;
page.onShown();
}
MainPage {

View File

@ -10,6 +10,7 @@
#include "dispatcher.h"
#include "paths.h"
#include "constants.h"
#include "filters.h"
using namespace jop;
@ -42,12 +43,15 @@ Application::Application(int &argc, char **argv) :
settings.setValue("clientId", uuid::createUuid());
}
Settings* qmlSettings = new Settings();
view_.setResizeMode(QQuickView::SizeRootObjectToView);
QQmlContext *ctxt = view_.rootContext();
ctxt->setContextProperty("folderListModel", &folderModel_);
ctxt->setContextProperty("noteListModel", &noteModel_);
ctxt->setContextProperty("noteModel", &selectedQmlNote_);
ctxt->setContextProperty("dispatcher", &dispatcher());
ctxt->setContextProperty("settings", qmlSettings);
view_.setSource(QUrl("qrc:/app.qml"));
@ -62,6 +66,7 @@ Application::Application(int &argc, char **argv) :
connect(&dispatcher(), SIGNAL(folderUpdated(QString)), this, SLOT(dispatcher_folderUpdated(QString)));
connect(&dispatcher(), SIGNAL(folderDeleted(QString)), this, SLOT(dispatcher_folderDeleted(QString)));
connect(&dispatcher(), SIGNAL(loginClicked(QString,QString,QString)), this, SLOT(dispatcher_loginClicked(QString,QString,QString)));
connect(&dispatcher(), SIGNAL(logoutClicked()), this, SLOT(dispatcher_logoutClicked()));
view_.show();
@ -75,6 +80,11 @@ Application::Application(int &argc, char **argv) :
if (!settings.contains("user.email") || !settings.contains("session.id") || !settings.contains("api.baseUrl")) {
view_.showPage("login");
} else {
afterSessionInitialization();
//QString apiBaseUrl = settings.value("api.baseUrl").toString();
//api_.setBaseUrl(apiBaseUrl);
//synchronizer_.api().setBaseUrl(apiBaseUrl);
//synchronizer_.setSessionId(settings.value("session.id").toString());
view_.showPage("main");
}
@ -107,8 +117,9 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta
if (tag == "getSession") {
if (response.contains("error")) {
qCritical() << "Could not get session:" << response.value("error").toString();
qWarning() << "Could not get session:" << response.value("error").toString();
dispatcher().emitLoginFailed();
view_.showPage("login");
} else {
QString sessionId = response.value("id").toString();
qDebug() << "Got session" << sessionId;
@ -116,8 +127,8 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta
settings.setValue("session.id", sessionId);
afterSessionInitialization();
dispatcher().emitLoginSuccess();
view_.showPage("main");
}
view_.showPage("main");
return;
}
}
@ -142,14 +153,24 @@ void Application::dispatcher_loginClicked(const QString &apiBaseUrl, const QStri
dispatcher().emitLoginStarted();
Settings settings;
settings.setValue("user.email", email);
settings.setValue("api.baseUrl", apiBaseUrl);
settings.setValue("user.email", filters::email(email));
settings.setValue("api.baseUrl", filters::apiBaseUrl(apiBaseUrl));
api_.setBaseUrl(apiBaseUrl);
login(email, password);
}
void Application::dispatcher_logoutClicked() {
api_.abortAll();
synchronizer_.abort();
synchronizer_.freeze();
Settings settings;
settings.setValue("session.id", "");
view_.showPage("login");
}
void Application::synchronizerTimer_timeout() {
//synchronizerTimer_.start(1000 * 10);
synchronizer_.start();
@ -178,8 +199,11 @@ void Application::afterSessionInitialization() {
Settings settings;
QString sessionId = settings.value("session.id").toString();
qDebug() << "Session:" << sessionId;
api_.setBaseUrl(settings.value("api.baseUrl").toString());
api_.setSessionId(sessionId);
synchronizer_.api().setBaseUrl(settings.value("api.baseUrl").toString());
synchronizer_.setSessionId(sessionId);
synchronizer_.unfreeze();
synchronizer_.start();
}

View File

@ -53,6 +53,7 @@ public slots:
void dispatcher_folderUpdated(const QString& folderId);
void dispatcher_folderDeleted(const QString& folderId);
void dispatcher_loginClicked(const QString &domain, const QString &email, const QString &password);
void dispatcher_logoutClicked();
void synchronizerTimer_timeout();

View File

@ -20,6 +20,10 @@ void Dispatcher::emitLoginClicked(const QString &apiBaseUrl, const QString &emai
emit loginClicked(apiBaseUrl, email, password);
}
void Dispatcher::emitLogoutClicked() {
emit logoutClicked();
}
void Dispatcher::emitLoginStarted() {
emit loginStarted();
}

View File

@ -19,6 +19,7 @@ public slots:
void emitFolderUpdated(const QString& folderId);
void emitFolderDeleted(const QString& folderId);
void emitLoginClicked(const QString& domain, const QString& email, const QString &password);
void emitLogoutClicked();
void emitLoginStarted();
void emitLoginFailed();
void emitLoginSuccess();
@ -29,6 +30,7 @@ signals:
void folderUpdated(const QString& folderId);
void folderDeleted(const QString& folderId);
void loginClicked(const QString& domain, const QString& email, const QString& password);
void logoutClicked();
void loginStarted();
void loginFailed();
void loginSuccess();

View File

@ -0,0 +1,19 @@
#include "filters.h"
using namespace jop;
QString filters::apiBaseUrl(const QString &baseUrl) {
QString output(baseUrl.trimmed());
if (!output.startsWith("http://") && !output.startsWith("https://")) {
output = "http://" + output;
}
while (output.endsWith("/")) {
output = output.left(output.length() - 1);
}
return output;
}
QString filters::email(const QString &email) {
QString output(email.trimmed());
return output;
}

View File

@ -0,0 +1,15 @@
#ifndef FILTERS_H
#define FILTERS_H
#include <stable.h>
namespace jop {
namespace filters {
QString apiBaseUrl(const QString& apiBaseUrl);
QString email(const QString& email);
}
}
#endif // FILTERS_H

View File

@ -187,7 +187,6 @@ bool BaseModel::trackChanges() const {
}
bool BaseModel::isNew() const {
qDebug() << "EEEEEEEEEEEEEEEEEEEEEE" << isNew_ << primaryKey() << valueIsSet(primaryKey()) << values_["id"].toString();
if (isNew_ == 0) return false;
if (isNew_ == 1) return true;
return !valueIsSet(primaryKey());
@ -415,7 +414,6 @@ int BaseModel::Value::toInt() const {
QString BaseModel::Value::toString() const {
if (type_ == QMetaType::QString) return stringValue_;
if (type_ == QMetaType::Int) return QString::number(intValue_);
qCritical("Unreachable");
return QString("");
}

View File

@ -26,3 +26,11 @@ void Settings::initialize() {
const QSettings::Format SqliteFormat = QSettings::registerFormat("sqlite", &readSqlite, &writeSqlite);
QSettings::setDefaultFormat(SqliteFormat);
}
QString Settings::valueString(const QString &name, const QString &defaultValue) {
return value(name, defaultValue).toString();
}
int Settings::valueInt(const QString &name, int defaultValue) {
return value(name, defaultValue).toInt();
}

View File

@ -16,6 +16,11 @@ public:
static void initialize();
public slots:
QString valueString(const QString& name, const QString& defaultValue = "");
int valueInt(const QString& name, int defaultValue = 0);
};
}

View File

@ -12,6 +12,11 @@ Synchronizer::Synchronizer(Database &database) : db_(database) {
}
void Synchronizer::start() {
if (state_ == Frozen) {
qWarning() << "Cannot start synchronizer while frozen";
return;
}
if (state_ != Idle) {
qWarning() << "Cannot start synchronizer because synchronization already in progress. State: " << state_;
return;
@ -26,6 +31,22 @@ void Synchronizer::setSessionId(const QString &v) {
api_.setSessionId(v);
}
void Synchronizer::abort() {
switchState(Aborting);
}
void Synchronizer::freeze() {
switchState(Frozen);
}
void Synchronizer::unfreeze() {
switchState(Idle);
}
WebApi &Synchronizer::api() {
return api_;
}
QUrlQuery Synchronizer::valuesToUrlQuery(const QHash<QString, Change::Value>& values) const {
QUrlQuery query;
for (QHash<QString, Change::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
@ -57,6 +78,15 @@ void Synchronizer::checkNextState() {
break;
case Aborting:
switchState(Idle);
break;
case Frozen:
break;
default:
qCritical() << "Synchronizer has invalid state" << state_;
@ -142,11 +172,32 @@ void Synchronizer::switchState(Synchronizer::SynchronizationState state) {
query.addQueryItem("last_id", lastRevId);
api_.get("synchronizer", query, QUrlQuery(), "download:getSynchronizer");
} else if (state == Aborting) {
// =============================================================================================
// ABORTING STATE
// =============================================================================================
uploadsRemaining_ = 0;
api_.abortAll();
checkNextState();
} else if (state == Frozen) {
// =============================================================================================
// FROZEN STATE
// =============================================================================================
}
}
void Synchronizer::api_requestDone(const QJsonObject& response, const QString& tag) {
if (state_ == Frozen) {
qWarning() << "Receiving response while synchronizer is frozen";
return;
}
QStringList parts = tag.split(':');
QString category = parts[0];
QString action = parts[1];
@ -164,7 +215,7 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
// HANDLE UPLOAD RESPONSE
// =============================================================================================
if (category == "upload") {
if (state_ == UploadingChanges) {
uploadsRemaining_--;
qDebug() << "Synced folder" << arg1;
@ -191,7 +242,7 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
// HANDLE DOWNLOAD RESPONSE
// =============================================================================================
} else if (category == "download") {
} else if (state_ == DownloadingChanges) {
if (action == "getSynchronizer") {
QJsonArray items = response["items"].toArray();
QString maxRevId = "";

View File

@ -14,11 +14,15 @@ class Synchronizer : public QObject {
public:
enum SynchronizationState { Idle, UploadingChanges, DownloadingChanges };
enum SynchronizationState { Idle, UploadingChanges, DownloadingChanges, Aborting, Frozen };
Synchronizer(Database& database);
void start();
void setSessionId(const QString& v);
void abort();
void freeze();
void unfreeze();
WebApi& api();
private:

View File

@ -30,6 +30,7 @@ void WebApi::execRequest(HttpMethod method, const QString &path, const QUrlQuery
r.data = data;
r.tag = tag;
r.buffer = NULL;
r.reply = NULL;
queuedRequests_ << r;
processQueue();
@ -45,6 +46,25 @@ void WebApi::setSessionId(const QString &v) {
sessionId_ = v;
}
void WebApi::abortAll() {
for (int i = 0; i < inProgressRequests_.size(); i++) {
QueuedRequest r = inProgressRequests_[i];
if (r.reply) {
r.reply->abort();
// TODO: Delete r.reply?
}
}
for (int i = 0; i < queuedRequests_.size(); i++) {
QueuedRequest r = queuedRequests_[i];
if (r.reply) {
r.reply->abort();
// TODO: Delete r.reply?
}
}
queuedRequests_.size();
}
void WebApi::processQueue() {
if (!queuedRequests_.size() || inProgressRequests_.size() >= 50) return;
QueuedRequest r = queuedRequests_.takeFirst();

View File

@ -33,6 +33,7 @@ public:
void del(const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");
void patch(const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");
void setSessionId(const QString& v);
void abortAll();
private: