Merge lp:~mzanetti/reminders-app/rework-error-handling into lp:reminders-app

Proposed by Michael Zanetti
Status: Merged
Approved by: Michael Zanetti
Approved revision: 14
Merged at revision: 15
Proposed branch: lp:~mzanetti/reminders-app/rework-error-handling
Merge into: lp:reminders-app
Prerequisite: lp:~mzanetti/reminders-app/use-ssl
Diff against target: 877 lines (+292/-250)
17 files modified
src/plugin/Evernote/jobs/createnotejob.cpp (+25/-31)
src/plugin/Evernote/jobs/createnotejob.h (+11/-5)
src/plugin/Evernote/jobs/deletenotejob.cpp (+8/-9)
src/plugin/Evernote/jobs/deletenotejob.h (+5/-3)
src/plugin/Evernote/jobs/evernotejob.cpp (+45/-14)
src/plugin/Evernote/jobs/evernotejob.h (+21/-2)
src/plugin/Evernote/jobs/fetchnotebooksjob.cpp (+8/-12)
src/plugin/Evernote/jobs/fetchnotebooksjob.h (+8/-3)
src/plugin/Evernote/jobs/fetchnotejob.cpp (+6/-16)
src/plugin/Evernote/jobs/fetchnotejob.h (+8/-2)
src/plugin/Evernote/jobs/fetchnotesjob.cpp (+6/-13)
src/plugin/Evernote/jobs/fetchnotesjob.h (+6/-3)
src/plugin/Evernote/jobs/savenotejob.cpp (+26/-32)
src/plugin/Evernote/jobs/savenotejob.h (+11/-3)
src/plugin/Evernote/note.cpp (+1/-1)
src/plugin/Evernote/notesstore.cpp (+71/-93)
src/plugin/Evernote/notesstore.h (+26/-8)
To merge this branch: bzr merge lp:~mzanetti/reminders-app/rework-error-handling
Reviewer Review Type Date Requested Status
Victor Thompson (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
David Planella Approve
Review via email: mp+196987@code.launchpad.net

Commit message

rework error handling and job queue processing.

Description of the change

This reworks how jobs report their results. EvernoteJob.cpp does now all the error handling and tells the job what result code to emit. Creating a new threaded API call now is a matter of copying an existing job and adjusting 2 lines of code.

Along with that I simplified the usage of the job queue. Just create a new job, call enqueue(job) and connect to the jobDone() signal for obtaining results. No need for taking care about processing the queue any more.

Last but not least the simplified error handling made it easy to add a workaround for the connection drops. EvernoteJob.cpp now gives it a second try in case the connection dropped by reopening the connection and starting the job again. In my tests that successfully recovered from 100% of the drops.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Victor Thompson (vthompson) wrote :

1. In notes.h, I believe you'll want to include QQmlParserStatus in a Q_INTERFACES macro.
2. I see you're reworking some of the connection error exception handling. I get the following core dump every so often, I wonder if it's related to an error that isn't being handled.

terminate called after throwing an instance of 'apache::thrift::transport::TSSLException'
  what(): SSL_write: errno = 110
Aborted (core dumped)

3. Overall the changes to job handling and error handling look good--is there any particular error path that's being fixed that I might be able to try to reproduce? It's a bit hard to try to verify an overall rework of exception handling.

review: Needs Information
Revision history for this message
Michael Zanetti (mzanetti) wrote :

> 1. In notes.h, I believe you'll want to include QQmlParserStatus in a
> Q_INTERFACES macro.

Hmm... Why is that?

> 2. I see you're reworking some of the connection error exception handling. I
> get the following core dump every so often, I wonder if it's related to an
> error that isn't being handled.
>
> terminate called after throwing an instance of
> 'apache::thrift::transport::TSSLException'
> what(): SSL_write: errno = 110
> Aborted (core dumped)

Interesting. I intentionally only caught the exceptions I could see myself in order to learn about libthrift's behavior. I haven't ever gotten this one. I'll add catching that one and also all the others that can happen in theory as I've seen enough of libthrift by now.

Still, if you could tell me how to reproduce this I could check if there is something else I'm doing wrong and try to prevent it from happening instead of just catching and ignoring.

>
> 3. Overall the changes to job handling and error handling look good--is there
> any particular error path that's being fixed that I might be able to try to
> reproduce? It's a bit hard to try to verify an overall rework of exception
> handling.

Nope, not really. The main reason for this commit is that I didn't want to add the try {} catch() block around every single call to the evernote SDK. So this now offers one place to catch them all and still pass the error code back to the job in a Qt style manner (As Qt intentionally does not use exceptions by design).

Revision history for this message
David Planella (dpm) wrote :

>> 1. In notes.h, I believe you'll want to include QQmlParserStatus in a
>> Q_INTERFACES macro.

> Hmm... Why is that?

I'm not familiar with this, so take this as a pointer rather than an suggestion, but my guess would be as it's recommended at http://qt-project.org/doc/qt-5.0/qtqml/qqmlparserstatus.html

In any case, I don't see this affecting this MP.

Revision history for this message
David Planella (dpm) wrote :

I cannot reproduce Victor's core dump after several run tests. Otherwise, LGTM.

In any case, Victor, if you could tell us how to reproduce, we can come back to it.

review: Approve
Revision history for this message
Michael Zanetti (mzanetti) wrote :

> >> 1. In notes.h, I believe you'll want to include QQmlParserStatus in a
> >> Q_INTERFACES macro.
>
> > Hmm... Why is that?
>
> I'm not familiar with this, so take this as a pointer rather than an
> suggestion, but my guess would be as it's recommended at http://qt-
> project.org/doc/qt-5.0/qtqml/qqmlparserstatus.html
>
> In any case, I don't see this affecting this MP.

Oh... now I get it... Yeah. in this merge notes.h still inherits QQmlParserStatus. This has been changed in a newer one. If you want me I can add it in here for completeness, but it would be removed again with the next merge. Sorry for the confusion.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)
Revision history for this message
Victor Thompson (vthompson) wrote :

I haven't been able to reproduce. To me it seems like the core happened after letting the app idle while I was reviewing the code. So maybe it was related to the connection timing out.

review: Approve
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Thanks Victor.

I'll pay extra attention to this.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/plugin/Evernote/jobs/createnotejob.cpp'
--- src/plugin/Evernote/jobs/createnotejob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/createnotejob.cpp 2013-11-27 21:48:53 +0000
@@ -22,36 +22,30 @@
2222
23#include <QDebug>23#include <QDebug>
2424
25CreateNoteJob::CreateNoteJob(Note *note, QObject *parent) :25CreateNoteJob::CreateNoteJob(const QString &title, const QString &notebookGuid, const QString &content, QObject *parent) :
26 EvernoteJob(parent),26 EvernoteJob(parent),
27 m_note(note)27 m_title(title),
28{28 m_notebookGuid(notebookGuid),
29}29 m_content(content)
3030{
31void CreateNoteJob::run()31}
32{32
33 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;33void CreateNoteJob::startJob()
3434{
35 try {35 evernote::edam::Note input;
36 evernote::edam::Note input;36 input.title = m_title.toStdString();
37 input.title = m_note->title().toStdString();37 input.__isset.title = true;
38 input.__isset.title = true;38 input.notebookGuid = m_notebookGuid.toStdString();
39 input.notebookGuid = m_note->notebookGuid().toStdString();39 input.__isset.notebookGuid = true;
40 input.__isset.notebookGuid = true;40 input.content = m_content.toStdString();
41 input.content = m_note->content().toStdString();41 input.__isset.content = true;
42 input.__isset.content = true;42 input.contentLength = m_content.length();
43 input.contentLength = m_note->content().length();43 input.__isset.contentLength = true;
44 input.__isset.contentLength = true;44
4545 client()->createNote(m_resultNote, token().toStdString(), input);
46 evernote::edam::Note result;46}
47 client()->createNote(result, token().toStdString(), input);47
4848void CreateNoteJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
49 m_note->setGuid(QString::fromStdString(result.guid));49{
5050 emit jobDone(errorCode, errorMessage, m_resultNote);
51 } catch(evernote::edam::EDAMUserException e) {
52 errorCode = NotesStore::ErrorCodeUserException;
53 } catch(evernote::edam::EDAMSystemException) {
54 errorCode = NotesStore::ErrorCodeSystemException;
55 }
56 emit resultReady(errorCode, m_note);
57}51}
5852
=== modified file 'src/plugin/Evernote/jobs/createnotejob.h'
--- src/plugin/Evernote/jobs/createnotejob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/createnotejob.h 2013-11-27 21:48:53 +0000
@@ -8,15 +8,21 @@
8{8{
9 Q_OBJECT9 Q_OBJECT
10public:10public:
11 explicit CreateNoteJob(Note *note, QObject *parent = 0);11 explicit CreateNoteJob(const QString &title, const QString &notebookGuid, const QString &content, QObject *parent = 0);
12
13 void run();
1412
15signals:13signals:
16 void resultReady(NotesStore::ErrorCode errorCode, Note *note);14 void jobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, evernote::edam::Note note);
15
16protected:
17 void startJob();
18 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
1719
18private:20private:
19 Note *m_note;21 QString m_title;
22 QString m_notebookGuid;
23 QString m_content;
24
25 evernote::edam::Note m_resultNote;
20};26};
2127
22#endif // CREATENOTEJOB_H28#endif // CREATENOTEJOB_H
2329
=== modified file 'src/plugin/Evernote/jobs/deletenotejob.cpp'
--- src/plugin/Evernote/jobs/deletenotejob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/deletenotejob.cpp 2013-11-27 21:48:53 +0000
@@ -26,13 +26,12 @@
26{26{
27}27}
2828
29void DeleteNoteJob::run()29void DeleteNoteJob::startJob()
30{30{
31 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;31 client()->deleteNote(token().toStdString(), m_guid.toStdString());
32 try {32}
33 client()->deleteNote(token().toStdString(), m_guid.toStdString());33
34 } catch(...) {34void DeleteNoteJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
35 catchTransportException();35{
36 }36 emit jobDone(errorCode, errorMessage, m_guid);
37 emit resultReady(errorCode, m_guid);
38}37}
3938
=== modified file 'src/plugin/Evernote/jobs/deletenotejob.h'
--- src/plugin/Evernote/jobs/deletenotejob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/deletenotejob.h 2013-11-27 21:48:53 +0000
@@ -9,10 +9,12 @@
9public:9public:
10 DeleteNoteJob(const QString &guid, QObject *parent = 0);10 DeleteNoteJob(const QString &guid, QObject *parent = 0);
1111
12 void run();
13
14signals:12signals:
15 void resultReady(NotesStore::ErrorCode errorCode, const QString &guid);13 void jobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const QString &guid);
14
15protected:
16 void startJob();
17 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
1618
17private:19private:
18 QString m_guid;20 QString m_guid;
1921
=== modified file 'src/plugin/Evernote/jobs/evernotejob.cpp'
--- src/plugin/Evernote/jobs/evernotejob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/evernotejob.cpp 2013-11-27 21:48:53 +0000
@@ -38,11 +38,55 @@
38 m_token(NotesStore::instance()->token())38 m_token(NotesStore::instance()->token())
39{39{
40 connect(this, &EvernoteJob::finished, this, &EvernoteJob::deleteLater);40 connect(this, &EvernoteJob::finished, this, &EvernoteJob::deleteLater);
41 connect(this, &EvernoteJob::finished, NotesStore::instance(), &NotesStore::startNextJob);
41}42}
4243
43EvernoteJob::~EvernoteJob()44EvernoteJob::~EvernoteJob()
44{45{
4546}
47
48void EvernoteJob::run()
49{
50 if (m_token.isEmpty()) {
51 qWarning() << "No token set. Cannot execute job.";
52 emitJobDone(NotesStore::ErrorCodeUserException, QStringLiteral("No token set."));
53 return;
54 }
55
56 try {
57 startJob();
58
59 } catch (const TTransportException & e) {
60
61 // The connection broke down. libthrift + evernote servers seem to be quite flaky
62 // so lets try to start the job once more.
63 qWarning() << "Got a transport exception:" << e.what() << ". Trying to reestablish connection...";
64 try {
65 NotesStore::instance()->m_httpClient->close();
66 NotesStore::instance()->m_httpClient->open();
67
68 startJob();
69 } catch (const TTransportException &e) {
70 // Giving up... the connection seems to be down for real.
71 qWarning() << "Cannot reestablish connection:" << e.what();
72 emitJobDone(NotesStore::ErrorCodeConnectionLost, e.what());
73 } catch (const evernote::edam::EDAMUserException &e) {
74 emitJobDone(NotesStore::ErrorCodeUserException, e.what());
75 } catch (const evernote::edam::EDAMSystemException &e) {
76 emitJobDone(NotesStore::ErrorCodeSystemException, e.what());
77 } catch (const evernote::edam::EDAMNotFoundException &e) {
78 emitJobDone(NotesStore::ErrorCodeNotFoundExcpetion, e.what());
79 }
80
81 } catch (const evernote::edam::EDAMUserException &e) {
82 emitJobDone(NotesStore::ErrorCodeUserException, e.what());
83 } catch (const evernote::edam::EDAMSystemException &e) {
84 emitJobDone(NotesStore::ErrorCodeSystemException, e.what());
85 } catch (const evernote::edam::EDAMNotFoundException &e) {
86 emitJobDone(NotesStore::ErrorCodeNotFoundExcpetion, e.what());
87 }
88
89 emitJobDone(NotesStore::ErrorCodeNoError, QString());
46}90}
4791
48evernote::edam::NoteStoreClient *EvernoteJob::client()92evernote::edam::NoteStoreClient *EvernoteJob::client()
@@ -54,16 +98,3 @@
54{98{
55 return m_token;99 return m_token;
56}100}
57
58void EvernoteJob::catchTransportException()
59{
60 try {
61 // this function is meant to be called from a catch block
62 // rethrow the exception to catch it again
63 throw;
64 } catch (const TTransportException & e) {
65 qDebug() << e.what();
66 } catch (const TException & e) {
67 qDebug() << e.what();
68 }
69}
70101
=== modified file 'src/plugin/Evernote/jobs/evernotejob.h'
--- src/plugin/Evernote/jobs/evernotejob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/evernotejob.h 2013-11-27 21:48:53 +0000
@@ -10,6 +10,19 @@
1010
11#include <QThread>11#include <QThread>
1212
13/* How to create a new Job type:
14 * - Subclass EvernoteJob
15 * - Implement startJob() in which you do the call to evernote.
16 * - No need to catch exceptions, EvernoteJob will deal with those.
17 * - Define a jobDone() signal with the result parameters you need.
18 * - Keep the convention of jobDone(NotesStore::ErrorCode errorCode, const QString &message [, ...])
19 * - Emit jobDone() in your implementation of emitJobDone().
20 * - NOTE: emitJobDone() might be called with an error even before startJob() is triggered.
21 *
22 * Jobs can be enqueue()d in NotesStore.
23 * They will destroy themselves when finished.
24 * The jobqueue will take care about starting them.
25 */
13class EvernoteJob : public QThread26class EvernoteJob : public QThread
14{27{
15 Q_OBJECT28 Q_OBJECT
@@ -17,12 +30,18 @@
17 explicit EvernoteJob(QObject *parent = 0);30 explicit EvernoteJob(QObject *parent = 0);
18 virtual ~EvernoteJob();31 virtual ~EvernoteJob();
1932
33 void run() final;
34
35signals:
36 void connectionLost(const QString &errorMessage);
37
20protected:38protected:
39 virtual void startJob() = 0;
40 virtual void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage) = 0;
41
21 evernote::edam::NoteStoreClient* client();42 evernote::edam::NoteStoreClient* client();
22 QString token();43 QString token();
2344
24 void catchTransportException();
25
26private:45private:
27 QString m_token;46 QString m_token;
28};47};
2948
=== modified file 'src/plugin/Evernote/jobs/fetchnotebooksjob.cpp'
--- src/plugin/Evernote/jobs/fetchnotebooksjob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/fetchnotebooksjob.cpp 2013-11-27 21:48:53 +0000
@@ -28,16 +28,12 @@
28}28}
2929
3030
31void FetchNotebooksJob::run()31void FetchNotebooksJob::startJob()
32{32{
33 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;33 client()->listNotebooks(m_results, token().toStdString());
34 std::vector<evernote::edam::Notebook> results;34}
35 try {35
36 client()->listNotebooks(results, token().toStdString());36void FetchNotebooksJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
37 } catch(evernote::edam::EDAMUserException) {37{
38 errorCode = NotesStore::ErrorCodeUserException;38 emit jobDone(errorCode, errorMessage, m_results);
39 } catch(evernote::edam::EDAMSystemException) {
40 errorCode = NotesStore::ErrorCodeSystemException;
41 }
42 emit resultReady(errorCode, results);
43}39}
4440
=== modified file 'src/plugin/Evernote/jobs/fetchnotebooksjob.h'
--- src/plugin/Evernote/jobs/fetchnotebooksjob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/fetchnotebooksjob.h 2013-11-27 21:48:53 +0000
@@ -9,10 +9,15 @@
9public:9public:
10 explicit FetchNotebooksJob(QObject *parent = 0);10 explicit FetchNotebooksJob(QObject *parent = 0);
1111
12 void run();
13
14signals:12signals:
15 void resultReady(NotesStore::ErrorCode errorCode, const std::vector<evernote::edam::Notebook> &results);13 void jobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const std::vector<evernote::edam::Notebook> &results);
14
15protected:
16 void startJob();
17 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
18
19private:
20 std::vector<evernote::edam::Notebook> m_results;
16};21};
1722
18#endif // FETCHNOTEBOOKSJOB_H23#endif // FETCHNOTEBOOKSJOB_H
1924
=== modified file 'src/plugin/Evernote/jobs/fetchnotejob.cpp'
--- src/plugin/Evernote/jobs/fetchnotejob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/fetchnotejob.cpp 2013-11-27 21:48:53 +0000
@@ -26,22 +26,12 @@
26{26{
27}27}
2828
29void FetchNoteJob::run()29void FetchNoteJob::startJob()
30{30{
31 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;31 client()->getNote(m_result, token().toStdString(), m_guid.toStdString(), true, true, false, false);
32 evernote::edam::Note result;32}
33 try {
34 client()->getNote(result, token().toStdString(), m_guid.toStdString(), true, true, false, false);
35 } catch (evernote::edam::EDAMUserException) {
36 errorCode = NotesStore::ErrorCodeUserException;
37 } catch (evernote::edam::EDAMSystemException) {
38 errorCode = NotesStore::ErrorCodeSystemException;
39 } catch (evernote::edam::EDAMNotFoundException) {
40 errorCode = NotesStore::ErrorCodeNotFoundExcpetion;
41 } catch (...) {
42 catchTransportException();
43 errorCode = NotesStore::ErrorCodeConnectionLost;
44 }
4533
46 emit resultReady(errorCode, result);34void FetchNoteJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
35{
36 emit resultReady(errorCode, errorMessage, m_result);
47}37}
4838
=== modified file 'src/plugin/Evernote/jobs/fetchnotejob.h'
--- src/plugin/Evernote/jobs/fetchnotejob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/fetchnotejob.h 2013-11-27 21:48:53 +0000
@@ -9,14 +9,20 @@
9public:9public:
10 explicit FetchNoteJob(const QString &guid, QObject *parent = 0);10 explicit FetchNoteJob(const QString &guid, QObject *parent = 0);
1111
12 void run();
13signals:12signals:
14 void resultReady(NotesStore::ErrorCode error, const evernote::edam::Note &note);13 void resultReady(NotesStore::ErrorCode error, const QString &errorMessage, const evernote::edam::Note &note);
14
15protected:
16 void startJob();
17 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
1518
16private:19private:
17 evernote::edam::NoteStoreClient *m_client;20 evernote::edam::NoteStoreClient *m_client;
18 QString m_token;21 QString m_token;
19 QString m_guid;22 QString m_guid;
23
24 evernote::edam::Note m_result;
25
20};26};
2127
22#endif // FETCHNOTEJOB_H28#endif // FETCHNOTEJOB_H
2329
=== modified file 'src/plugin/Evernote/jobs/fetchnotesjob.cpp'
--- src/plugin/Evernote/jobs/fetchnotesjob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/fetchnotesjob.cpp 2013-11-27 21:48:53 +0000
@@ -30,7 +30,7 @@
30{30{
31}31}
3232
33void FetchNotesJob::run()33void FetchNotesJob::startJob()
34{34{
35 // TODO: fix start/end (use smaller chunks and continue fetching if there are more notes available)35 // TODO: fix start/end (use smaller chunks and continue fetching if there are more notes available)
36 int32_t start = 0;36 int32_t start = 0;
@@ -48,17 +48,10 @@
48 resultSpec.includeTitle = true;48 resultSpec.includeTitle = true;
49 resultSpec.__isset.includeTitle = true;49 resultSpec.__isset.includeTitle = true;
5050
51 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;51 client()->findNotesMetadata(m_results, token().toStdString(), filter, start, end, resultSpec);
52 evernote::edam::NotesMetadataList results;52}
5353
54 try {54void FetchNotesJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
55 client()->findNotesMetadata(results, token().toStdString(), filter, start, end, resultSpec);55{
56 } catch(evernote::edam::EDAMUserException) {56 emit jobDone(errorCode, errorMessage, m_results);
57 errorCode = NotesStore::ErrorCodeUserException;
58 } catch(evernote::edam::EDAMSystemException) {
59 errorCode = NotesStore::ErrorCodeSystemException;
60 } catch(evernote::edam::EDAMNotFoundException) {
61 errorCode = NotesStore::ErrorCodeNotFoundExcpetion;
62 }
63 emit resultReady(errorCode, results);
64}57}
6558
=== modified file 'src/plugin/Evernote/jobs/fetchnotesjob.h'
--- src/plugin/Evernote/jobs/fetchnotesjob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/fetchnotesjob.h 2013-11-27 21:48:53 +0000
@@ -9,13 +9,16 @@
9public:9public:
10 explicit FetchNotesJob(const QString &filterNotebookGuid, QObject *parent = 0);10 explicit FetchNotesJob(const QString &filterNotebookGuid, QObject *parent = 0);
1111
12 void run();
13
14signals:12signals:
15 void resultReady(NotesStore::ErrorCode errorCode, const evernote::edam::NotesMetadataList &results);13 void jobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const evernote::edam::NotesMetadataList &results);
14
15protected:
16 void startJob();
17 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
1618
17private:19private:
18 QString m_filterNotebookGuid;20 QString m_filterNotebookGuid;
21 evernote::edam::NotesMetadataList m_results;
19};22};
2023
21#endif // FETCHNOTESJOB_H24#endif // FETCHNOTESJOB_H
2225
=== modified file 'src/plugin/Evernote/jobs/savenotejob.cpp'
--- src/plugin/Evernote/jobs/savenotejob.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/jobs/savenotejob.cpp 2013-11-27 21:48:53 +0000
@@ -25,36 +25,30 @@
2525
26SaveNoteJob::SaveNoteJob(Note *note, QObject *parent) :26SaveNoteJob::SaveNoteJob(Note *note, QObject *parent) :
27 EvernoteJob(parent),27 EvernoteJob(parent),
28 m_note(note)28 m_guid(note->guid()),
29{29 m_title(note->title()),
30}30 m_notebookGuid(note->notebookGuid()),
3131 m_content(note->content())
32void SaveNoteJob::run()32{
33{33}
34 NotesStore::ErrorCode errorCode = NotesStore::ErrorCodeNoError;34
35 try {35void SaveNoteJob::startJob()
36 evernote::edam::Note note;36{
37 note.guid = m_note->guid().toStdString();37 evernote::edam::Note note;
38 note.__isset.guid = true;38 note.guid = m_guid.toStdString();
39 note.title = m_note->title().toStdString();39 note.__isset.guid = true;
40 note.__isset.title = true;40 note.title = m_title.toStdString();
41 note.notebookGuid = m_note->notebookGuid().toStdString();41 note.__isset.title = true;
42 note.__isset.notebookGuid = true;42 note.notebookGuid = m_notebookGuid.toStdString();
43 note.content = m_note->content().toStdString();43 note.__isset.notebookGuid = true;
44 note.__isset.content = true;44 note.content = m_content.toStdString();
45 note.contentLength = m_note->content().length();45 note.__isset.content = true;
4646 note.contentLength = m_content.length();
47 client()->updateNote(note, token().toStdString(), note);47
4848 client()->updateNote(m_note, token().toStdString(), note);
49 } catch (evernote::edam::EDAMUserException e) {49}
50 errorCode = NotesStore::ErrorCodeUserException;50
51 qDebug() << QString::fromStdString(e.parameter);51void SaveNoteJob::emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage)
52 } catch (evernote::edam::EDAMSystemException) {52{
53 errorCode = NotesStore::ErrorCodeSystemException;53 emit jobDone(errorCode, errorMessage, m_note);
54 } catch (...) {
55 catchTransportException();
56 errorCode = NotesStore::ErrorCodeConnectionLost;
57 }
58
59 emit resultReady(errorCode, m_note);
60}54}
6155
=== modified file 'src/plugin/Evernote/jobs/savenotejob.h'
--- src/plugin/Evernote/jobs/savenotejob.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/jobs/savenotejob.h 2013-11-27 21:48:53 +0000
@@ -9,12 +9,20 @@
9public:9public:
10 explicit SaveNoteJob(Note *note, QObject *parent = 0);10 explicit SaveNoteJob(Note *note, QObject *parent = 0);
1111
12 void run();
13signals:12signals:
14 void resultReady(NotesStore::ErrorCode errorCode, Note *note);13 void jobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &note);
14
15protected:
16 void startJob();
17 void emitJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage);
1518
16private:19private:
17 Note *m_note;20 QString m_guid;
21 QString m_title;
22 QString m_notebookGuid;
23 QString m_content;
24
25 evernote::edam::Note m_note;
18};26};
1927
20#endif // SAVENOTEJOB_H28#endif // SAVENOTEJOB_H
2129
=== modified file 'src/plugin/Evernote/note.cpp'
--- src/plugin/Evernote/note.cpp 2013-11-26 17:18:33 +0000
+++ src/plugin/Evernote/note.cpp 2013-11-27 21:48:53 +0000
@@ -35,7 +35,7 @@
3535
36void Note::setGuid(const QString &guid)36void Note::setGuid(const QString &guid)
37{37{
38 if (m_guid == guid) {38 if (m_guid != guid) {
39 m_guid = guid;39 m_guid = guid;
40 emit guidChanged();40 emit guidChanged();
41 }41 }
4242
=== modified file 'src/plugin/Evernote/notesstore.cpp'
--- src/plugin/Evernote/notesstore.cpp 2013-11-27 21:48:53 +0000
+++ src/plugin/Evernote/notesstore.cpp 2013-11-27 21:48:53 +0000
@@ -77,12 +77,12 @@
77 }77 }
7878
79 boost::shared_ptr<TBufferedTransport> bufferedTransport(new TBufferedTransport(socket));79 boost::shared_ptr<TBufferedTransport> bufferedTransport(new TBufferedTransport(socket));
80 boost::shared_ptr<THttpClient> userStoreHttpClient (new THttpClient(bufferedTransport,80 m_httpClient = boost::shared_ptr<THttpClient>(new THttpClient(bufferedTransport,
81 EVERNOTE_HOST.toStdString(),81 EVERNOTE_HOST.toStdString(),
82 EDAM_USER_STORE_PATH.toStdString()));82 EDAM_USER_STORE_PATH.toStdString()));
83 userStoreHttpClient->open();83 m_httpClient->open();
8484
85 boost::shared_ptr<TProtocol> iprot(new TBinaryProtocol(userStoreHttpClient));85 boost::shared_ptr<TProtocol> iprot(new TBinaryProtocol(m_httpClient));
86 m_client = new evernote::edam::NoteStoreClient(iprot);86 m_client = new evernote::edam::NoteStoreClient(iprot);
8787
88 qDebug() << "NoteStore client created.";88 qDebug() << "NoteStore client created.";
@@ -153,27 +153,6 @@
153 return m_notes.value(guid);153 return m_notes.value(guid);
154}154}
155155
156void NotesStore::saveNote(const QString &guid)
157{
158 Note *note = m_notes.value(guid);
159
160 QString enml = Html2EnmlConverter::html2enml(note->content());
161 note->setContent(enml);
162
163 SaveNoteJob *job = new SaveNoteJob(note, this);
164 connect(job, &SaveNoteJob::resultReady, this, &NotesStore::saveNoteJobDone);
165 m_jobQueue.append(job);
166 startJobQueue();
167}
168
169void NotesStore::deleteNote(const QString &guid)
170{
171 DeleteNoteJob *job = new DeleteNoteJob(guid, this);
172 connect(job, &DeleteNoteJob::resultReady, this, &NotesStore::deleteNoteJobDone);
173 m_jobQueue.append(job);
174 startJobQueue();
175}
176
177QList<Notebook *> NotesStore::notebooks() const156QList<Notebook *> NotesStore::notebooks() const
178{157{
179 return m_notebooks.values();158 return m_notebooks.values();
@@ -184,6 +163,12 @@
184 return m_notebooks.value(guid);163 return m_notebooks.value(guid);
185}164}
186165
166void NotesStore::enqueue(EvernoteJob *job)
167{
168 m_jobQueue.append(job);
169 startJobQueue();
170}
171
187void NotesStore::startJobQueue()172void NotesStore::startJobQueue()
188{173{
189 if (m_jobQueue.isEmpty()) {174 if (m_jobQueue.isEmpty()) {
@@ -205,23 +190,15 @@
205190
206void NotesStore::refreshNotes(const QString &filterNotebookGuid)191void NotesStore::refreshNotes(const QString &filterNotebookGuid)
207{192{
208 if (m_token.isEmpty()) {
209 qWarning() << "No token set. Cannot fetch notes.";
210 return;
211 }
212
213 FetchNotesJob *job = new FetchNotesJob(filterNotebookGuid);193 FetchNotesJob *job = new FetchNotesJob(filterNotebookGuid);
214 connect(job, &FetchNotesJob::resultReady, this, &NotesStore::fetchNotesJobDone);194 connect(job, &FetchNotesJob::jobDone, this, &NotesStore::fetchNotesJobDone);
215195 enqueue(job);
216 m_jobQueue.append(job);
217 startJobQueue();
218}196}
219197
220void NotesStore::fetchNotesJobDone(ErrorCode errorCode, const evernote::edam::NotesMetadataList &results)198void NotesStore::fetchNotesJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::NotesMetadataList &results)
221{199{
222 if (errorCode != ErrorCodeNoError) {200 if (errorCode != ErrorCodeNoError) {
223 qWarning() << "Failed to fetch notes list:" << errorCodeToString(errorCode);201 qWarning() << "Failed to fetch notes list:" << errorMessage;
224 startNextJob();
225 return;202 return;
226 }203 }
227204
@@ -240,29 +217,19 @@
240 emit noteAdded(note->guid());217 emit noteAdded(note->guid());
241 }218 }
242 }219 }
243
244 startNextJob();
245}220}
246221
247void NotesStore::refreshNoteContent(const QString &guid)222void NotesStore::refreshNoteContent(const QString &guid)
248{223{
249 if (m_token.isEmpty()) {
250 qWarning() << "No token set. Cannot fetch note.";
251 return;
252 }
253
254 FetchNoteJob *job = new FetchNoteJob(guid, this);224 FetchNoteJob *job = new FetchNoteJob(guid, this);
255 connect(job, &FetchNoteJob::resultReady, this, &NotesStore::fetchNoteJobDone);225 connect(job, &FetchNoteJob::resultReady, this, &NotesStore::fetchNoteJobDone);
256 m_jobQueue.append(job);226 enqueue(job);
257
258 startJobQueue();
259}227}
260228
261void NotesStore::fetchNoteJobDone(ErrorCode errorCode, const evernote::edam::Note &result)229void NotesStore::fetchNoteJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result)
262{230{
263 if (errorCode != ErrorCodeNoError) {231 if (errorCode != ErrorCodeNoError) {
264 qWarning() << "Error fetching note:" << errorCode;232 qWarning() << "Error fetching note:" << errorMessage;
265 startNextJob();
266 return;233 return;
267 }234 }
268235
@@ -271,29 +238,19 @@
271 note->setTitle(QString::fromStdString(result.title));238 note->setTitle(QString::fromStdString(result.title));
272 note->setContent(QString::fromStdString(result.content));239 note->setContent(QString::fromStdString(result.content));
273 emit noteChanged(note->guid());240 emit noteChanged(note->guid());
274
275 startNextJob();
276}241}
277242
278void NotesStore::refreshNotebooks()243void NotesStore::refreshNotebooks()
279{244{
280 if (m_token.isEmpty()) {
281 qWarning() << "No token set. Cannot refresh notebooks.";
282 return;
283 }
284
285 FetchNotebooksJob *job = new FetchNotebooksJob();245 FetchNotebooksJob *job = new FetchNotebooksJob();
286 connect(job, &FetchNotebooksJob::resultReady, this, &NotesStore::fetchNotebooksJobDone);246 connect(job, &FetchNotebooksJob::jobDone, this, &NotesStore::fetchNotebooksJobDone);
287247 enqueue(job);
288 m_jobQueue.append(job);
289 startJobQueue();
290}248}
291249
292void NotesStore::fetchNotebooksJobDone(ErrorCode errorCode, const std::vector<evernote::edam::Notebook> &results)250void NotesStore::fetchNotebooksJobDone(ErrorCode errorCode, const QString &errorMessage, const std::vector<evernote::edam::Notebook> &results)
293{251{
294 if (errorCode != ErrorCodeNoError) {252 if (errorCode != ErrorCodeNoError) {
295 qWarning() << "Error fetching notebooks:" << errorCodeToString(errorCode);253 qWarning() << "Error fetching notebooks:" << errorMessage;
296 startNextJob();
297 return;254 return;
298 }255 }
299256
@@ -312,51 +269,72 @@
312 qDebug() << "got new notebook" << notebook->guid();269 qDebug() << "got new notebook" << notebook->guid();
313 }270 }
314 }271 }
315
316 startNextJob();
317}272}
318273
319void NotesStore::createNote(const QString &title, const QString &notebookGuid, const QString &content)274void NotesStore::createNote(const QString &title, const QString &notebookGuid, const QString &content)
320{275{
321 Note *note = new Note();276 CreateNoteJob *job = new CreateNoteJob(title, notebookGuid, content);
322 note->setTitle(title);277 connect(job, &CreateNoteJob::jobDone, this, &NotesStore::createNoteJobDone);
323 note->setNotebookGuid(notebookGuid);278 enqueue(job);
324 note->setContent(content);
325 CreateNoteJob *job = new CreateNoteJob(note);
326 connect(job, &CreateNoteJob::resultReady, this, &NotesStore::createNoteJobDone);
327
328 m_jobQueue.append(job);
329 startJobQueue();
330}279}
331280
332void NotesStore::createNoteJobDone(NotesStore::ErrorCode errorCode, Note *note)281void NotesStore::createNoteJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result)
333{282{
334 if (errorCode != ErrorCodeNoError) {283 if (errorCode != ErrorCodeNoError) {
335 qWarning() << "Error creating note:" << errorCodeToString(errorCode);284 qWarning() << "Error creating note:" << errorMessage;
336 delete note;
337 startNextJob();
338 return;285 return;
339 }286 }
340287
288 Note *note = new Note(QString::fromStdString(result.guid));
289 note->setNotebookGuid(QString::fromStdString(result.notebookGuid));
290 note->setTitle(QString::fromStdString(result.title));
291 note->setContent(QString::fromStdString(result.content));
292
341 m_notes.insert(note->guid(), note);293 m_notes.insert(note->guid(), note);
342 noteAdded(note->guid());294 noteAdded(note->guid());
343 startNextJob();295}
344}296
345297void NotesStore::saveNote(const QString &guid)
346void NotesStore::saveNoteJobDone(NotesStore::ErrorCode errorCode, Note *note)298{
347{299 Note *note = m_notes.value(guid);
348 startNextJob();300
349}301 QString enml = Html2EnmlConverter::html2enml(note->content());
350302 note->setContent(enml);
351void NotesStore::deleteNoteJobDone(NotesStore::ErrorCode errorCode, const QString &guid)303
352{304 SaveNoteJob *job = new SaveNoteJob(note, this);
353 if (errorCode != ErrorCodeNoError) {305 connect(job, &SaveNoteJob::jobDone, this, &NotesStore::saveNoteJobDone);
354 qWarning() << "Cannot delete note:" << errorCodeToString(errorCode);306 enqueue(job);
355 startNextJob();307}
308
309void NotesStore::saveNoteJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result)
310{
311 if (errorCode != ErrorCodeNoError) {
312 qWarning() << "error saving note" << errorMessage;
313 return;
314 }
315
316 Note *note = m_notes.value(QString::fromStdString(result.guid));
317 if (note) {
318 note->setTitle(QString::fromStdString(result.title));
319 note->setNotebookGuid(QString::fromStdString(result.notebookGuid));
320
321 emit noteChanged(note->guid());
322 }
323}
324
325void NotesStore::deleteNote(const QString &guid)
326{
327 DeleteNoteJob *job = new DeleteNoteJob(guid, this);
328 connect(job, &DeleteNoteJob::jobDone, this, &NotesStore::deleteNoteJobDone);
329 enqueue(job);
330}
331
332void NotesStore::deleteNoteJobDone(NotesStore::ErrorCode errorCode, const QString &errorMessage, const QString &guid)
333{
334 if (errorCode != ErrorCodeNoError) {
335 qWarning() << "Cannot delete note:" << errorMessage;
356 return;336 return;
357 }337 }
358 emit noteRemoved(guid);338 emit noteRemoved(guid);
359 m_notes.take(guid)->deleteLater();339 m_notes.take(guid)->deleteLater();
360 startNextJob();
361}340}
362
363341
=== modified file 'src/plugin/Evernote/notesstore.h'
--- src/plugin/Evernote/notesstore.h 2013-11-25 00:49:48 +0000
+++ src/plugin/Evernote/notesstore.h 2013-11-27 21:48:53 +0000
@@ -1,6 +1,9 @@
1#ifndef NOTESSTORE_H1#ifndef NOTESSTORE_H
2#define NOTESSTORE_H2#define NOTESSTORE_H
33
4// Thrift
5#include <transport/THttpClient.h>
6
4// Evernote SDK7// Evernote SDK
5#include <NoteStore.h>8#include <NoteStore.h>
6#include <NoteStore_constants.h>9#include <NoteStore_constants.h>
@@ -14,6 +17,8 @@
14class Notebook;17class Notebook;
15class Note;18class Note;
1619
20using namespace apache::thrift::transport;
21
17class NotesStore : public QObject22class NotesStore : public QObject
18{23{
19 Q_OBJECT24 Q_OBJECT
@@ -63,14 +68,19 @@
63 void notebookChanged(const QString &guid);68 void notebookChanged(const QString &guid);
6469
65private slots:70private slots:
66 void fetchNotesJobDone(ErrorCode errorCode, const evernote::edam::NotesMetadataList &results);71 void fetchNotesJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::NotesMetadataList &results);
67 void fetchNotebooksJobDone(ErrorCode errorCode, const std::vector<evernote::edam::Notebook> &results);72 void fetchNotebooksJobDone(ErrorCode errorCode, const QString &errorMessage, const std::vector<evernote::edam::Notebook> &results);
68 void fetchNoteJobDone(ErrorCode errorCode, const evernote::edam::Note &result);73 void fetchNoteJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result);
69 void createNoteJobDone(ErrorCode errorCode, Note *note);74 void createNoteJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result);
70 void saveNoteJobDone(ErrorCode errorCode, Note *note);75 void saveNoteJobDone(ErrorCode errorCode, const QString &errorMessage, const evernote::edam::Note &result);
71 void deleteNoteJobDone(ErrorCode errorCode, const QString &guid);76 void deleteNoteJobDone(ErrorCode errorCode, const QString &errorMessage, const QString &guid);
7277
78 // Use this to enqueue a new job. It will automatically start it if there is no other job pending.
79 void enqueue(EvernoteJob *job);
73 void startJobQueue();80 void startJobQueue();
81
82 // You should not use this. It's called by the job queue.
83 // If you have a new job to run, just enqueue it. The queue will process it eventually.
74 void startNextJob();84 void startNextJob();
7585
76private:86private:
@@ -78,13 +88,21 @@
78 static NotesStore *s_instance;88 static NotesStore *s_instance;
7989
80 QString m_token;90 QString m_token;
81 evernote::edam::NoteStoreClient *m_client;
8291
83 QHash<QString, Notebook*> m_notebooks;92 QHash<QString, Notebook*> m_notebooks;
84 QHash<QString, Note*> m_notes;93 QHash<QString, Note*> m_notes;
8594
95 // There must be only one job running at a time
96 // Do not start jobs other than with startJobQueue()
86 QList<EvernoteJob*> m_jobQueue;97 QList<EvernoteJob*> m_jobQueue;
87 QThread *m_currentJob;98 EvernoteJob *m_currentJob;
99
100 // Those two are accessed from the job thread.
101 // Make sure to not access them while any jobs are running
102 // or we need to mutex them.
103 evernote::edam::NoteStoreClient *m_client;
104 boost::shared_ptr<THttpClient> m_httpClient;
105
88};106};
89107
90#endif // NOTESSTORE_H108#endif // NOTESSTORE_H

Subscribers

People subscribed via source and target branches