Skip to content

Latest commit

 

History

History
466 lines (413 loc) · 15.8 KB

socialnetworksyncadaptor.cpp

File metadata and controls

466 lines (413 loc) · 15.8 KB
 
Jun 24, 2013
Jun 24, 2013
1
2
/****************************************************************************
**
Jun 13, 2014
Jun 13, 2014
3
** Copyright (C) 2013-2014 Jolla Ltd.
Jun 24, 2013
Jun 24, 2013
4
5
** Contact: Chris Adams <chris.adams@jollamobile.com>
**
Jun 13, 2014
Jun 13, 2014
6
7
8
9
10
11
12
13
14
15
16
17
18
19
** This program/library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public License
** version 2.1 as published by the Free Software Foundation.
**
** This program/library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this program/library; if not, write to the Free
** Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
** 02110-1301 USA
**
Jun 24, 2013
Jun 24, 2013
20
****************************************************************************/
21
22
#include "socialnetworksyncadaptor.h"
Jan 2, 2014
Jan 2, 2014
23
#include "socialdnetworkaccessmanager_p.h"
24
25
#include "trace.h"
Aug 29, 2013
Aug 29, 2013
26
#include <QtCore/QJsonDocument>
Apr 1, 2014
Apr 1, 2014
27
#include <QtCore/QTimer>
28
29
30
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
Aug 19, 2013
Aug 19, 2013
31
#include <QtSql/QSqlRecord>
Jun 24, 2013
Jun 24, 2013
33
#include <QtNetwork/QNetworkAccessManager>
Apr 1, 2014
Apr 1, 2014
34
#include <QtNetwork/QNetworkReply>
Jun 24, 2013
Jun 24, 2013
35
Apr 7, 2014
Apr 7, 2014
36
#include "buteosyncfw_p.h"
Apr 7, 2014
Apr 7, 2014
37
Jun 10, 2014
Jun 10, 2014
38
39
40
41
// libaccounts-qt5
#include <Accounts/Manager>
#include <Accounts/Account>
#include <Accounts/Service>
Jun 24, 2013
Jun 24, 2013
42
Apr 7, 2014
Apr 7, 2014
43
// libsocialcache
May 21, 2019
May 21, 2019
44
45
#include <socialcache/socialimagesdatabase.h>
#include <socialcache/socialnetworksyncdatabase.h>
Sep 29, 2013
Sep 29, 2013
46
Apr 7, 2014
Apr 7, 2014
47
48
49
50
51
52
53
54
55
56
57
namespace {
QStringList validDataTypesInitialiser()
{
return QStringList()
<< QStringLiteral("Contacts")
<< QStringLiteral("Calendars")
<< QStringLiteral("Notifications")
<< QStringLiteral("Images")
<< QStringLiteral("Videos")
<< QStringLiteral("Posts")
<< QStringLiteral("Messages")
Apr 16, 2014
Apr 16, 2014
58
59
<< QStringLiteral("Emails")
<< QStringLiteral("Signon");
Apr 7, 2014
Apr 7, 2014
60
61
62
63
64
}
}
SocialNetworkSyncAdaptor::SocialNetworkSyncAdaptor(const QString &serviceName,
SocialNetworkSyncAdaptor::DataType dataType,
Nov 13, 2015
Nov 13, 2015
65
QNetworkAccessManager *qnam,
Apr 7, 2014
Apr 7, 2014
66
QObject *parent)
Jun 24, 2013
Jun 24, 2013
67
: QObject(parent)
Jan 9, 2015
Jan 9, 2015
68
69
, m_dataType(dataType)
, m_accountManager(new Accounts::Manager(this))
Nov 13, 2015
Nov 13, 2015
70
, m_networkAccessManager(qnam != 0 ? qnam : new SocialdNetworkAccessManager)
Apr 7, 2014
Apr 7, 2014
71
, m_accountSyncProfile(NULL)
Sep 29, 2013
Sep 29, 2013
72
, m_syncDb(new SocialNetworkSyncDatabase())
Jun 24, 2013
Jun 24, 2013
73
, m_status(SocialNetworkSyncAdaptor::Invalid)
Apr 20, 2015
Apr 20, 2015
74
75
, m_enabled(false)
, m_syncAborted(false)
Jun 24, 2013
Jun 24, 2013
76
, m_serviceName(serviceName)
77
78
79
80
81
{
}
SocialNetworkSyncAdaptor::~SocialNetworkSyncAdaptor()
{
Nov 13, 2015
Nov 13, 2015
82
delete m_networkAccessManager;
Apr 7, 2014
Apr 7, 2014
83
delete m_accountSyncProfile;
Sep 29, 2013
Sep 29, 2013
84
delete m_syncDb;
85
86
}
Apr 7, 2014
Apr 7, 2014
87
88
89
90
// The SocialNetworkSyncAdaptor takes ownership of the sync profiles.
void SocialNetworkSyncAdaptor::setAccountSyncProfile(Buteo::SyncProfile* perAccountSyncProfile)
{
delete m_accountSyncProfile;
Jan 9, 2015
Jan 9, 2015
91
m_accountSyncProfile = perAccountSyncProfile;
Apr 7, 2014
Apr 7, 2014
92
93
}
94
95
96
97
98
99
100
101
102
103
SocialNetworkSyncAdaptor::Status SocialNetworkSyncAdaptor::status() const
{
return m_status;
}
bool SocialNetworkSyncAdaptor::enabled() const
{
return m_enabled;
}
Jun 24, 2013
Jun 24, 2013
104
QString SocialNetworkSyncAdaptor::serviceName() const
Jun 24, 2013
Jun 24, 2013
105
106
107
108
{
return m_serviceName;
}
Apr 20, 2015
Apr 20, 2015
109
110
111
112
113
bool SocialNetworkSyncAdaptor::syncAborted() const
{
return m_syncAborted;
}
Apr 7, 2014
Apr 7, 2014
114
void SocialNetworkSyncAdaptor::sync(const QString &dataType, int accountId)
115
116
{
Q_UNUSED(dataType)
Apr 7, 2014
Apr 7, 2014
117
Q_UNUSED(accountId)
Jan 9, 2015
Jan 9, 2015
118
SOCIALD_LOG_ERROR("sync() must be overridden by derived types");
119
120
}
Apr 20, 2015
Apr 20, 2015
121
122
123
124
125
126
127
void SocialNetworkSyncAdaptor::abortSync(Sync::SyncStatus status)
{
SOCIALD_LOG_INFO("forcing timeout of outstanding replies due to abort:" << status);
m_syncAborted = true;
triggerReplyTimeouts();
}
Apr 7, 2014
Apr 7, 2014
128
129
130
131
132
133
134
135
/*!
* \brief SocialNetworkSyncAdaptor::checkAccount
* \param account
* \return true if synchronization of this adaptor's datatype is enabled for the account
*
* The default implementation checks that the account is enabled
* with the accounts&sso service associated with this sync adaptor.
*/
Jun 10, 2014
Jun 10, 2014
136
bool SocialNetworkSyncAdaptor::checkAccount(Accounts::Account *account)
Apr 7, 2014
Apr 7, 2014
137
{
Jun 10, 2014
Jun 10, 2014
138
bool globallyEnabled = account->enabled();
Jan 9, 2015
Jan 9, 2015
139
Accounts::Service srv(m_accountManager->service(syncServiceName()));
Jun 10, 2014
Jun 10, 2014
140
if (!srv.isValid()) {
Jan 9, 2015
Jan 9, 2015
141
142
SOCIALD_LOG_INFO("invalid service" << syncServiceName() <<
"specified, account" << account->id() <<
Jan 9, 2015
Jan 9, 2015
143
"will be disabled for" << m_serviceName << dataTypeName(m_dataType) << "sync");
Jun 10, 2014
Jun 10, 2014
144
145
146
147
148
149
return false;
}
account->selectService(srv);
bool serviceEnabled = account->enabled();
account->selectService(Accounts::Service());
return globallyEnabled && serviceEnabled;
Apr 7, 2014
Apr 7, 2014
150
151
}
Nov 13, 2013
Nov 13, 2013
152
153
154
155
156
157
158
159
160
161
162
/*!
\internal
Called when the semaphores for all accounts have been decreased
to zero. This is the final function which is called prior to
telling buteo that the sync plugin can be destroyed.
The implementation MUST be synchronous.
*/
void SocialNetworkSyncAdaptor::finalCleanup()
{
}
Sep 26, 2013
Sep 26, 2013
163
164
165
166
/*!
\internal
Called when the semaphores decreased to 0, this method is used
to finalize something, like saving all data to a database.
Oct 17, 2013
Oct 17, 2013
167
168
169
170
171
172
173
174
175
176
177
178
179
You can call incrementSemaphore to perform asynchronous tasks
in this method. finalize will then be called again when the
asynchronous task is finished (and when decrementSemaphore is
called), be sure to have a condition check in order not to run
into an infinite loop.
It is unsafe to call decrementSemaphore in this method, as
the semaphore handling method will find that the semaphore
went to 0 twice and will perform cleanup operations twice.
Please call decrementSemaphore at the end of the asynchronous
task (preferably in a slot), and only call incrementSemaphore
for asynchronous tasks.
Sep 26, 2013
Sep 26, 2013
180
*/
Oct 17, 2013
Oct 17, 2013
181
void SocialNetworkSyncAdaptor::finalize(int accountId)
Sep 26, 2013
Sep 26, 2013
182
{
Oct 17, 2013
Oct 17, 2013
183
Q_UNUSED(accountId)
Sep 26, 2013
Sep 26, 2013
184
185
}
186
187
188
189
190
191
/*!
\internal
Returns the last sync timestamp for the given service, account and data type.
If data from prior to this timestamp is received in subsequent requests, it does not need to be synced.
This function will return an invalid QDateTime if no synchronisation has occurred.
*/
Sep 29, 2013
Sep 29, 2013
192
193
194
QDateTime SocialNetworkSyncAdaptor::lastSyncTimestamp(const QString &serviceName,
const QString &dataType,
int accountId) const
195
{
Sep 29, 2013
Sep 29, 2013
196
return m_syncDb->lastSyncTimestamp(serviceName, dataType, accountId);
197
198
199
200
201
202
}
/*!
\internal
Updates the last sync timestamp for the given service, account and data type to the given \a timestamp.
*/
Sep 29, 2013
Sep 29, 2013
203
204
205
206
bool SocialNetworkSyncAdaptor::updateLastSyncTimestamp(const QString &serviceName,
const QString &dataType,
int accountId,
const QDateTime &timestamp)
207
{
Sep 29, 2013
Sep 29, 2013
208
209
210
// Workaround
// TODO: do better, with a queue
m_syncDb->addSyncTimestamp(serviceName, dataType, accountId, timestamp);
Dec 5, 2013
Dec 5, 2013
211
212
213
m_syncDb->commit();
m_syncDb->wait();
return m_syncDb->writeStatus() == AbstractSocialCacheDatabase::Finished;
214
215
216
}
/*!
Aug 19, 2013
Aug 19, 2013
217
218
\internal
Returns the list of identifiers of accounts which have been synced for
Oct 3, 2013
Oct 3, 2013
219
the given \a dataType.
220
*/
Oct 3, 2013
Oct 3, 2013
221
QList<int> SocialNetworkSyncAdaptor::syncedAccounts(const QString &dataType)
222
{
Oct 3, 2013
Oct 3, 2013
223
return m_syncDb->syncedAccounts(m_serviceName, dataType);
224
225
}
Jun 24, 2013
Jun 24, 2013
226
227
228
229
/*!
* \internal
* Changes status if there is real change and emits statusChanged() signal.
*/
Aug 19, 2013
Aug 19, 2013
230
void SocialNetworkSyncAdaptor::setStatus(Status status)
Jun 24, 2013
Jun 24, 2013
231
232
233
234
235
236
{
if (m_status != status) {
m_status = status;
emit statusChanged();
}
}
Aug 19, 2013
Aug 19, 2013
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*!
* \internal
* Should be used in constructors to set the initial state
* of enabled and status, without emitting signals
*
*/
void SocialNetworkSyncAdaptor::setInitialActive(bool enabled)
{
m_enabled = enabled;
if (enabled) {
m_status = Inactive;
} else {
m_status = Invalid;
}
}
Sep 17, 2013
Sep 17, 2013
254
255
256
257
258
259
260
261
262
263
/*!
* \internal
* Should be called by any specific sync adapter when
* they've finished syncing data. The transition from
* busy status to inactive status is what causes the
* Buteo plugin to emit the sync results (and allows
* subsequent syncs to occur).
*/
void SocialNetworkSyncAdaptor::setFinishedInactive()
{
Nov 13, 2013
Nov 13, 2013
264
finalCleanup();
Jan 9, 2015
Jan 9, 2015
265
SOCIALD_LOG_INFO("Finished" << m_serviceName << SocialNetworkSyncAdaptor::dataTypeName(m_dataType) <<
Jan 9, 2015
Jan 9, 2015
266
"sync at:" << QDateTime::currentDateTime().toString(Qt::ISODate));
Sep 17, 2013
Sep 17, 2013
267
268
269
setStatus(SocialNetworkSyncAdaptor::Inactive);
}
Aug 19, 2013
Aug 19, 2013
270
271
272
273
274
void SocialNetworkSyncAdaptor::incrementSemaphore(int accountId)
{
int semaphoreValue = m_accountSyncSemaphores.value(accountId);
semaphoreValue += 1;
m_accountSyncSemaphores.insert(accountId, semaphoreValue);
Jan 9, 2015
Jan 9, 2015
275
SOCIALD_LOG_DEBUG("incremented busy semaphore for account" << accountId << "to:" << semaphoreValue);
Aug 19, 2013
Aug 19, 2013
276
277
278
279
280
}
void SocialNetworkSyncAdaptor::decrementSemaphore(int accountId)
{
if (!m_accountSyncSemaphores.contains(accountId)) {
Jan 9, 2015
Jan 9, 2015
281
SOCIALD_LOG_ERROR("no such semaphore for account" << accountId);
Aug 19, 2013
Aug 19, 2013
282
283
284
285
286
return;
}
int semaphoreValue = m_accountSyncSemaphores.value(accountId);
semaphoreValue -= 1;
Jan 9, 2015
Jan 9, 2015
287
SOCIALD_LOG_DEBUG("decremented busy semaphore for account" << accountId << "to:" << semaphoreValue);
Aug 19, 2013
Aug 19, 2013
288
if (semaphoreValue < 0) {
Jan 9, 2015
Jan 9, 2015
289
SOCIALD_LOG_ERROR("busy semaphore is negative for account" << accountId);
Aug 19, 2013
Aug 19, 2013
290
291
292
293
294
return;
}
m_accountSyncSemaphores.insert(accountId, semaphoreValue);
if (semaphoreValue == 0) {
Oct 17, 2013
Oct 17, 2013
295
296
297
298
299
300
301
302
finalize(accountId);
// With the newer implementation, in finalize we can rereaise semaphores,
// so if after calling finalize, the semaphore count is not the same anymore,
// we shouldn't update the sync timestamp
if (m_accountSyncSemaphores.value(accountId) > 0) {
return;
}
Sep 26, 2013
Sep 26, 2013
303
Aug 21, 2013
Aug 21, 2013
304
305
// finished all outstanding sync requests for this account.
// update the sync time in the global sociald database.
Aug 19, 2013
Aug 19, 2013
306
updateLastSyncTimestamp(m_serviceName,
Jan 9, 2015
Jan 9, 2015
307
SocialNetworkSyncAdaptor::dataTypeName(m_dataType), accountId,
Aug 21, 2013
Aug 21, 2013
308
QDateTime::currentDateTime().toTimeSpec(Qt::UTC));
Aug 19, 2013
Aug 19, 2013
309
310
311
312
313
314
315
316
317
318
319
320
321
// if all outstanding requests for all accounts have finished,
// then update our status to Inactive / ready to handle more sync requests.
bool allAreZero = true;
QList<int> semaphores = m_accountSyncSemaphores.values();
foreach (int sv, semaphores) {
if (sv != 0) {
allAreZero = false;
break;
}
}
if (allAreZero) {
Sep 17, 2013
Sep 17, 2013
322
setFinishedInactive(); // Finished!
Aug 19, 2013
Aug 19, 2013
323
324
325
}
}
}
Aug 29, 2013
Aug 29, 2013
326
Apr 1, 2014
Apr 1, 2014
327
328
329
330
331
332
void SocialNetworkSyncAdaptor::timeoutReply()
{
QTimer *timer = qobject_cast<QTimer*>(sender());
QNetworkReply *reply = timer->property("networkReply").value<QNetworkReply*>();
int accountId = timer->property("accountId").toInt();
Jan 9, 2015
Jan 9, 2015
333
SOCIALD_LOG_ERROR("network request timed out while performing sync with account" << accountId);
Apr 1, 2014
Apr 1, 2014
334
Apr 30, 2014
Apr 30, 2014
335
336
337
338
m_networkReplyTimeouts[accountId].remove(reply);
reply->setProperty("isError", QVariant::fromValue<bool>(true));
reply->finished(); // invoke finished, so that the error handling there decrements the semaphore etc.
reply->disconnect();
Apr 1, 2014
Apr 1, 2014
339
340
}
Oct 16, 2015
Oct 16, 2015
341
void SocialNetworkSyncAdaptor::setupReplyTimeout(int accountId, QNetworkReply *reply, int msecs)
Apr 1, 2014
Apr 1, 2014
342
343
344
345
{
// this function should be called whenever a new network request is performed.
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
Oct 16, 2015
Oct 16, 2015
346
timer->setInterval(msecs);
Apr 1, 2014
Apr 1, 2014
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
timer->setProperty("accountId", accountId);
timer->setProperty("networkReply", QVariant::fromValue<QNetworkReply*>(reply));
connect(timer, SIGNAL(timeout()), this, SLOT(timeoutReply()));
timer->start();
m_networkReplyTimeouts[accountId].insert(reply, timer);
}
void SocialNetworkSyncAdaptor::removeReplyTimeout(int accountId, QNetworkReply *reply)
{
// this function should be called by the finished() handler for the reply.
QTimer *timer = m_networkReplyTimeouts[accountId].value(reply);
if (!reply) {
return;
}
delete timer;
m_networkReplyTimeouts[accountId].remove(reply);
}
Apr 20, 2015
Apr 20, 2015
366
367
368
369
370
371
372
373
374
375
376
377
void SocialNetworkSyncAdaptor::triggerReplyTimeouts()
{
// if we've lost network connectivity, we should immediately timeout all replies.
Q_FOREACH (int accountId, m_networkReplyTimeouts.keys()) {
Q_FOREACH (QTimer *timer, m_networkReplyTimeouts[accountId]) {
timer->stop();
timer->setInterval(1);
timer->start();
}
}
}
Aug 29, 2013
Aug 29, 2013
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
QJsonObject SocialNetworkSyncAdaptor::parseJsonObjectReplyData(const QByteArray &replyData, bool *ok)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(replyData);
*ok = !jsonDocument.isEmpty();
if (*ok && jsonDocument.isObject()) {
return jsonDocument.object();
}
*ok = false;
return QJsonObject();
}
QJsonArray SocialNetworkSyncAdaptor::parseJsonArrayReplyData(const QByteArray &replyData, bool *ok)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(replyData);
*ok = !jsonDocument.isEmpty();
if (*ok && jsonDocument.isArray()) {
return jsonDocument.array();
}
*ok = false;
return QJsonArray();
}
Apr 7, 2014
Apr 7, 2014
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/*
Valid data types are data types which are known to the API.
Note that just because a data type is valid does not mean
that it will necessarily be supported by a given social network
sync adaptor.
*/
QStringList SocialNetworkSyncAdaptor::validDataTypes()
{
static QStringList retn(validDataTypesInitialiser());
return retn;
}
/*
String for Enum since the DBus API uses strings
*/
QString SocialNetworkSyncAdaptor::dataTypeName(SocialNetworkSyncAdaptor::DataType t)
{
switch (t) {
case SocialNetworkSyncAdaptor::Contacts: return QStringLiteral("Contacts");
case SocialNetworkSyncAdaptor::Calendars: return QStringLiteral("Calendars");
case SocialNetworkSyncAdaptor::Notifications: return QStringLiteral("Notifications");
case SocialNetworkSyncAdaptor::Images: return QStringLiteral("Images");
case SocialNetworkSyncAdaptor::Videos: return QStringLiteral("Videos");
case SocialNetworkSyncAdaptor::Posts: return QStringLiteral("Posts");
case SocialNetworkSyncAdaptor::Messages: return QStringLiteral("Messages");
case SocialNetworkSyncAdaptor::Emails: return QStringLiteral("Emails");
Apr 16, 2014
Apr 16, 2014
426
case SocialNetworkSyncAdaptor::Signon: return QStringLiteral("Signon");
Oct 9, 2015
Oct 9, 2015
427
case SocialNetworkSyncAdaptor::Backup: return QStringLiteral("Backup");
Apr 7, 2014
Apr 7, 2014
428
429
430
431
432
default: break;
}
return QString();
}
Jul 15, 2015
Jul 15, 2015
433
434
435
436
437
438
439
440
441
void SocialNetworkSyncAdaptor::purgeCachedImages(SocialImagesDatabase *database,
int accountId)
{
database->queryImages(accountId);
database->wait();
QList<SocialImage::ConstPtr> images = database->images();
foreach (SocialImage::ConstPtr image, images) {
Sep 1, 2015
Sep 1, 2015
442
SOCIALD_LOG_DEBUG("Purge cached image " << image->imageFile() << " for account " << image->accountId());
Jul 15, 2015
Jul 15, 2015
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
QFile::remove(image->imageFile());
}
database->removeImages(images);
database->commit();
database->wait();
}
void SocialNetworkSyncAdaptor::purgeExpiredImages(SocialImagesDatabase *database,
int accountId)
{
database->queryExpired(accountId);
database->wait();
QList<SocialImage::ConstPtr> images = database->images();
foreach (SocialImage::ConstPtr image, images) {
Sep 1, 2015
Sep 1, 2015
459
SOCIALD_LOG_DEBUG("Purge expired image " << image->imageFile() << " for account " << image->accountId());
Jul 15, 2015
Jul 15, 2015
460
461
462
463
464
465
466
QFile::remove(image->imageFile());
}
database->removeImages(images);
database->commit();
database->wait();
}