From bbb581bc9c2a2bfd91c8bbbae42ccd7f9901268a Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Fri, 14 Apr 2017 19:37:39 +0100 Subject: [PATCH] Cloud Auto Download - 2 of 3 .. background download management, adds to the ride list .. next commit needs to fixup GUI notifications etc. --- src/Cloud/CloudService.cpp | 211 ++++++++++++++++++++++++++++++++++++- src/Cloud/CloudService.h | 21 ++++ 2 files changed, 230 insertions(+), 2 deletions(-) diff --git a/src/Cloud/CloudService.cpp b/src/Cloud/CloudService.cpp index beca86e4e..67055e267 100644 --- a/src/Cloud/CloudService.cpp +++ b/src/Cloud/CloudService.cpp @@ -1597,9 +1597,216 @@ CloudServiceAutoDownload::run() // we notify the main gui via the usual signals. context->notifyAutoDownloadStart(); - // do stuff... progress is 0-100% - context->notifyAutoDownloadProgress(100); + // get a list of services to sync from + QStringList worklist; + foreach(QString name, CloudServiceFactory::instance().serviceNames()) { + if (appsettings->cvalue(context->athlete->cyclist, CloudServiceFactory::instance().service(name)->syncOnStartupSettingName(), "false").toString() == "true") { + worklist << name; + } + } + // update progress indicator + context->notifyAutoDownloadProgress(0.0f); + + // + // generate a worklist to process + // + if (worklist.count()) { + + // workthrough + for(int i=0; iopen(errors) == false) { + delete service; + continue; + } + + // get list of entries + QDateTime now = QDateTime::currentDateTime(); + QList found = service->readdir(service->home(), errors, now.addDays(-30), now); + + // some were found, so lets see if they match + if (found.count()) { + + QStringList rideFiles; // what we have already + + Specification specification; + specification.setDateRange(DateRange(now.addDays(-30).date(), now.date())); + foreach(RideItem *item, context->athlete->rideCache->rides()) { + if (specification.pass(item)) + rideFiles << QFileInfo(item->fileName).baseName().mid(0,16); + } + + // eliminate matches + bool need=false; + foreach(CloudServiceEntry *entry, found) { + + QDateTime ridedatetime; + + // skip files that aren't ride files + if (!RideFile::parseRideFileName(entry->name, &ridedatetime)) continue; + + // skip files that aren't in range + if (ridedatetime.date() < now.addDays(-30).date() || ridedatetime.date() > now.date()) continue; + + // skip files we already have + bool got=false; + foreach(QString name, rideFiles) + if (entry->name.startsWith(name)) + got=true; + + // we want it ! + if (!got) { + need = true; // need to download, so don't zap the service + + CloudServiceDownloadEntry add; + add.state = CloudServiceDownloadEntry::Pending; + add.entry = entry; + add.provider = service; + downloadlist << add; + } + } + + if (!need) { + + // none found that we need + service->close(); + delete service; + } else { + providers << service; // so we can clean up later + } + + } else { + + // none found + service->close(); + delete service; + } + } + } + + // + // Worker loop to process the list, blocking on each download + // and timeout if no response in 30 seconds for each + // + // Since this is asynchronous, the actual data is processed + // by the receivedFile method + // + + double progress=0; + double inc = 100.0f / double(downloadlist.count()); + for(int i=0; ireadFile(downloadlist[i].data, download.entry->name, download.entry->id); + + // block on timeout or readComplete... + loop.exec(); + + // notify progress + context->notifyAutoDownloadProgress(progress += inc); + } + + // all done, close the sync notification + context->notifyAutoDownloadProgress(100); context->notifyAutoDownloadEnd(); + + // remove providers + foreach(CloudService *s, providers) { + s->close(); + delete s; + } + + // in case we restart + providers.clear(); + downloadlist.clear(); + + // and end thread exit(0); } + +void +CloudServiceAutoDownload::readComplete(QByteArray*data,QString name,QString status) +{ + qDebug()<<"received:"<uncompressRide(data, name, errors); + + // free up regardless + delete data; + + // can't process the content received. + if (ride == NULL) return; + + // lets save this one away as json with the right filename + QDateTime ridedatetime = ride->startTime(); + + QChar zero = QLatin1Char ('0'); + QString targetnosuffix = QString ( "%1_%2_%3_%4_%5_%6" ) + .arg ( ridedatetime.date().year(), 4, 10, zero ) + .arg ( ridedatetime.date().month(), 2, 10, zero ) + .arg ( ridedatetime.date().day(), 2, 10, zero ) + .arg ( ridedatetime.time().hour(), 2, 10, zero ) + .arg ( ridedatetime.time().minute(), 2, 10, zero ) + .arg ( ridedatetime.time().second(), 2, 10, zero ); + + QString filename = context->athlete->home->activities().canonicalPath() + "/" + targetnosuffix + ".json"; + + // exists? -- totally should never happen unless readdir timestamp mismatches actual ride + // could happen if same file available at two services XXX should check above... XXX + QFileInfo fileinfo(filename); + if (fileinfo.exists()) { + qDebug()<<"auto download got a duplicate:"<athlete->addRide(fileinfo.fileName(), true); + +} diff --git a/src/Cloud/CloudService.h b/src/Cloud/CloudService.h index e85e76c71..2e1b3a23b 100644 --- a/src/Cloud/CloudService.h +++ b/src/Cloud/CloudService.h @@ -427,6 +427,15 @@ class CloudServiceEntry } }; +struct CloudServiceDownloadEntry { + + CloudServiceEntry *entry; + QByteArray *data; + CloudService *provider; + enum { Pending, InProgress, Failed, Complete } state; + +}; + class CloudServiceAutoDownload : public QThread { Q_OBJECT @@ -438,13 +447,25 @@ class CloudServiceAutoDownload : public QThread { public slots: + // external entry point to trigger auto download void autoDownload(); + + // thread worker to generate download requests void run(); + // receiver for downloaded files to add to the ridecache + void readComplete(QByteArray*,QString,QString); + private: Context *context; bool initial; + + // list of files to download + QList downloadlist; + + // list of providers - so we can clean up + QList providers; }; // all cloud services register at startup and can be accessed by name