From: Konrad Rosenbaum Date: Sat, 20 Jul 2013 11:53:53 +0000 (+0200) Subject: aurora: download index X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=7e6328381dbf9b738dafb7647e21cfe0c146c131;p=konrad%2Ftaurus.git aurora: download index --- diff --git a/aurora.pri b/aurora.pri new file mode 100644 index 0000000..f6b4b1a --- /dev/null +++ b/aurora.pri @@ -0,0 +1,6 @@ +#include this into your qmake project file to +#use the ZIP library + +LIBS += -L$$PWD/lib -lAurora +INCLUDEPATH += $$PWD/include/aurora +CONFIG += link_prl \ No newline at end of file diff --git a/aurora/aurora.pro b/aurora/aurora.pro index 566187c..d9de6bb 100644 --- a/aurora/aurora.pro +++ b/aurora/aurora.pro @@ -11,9 +11,21 @@ RCC_DIR = .ctmp VERSION = 0.2.0 -SOURCES += src/aurora.cpp +SOURCES += \ + src/aurora.cpp \ + src/subtask.cpp -HEADERS += src/aurora.h +HEADERS += \ + src/aurora.h \ + src/subtask.h INCLUDEPATH += src -DEPENDPATH += $$INCLUDEPATH \ No newline at end of file +DEPENDPATH += $$INCLUDEPATH + +DEFINES += AURORA_LIBRARY_BUILD=1 +LIBS += -Lgpg/lib -lgpgme-pthread -lassuan -lgpg-error +INCLUDEPATH += gpg/include + +gcc { + QMAKE_CXXFLAGS += -std=gnu++11 +} \ No newline at end of file diff --git a/aurora/build-gpg.sh b/aurora/build-gpg.sh index 2a13096..5d939ee 100755 --- a/aurora/build-gpg.sh +++ b/aurora/build-gpg.sh @@ -1,3 +1,4 @@ +#!/bin/bash set -e fmake(){ @@ -47,3 +48,11 @@ fmake doc fmake tests make make install + + +#clean up and optimization +cd .. +rm gpg/bin/*-config +strip gpg/bin/* || true +echo +echo Done. diff --git a/aurora/src/aurora.cpp b/aurora/src/aurora.cpp index 6489e94..4c964a0 100644 --- a/aurora/src/aurora.cpp +++ b/aurora/src/aurora.cpp @@ -1,22 +1,28 @@ -// Copyright (C) 2012 by Konrad Rosenbaum +// Copyright (C) 2012-2013 by Konrad Rosenbaum // protected under the GNU LGPL version 3 or at your option any newer. // See COPYING.LGPL file that comes with this distribution. // #include "aurora.h" +#include "subtask.h" #include +#include +#include +#include #include #include -struct AuroraPrivate +struct AuroraUpdater::AuroraPrivate { AuroraPrivate(); - Aurora::State state; + Aurora::State state=Aurora::Initializing; QUrl url; - int pollint; - QTimer*polltmr; + QString indexfile; + int pollint=0; + QTimer*polltmr=nullptr; + QPointertask; bool isBlocking()const{return state!=Aurora::Initializing && state!=Aurora::Polling;} @@ -39,19 +45,23 @@ Aurora::~Aurora() static const QString AuroraGroup("aurora_updater"); AuroraPrivate::AuroraPrivate() - :state(Aurora::Initializing),pollint(0),polltmr(0) { QSettings cfg; cfg.beginGroup(AuroraGroup); url=cfg.value("baseurl").toUrl(); - pollint=cfg.value("pollintervall",0).toInt(); + indexfile=cfg.value("indexfile","auroraindex.xml").toString(); + pollint=cfg.value("pollinterval",0).toInt(); + qDebug()<<"Aurora: Initializing Auto-Updater. URL:"<url=u; + d->indexfile=idx; QSettings c;c.beginGroup(AuroraGroup); c.setValue("baseurl",u); + c.setValue("indexfile",idx); + qDebug()<<"Aurora: Changing URL to"<polltmr=0; if(!d->isBlocking()) d->state=Initializing; + qDebug()<<"Aurora: Stopping Timer."; + } + if(!d->url.isValid() || d->indexfile.isEmpty()){ + qDebug()<<"Aurora: no valid URL and/or index file, cannot poll."; + return; } if(d->pollint>0){ d->polltmr=new QTimer(this); connect(d->polltmr,SIGNAL(timeout()), this,SLOT(pollnow())); - d->polltmr->start(d->pollint); + d->polltmr->start(d->pollint*1000); if(!d->isBlocking()) d->state=Polling; - } + qDebug()<<"Aurora: Starting Timer."; + QTimer::singleShot(5,this,SLOT(pollnow())); + }else + qDebug()<<"Aurora: polling is deactivated, not starting."; } bool Aurora::isReadyForDownload() const @@ -113,9 +132,41 @@ bool Aurora::isReadyForInstall() const void Aurora::pollnow() { if(d->isBlocking()){ - qDebug()<<"missing an update poll cycle, in blocking mode"; + qDebug()<<"Aurora: missing an update poll cycle, still working on another one..."; + return; + } + qDebug()<<"Aurora: Polling for updates..."; + //start the web request + if(!d->task.isNull())d->task->deleteLater(); + QUrl u2(d->url); + const QString p=d->url.path(QUrl::FullyEncoded); + u2.setPath(p+"/"+d->indexfile,QUrl::StrictMode); + d->task=new SubTask(u2); + u2.setPath(p+"/"+d->indexfile+".asc",QUrl::StrictMode); + d->task->add(u2); + connect(d->task,SIGNAL(finished()),this,SLOT(checkMetaFile())); + connect(d->task,SIGNAL(error()),this,SLOT(abortCycle())); +} + + +void Aurora::checkMetaFile() +{ + if(d->task.isNull()){ + d->state=Polling; return; } + //TODO: verify signature + //extract info + qDebug()<<"Aurora: got Meta Data, not doing anything about it yet"; + d->task->deleteLater(); + d->state=Polling; +} + +void Aurora::abortCycle() +{ + qDebug()<<"Aurora: Aborting current poll cycle."; + if(!d->task.isNull())d->task->deleteLater(); + d->state=Polling; } void Aurora::startDownload() diff --git a/aurora/src/aurora.h b/aurora/src/aurora.h index ef2c4d9..2ae0373 100644 --- a/aurora/src/aurora.h +++ b/aurora/src/aurora.h @@ -10,21 +10,46 @@ #include #include +#ifdef AURORA_LIBRARY_BUILD +#define AURORA_EXPORT Q_DECL_EXPORT +#else +#define AURORA_EXPORT Q_DECL_IMPORT +#endif + +namespace AuroraUpdater { + class AuroraPrivate; -class Aurora:public QObject +/** The Aurora class is the main interface for the automatic updater. + * + * Normally you just instantiate it. You only need to set the base URL and the + * polling interval once - next time the instance will remember the settings. + * */ +class AURORA_EXPORT Aurora:public QObject { Q_OBJECT public: + ///instantiates the updater object, normally you should only need one of them explicit Aurora(QObject*parent=0); + ///deletes the updater object (stopping any update that is in progress) virtual ~Aurora(); + ///returns the currently set base URL QUrl baseUrl()const; + ///returns the name of the index file that contains meta data about releases, + ///the name of the signature file is inferred to be the same plus ".asc" + QString indexFileName()const; + ///State of the Updater object enum State{ + ///the instance is initializing Initializing=0, + ///the instance is currently polling for an update on meta data Polling=1, + ///the instance is currently verifying the meta data Checking=5, + ///the instance is downloading a new release Downloading=2, + ///the instance has verified ... Installing=3, PostInstall=4 }; @@ -44,7 +69,7 @@ class Aurora:public QObject int pollInterVall()const; public slots: - void setBaseUrl(QUrl); + void setBaseUrl(QUrl baseurl,QString indexfile); void startPoll(int intervalInSeconds=-1); void setPollIntervall(int seconds); void startDownload(); @@ -60,8 +85,15 @@ class Aurora:public QObject private slots: void pollnow(); + void abortCycle(); + void checkMetaFile(); private: AuroraPrivate *d; }; +//end of namespace +} + +using namespace AuroraUpdater; + #endif diff --git a/aurora/src/subtask.cpp b/aurora/src/subtask.cpp new file mode 100644 index 0000000..77e596a --- /dev/null +++ b/aurora/src/subtask.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2012-2013 by Konrad Rosenbaum +// protected under the GNU LGPL version 3 or at your option any newer. +// See COPYING.LGPL file that comes with this distribution. +// + +#include "subtask.h" +#include +#include +#include +#include + +bool AuroraUpdater::SubTask::add(QList< QUrl > urls) +{ + qDebug()<<"SubTask::add"<get(QNetworkRequest(url)); + mreq.insert(url,rep); + connect(rep,SIGNAL(finished()),this,SLOT(finishedReq())); + connect(rep,SIGNAL(error(QNetworkReply::NetworkError)), this,SLOT(errorReq())); + connect(rep,SIGNAL(readyRead()),this,SLOT(readFromNet())); + } + return true; +} + +void AuroraUpdater::SubTask::finishedReq() +{ +// qDebug()<<"SubTask::finishedReq"<(sender()); + if(rp==nullptr)return; + for(auto &rq:mreq) + if(rp==rq.reply){ + rq.copyNet2Local(); +// qDebug()<<"SubTask::finishedReq: deleting connection"; + rq.reply->deleteLater(); + rq.reply=nullptr; + } + //is everything finished? + for(const auto &rq:mreq){ + if(!rq.reply.isNull())return; + } + qDebug()<<"SubTask: I'm done, emitting finished()"; + mstate=Success; + emit finished(); +} + +void AuroraUpdater::SubTask::errorReq() +{ +// qDebug()<<"SubTask::errorReq"<abort(); + } +// qDebug()<<"SubTask::errorReq: deleting connection"; + r.reply->deleteLater(); + } + } + mreq.clear(); + //signal my own error + qDebug()<<"SubTask::errorReq: done, emitting error"; + emit error(); +} + +void AuroraUpdater::SubTask::readFromNet() +{ +// qDebug()<<"SubTask::readFromNet"<(sender()); + if(r==nullptr)return; + for(auto &rq:mreq) + if(rq.reply == r) + rq.copyNet2Local(); +} + +void AuroraUpdater::SubTasklet::copyNet2Local() +{ +// qDebug()<<"SubTasklet::copyNet2Local, this="<bytesAvailable()<1)return; + file->seek(file->size()); + file->write(reply->readAll()); +} diff --git a/aurora/src/subtask.h b/aurora/src/subtask.h new file mode 100644 index 0000000..b6c5b23 --- /dev/null +++ b/aurora/src/subtask.h @@ -0,0 +1,110 @@ +// Copyright (C) 2012 by Konrad Rosenbaum +// protected under the GNU LGPL version 3 or at your option any newer. +// See COPYING.LGPL file that comes with this distribution. +// + +#ifndef AURORA_SUBTASK_H +#define AURORA_SUBTASK_H + +#include +#include +#include +#include +#include +#include +#include + +class QNetworkAccessManager; +namespace AuroraUpdater { + +/// \internal helper class for the SubTask - it tracks a single connection/url +struct SubTasklet { + ///the open reply object + QPointerreply; + ///temporary file to hold the data + QSharedPointer file; + + ///used by QMap only, invalid instance + SubTasklet(){} + ///normal way to instantiate it: from the fresh reply object, auto-creates a temporary file + SubTasklet(QNetworkReply*r):reply(r),file(new QTemporaryFile){file->open();} + ///copy constructor + SubTasklet(const SubTasklet&t):reply(t.reply),file(t.file){} + ///copy operator + SubTasklet& operator=(const SubTasklet&)=default; + ///used by SubTask to trigger copying data from the reply to the temp file + void copyNet2Local(); +}; + +///Instances of this class track the retrieval of one or more URLs and +///signal finished() when all of them downloaded successfully or error() +///if any of them failed. In case of an error all running downloads are +///aborted. +class SubTask:public QObject { + Q_OBJECT + public: + ///instantiates a SubTask with no running downloads, use add to start downloading + SubTask(QObject*parent=nullptr):SubTask(QList(),parent){} + ///instantiates a SubTask and starts downloading with one initial URL + SubTask(QUrl u,QObject*parent=nullptr):SubTask(QList()<u,QObject*parent=nullptr):QObject(parent){add(u);} + + ///adds a single URL to its downloads, + ///this function refuses to add downloads after the SubTask has already finished + ///\param url the URL to download + ///\returns true if the URL was successfully added, false if the URL was not valid + bool add(QUrl url){return add(QList()<urls); + + ///returns all URLs that this SubTask tries to download or has already downloaded + QList urls()const{return mreq.keys();} + ///returns the temporary file corresponding to the given URL, + ///after finished() has been triggered this file contains the completely + ///downloaded data + QFile& file(QUrl u){return *mreq[u].file;} + + ///represents the internal state of the object + enum State{ + ///the object has not started or is in the process of downloading + Working, + ///the SubTask has finished with an error + Error, + ///the SubTask has successfully finished + Success + }; + + ///returns the current state of the instance + State state()const{return mstate;} + + private slots: + /// \internal reacts to finished downloads + void finishedReq(); + /// \internal reacts to network errors + void errorReq(); + /// \internal reads data from open connections + void readFromNet(); + + signals: + ///emitted if/when a network error occurs, all downloads are aborted + void error(); + ///emitted when all downloads have finished successfully + void finished(); + private: + //network handling + QNetworkAccessManager*mnam=nullptr; + //all added URLs and corresponding requests and temp files + QMapmreq; + //current internal state + State mstate=Working; +}; + +//end of namespace +} + +#endif \ No newline at end of file diff --git a/include/aurora/Aurora b/include/aurora/Aurora new file mode 100644 index 0000000..4bffe7f --- /dev/null +++ b/include/aurora/Aurora @@ -0,0 +1 @@ +#include "../../aurora/src/aurora.h" \ No newline at end of file