utilities/downloadmanager/src/downloadbackend.cpp
changeset 16 3c88a81ff781
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utilities/downloadmanager/src/downloadbackend.cpp	Fri Oct 15 17:30:59 2010 -0400
@@ -0,0 +1,486 @@
+/**
+   This file is part of CWRT package **
+
+   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). **
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU (Lesser) General Public License as 
+   published by the Free Software Foundation, version 2.1 of the License. 
+   This program 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. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "clientdownload.h"
+#include "downloadmanager.h"
+#include "downloadbackend.h"
+#include "downloadcore.h"
+#include "downloadfactory.h"
+#include "downloadstore.h"
+#include <QCoreApplication>
+#include <QDateTime>
+
+//private implementation
+class DownloadBackendPrivate
+{
+    DM_DECLARE_PUBLIC(DownloadBackend);
+public:
+    DownloadBackendPrivate();
+    ~DownloadBackendPrivate();
+
+    DownloadCore *m_downloadCore; // not owned
+    ClientDownload *m_download; //// not owned, only reference 
+    DownloadInfo *m_dlInfo; // not owned
+    qint64 m_totalSize; // total size of the download
+    qint64 m_currentDownloadedSize; // current downloaded size
+    qint64 m_lastPausedSize;
+    DownloadState m_downloadState; // state of the download
+    bool m_infoDeleted; // flag to indicate the info deletion    
+    QDateTime m_startTime; // download start/resumed time
+    QDateTime m_endTime; // download completed time
+    int m_progressCounter;
+};  
+
+DownloadBackendPrivate::DownloadBackendPrivate()
+{
+    m_downloadCore = 0;
+    m_download = 0;
+    m_dlInfo = 0;
+    m_totalSize = 0;
+    m_currentDownloadedSize = 0;
+    m_lastPausedSize =0;
+    m_infoDeleted = false;
+    m_progressCounter = 1;
+}
+
+DownloadBackendPrivate::~DownloadBackendPrivate()
+{
+#if 0 //m_downloadCore may be stale.
+    if(m_downloadCore)
+    {     
+        // cancel if there is any transaction
+        m_downloadCore->abort();
+    }
+#endif
+}
+
+DownloadBackend::DownloadBackend(DownloadCore *dlCore, ClientDownload* dl)
+{
+    DM_INITIALIZE(DownloadBackend);
+    priv->m_downloadCore = dlCore;
+    priv->m_download = dl;
+    priv->m_dlInfo = dl->downloadInfo();
+    // connect all the signals from network
+    connect(dlCore, SIGNAL(downloadProgress(qint64 , qint64 )), this, SLOT(bytesRecieved(qint64 , qint64 )));
+    connect(dlCore, SIGNAL(finished()), this, SLOT(handleFinished()));
+    connect(dlCore, SIGNAL(metaDataChanged()), this, SLOT(headerReceived()));
+    connect(dlCore, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
+    connect(dlCore, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(bytesUploaded(qint64, qint64)));
+
+    // save the content type and url
+    setValue(DownloadInfo::EContentType, priv->m_downloadCore->contentType()); 
+    setValue(DownloadInfo::EUrl, priv->m_downloadCore->url()); 
+    setValue(DownloadInfo::EETag, priv->m_downloadCore->entityTag());
+    postEvent(Started, NULL);
+}
+
+DownloadBackend::~DownloadBackend()
+{
+    DM_UNINITIALIZE(DownloadBackend);
+}
+
+int DownloadBackend::pause()
+{
+    DM_PRIVATE(DownloadBackend);
+    setDownloadState(DlPaused);
+    priv->m_downloadCore->abort();
+    return 0;
+}
+
+int DownloadBackend::resume()
+{
+    DM_PRIVATE(DownloadBackend);
+    setDownloadState(DlInprogress);
+    // save the content type and url
+    setValue(DownloadInfo::EUrl, priv->m_downloadCore->url());
+    setValue(DownloadInfo::EContentType, priv->m_downloadCore->contentType());
+    priv->m_lastPausedSize = priv->m_currentDownloadedSize;
+    priv->m_downloadCore->resumeDownload(priv->m_currentDownloadedSize);
+    priv->m_startTime = QDateTime::currentDateTime();
+    postEvent(Progress, NULL);
+    return 0;
+}
+
+int DownloadBackend::cancel()
+{
+    DM_PRIVATE(DownloadBackend);   
+    setDownloadState(DlCancelled);
+    // cancel the transaction
+    priv->m_downloadCore->abort();
+    // delete the temporary storage
+    deleteStore();
+    // reset the states
+    priv->m_totalSize = 0;
+    priv->m_currentDownloadedSize = 0;
+    priv->m_lastPausedSize = 0;
+    return 0;
+}
+
+QVariant DownloadBackend::getAttribute(DownloadAttribute attr)
+{
+    DM_PRIVATE(DownloadBackend); 
+    switch(attr)
+    {
+         case DlDownloadedSize:
+         {
+             return QVariant(priv->m_currentDownloadedSize);
+         }
+         case DlTotalSize:
+         {
+             return QVariant(priv->m_totalSize);
+         }
+         case DlDownloadState:
+         {
+             return QVariant(priv->m_downloadState);
+         }
+         case DlSourceUrl:
+         {
+             return QVariant(priv->m_downloadCore->url());
+         }
+         case DlContentType:
+         {
+             return QVariant(priv->m_downloadCore->contentType());
+         }
+         case DlStartTime:
+         {
+             return QVariant(priv->m_startTime);
+         }
+         case DlEndTime:
+         {
+             if (priv->m_downloadState == DlCompleted)
+                 return priv->m_endTime;
+             else 
+                 return QVariant();
+         }
+         case DlElapsedTime:
+         {
+             if (priv->m_downloadState == DlCompleted)
+                 return QVariant((priv->m_endTime.toTime_t()-priv->m_startTime.toTime_t()));
+
+             if (priv->m_downloadState != DlInprogress)
+                 return QVariant();
+             QDateTime currentTime = QDateTime::currentDateTime();
+             uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t();
+             return QVariant(timeElasped);
+         }
+         case DlRemainingTime:
+         {
+             if (priv->m_downloadState != DlInprogress)
+                 return QVariant();
+             QDateTime currentTime = QDateTime::currentDateTime();
+             uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t();
+             // total bytes recieved since last start/resume
+             qint64 totalBytesRecieved = priv->m_currentDownloadedSize - priv->m_lastPausedSize;
+             qint64 remainingSize = priv->m_totalSize - priv->m_currentDownloadedSize;
+             if (totalBytesRecieved > 0)
+                 return QVariant((timeElasped*remainingSize)/totalBytesRecieved);
+             else
+                 return QVariant();
+         }
+         case DlSpeed:
+         {
+             if (priv->m_downloadState != DlInprogress)
+                 return QVariant();
+             QDateTime currentTime = QDateTime::currentDateTime();
+             uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t();
+             qint64 totalBytesRecieved = priv->m_currentDownloadedSize - priv->m_lastPausedSize;
+             if (timeElasped > 0)
+                 return QVariant(totalBytesRecieved/timeElasped);
+             else
+                 return QVariant();
+         }
+         case DlPercentage:
+         {
+             if (priv->m_totalSize > 0)
+                 return QVariant((priv->m_currentDownloadedSize*100)/priv->m_totalSize);
+             else
+                 return QVariant();
+         }
+         case DlLastError:
+         {
+             return QVariant(priv->m_downloadCore->lastError());
+         }
+         case DlLastErrorString:
+         {
+             return QVariant(priv->m_downloadCore->lastErrorString());
+         }
+         default:
+         {
+             break;
+         }
+     }
+    return QVariant();
+     
+}
+
+int DownloadBackend::setAttribute(DownloadAttribute /*attr*/, const QVariant& /*value*/)
+{
+    return -1;
+}
+
+void DownloadBackend::bytesRecieved(qint64 bytesRecieved, qint64 bytesTotal)
+{
+    DM_PRIVATE(DownloadBackend);
+    if((priv->m_downloadState == DlFailed) || (bytesRecieved == 0))
+    {
+        return;
+    }
+ 
+    // in case of resumed downloads, we recieve total size remained to download
+    setTotalSize(priv->m_lastPausedSize + bytesTotal);
+    priv->m_currentDownloadedSize = priv->m_lastPausedSize + bytesRecieved;
+    setDownloadState(DlInprogress);
+    // store the recieved chunk
+    store(priv->m_downloadCore->reply()->readAll(), false); 
+    postEvent(Progress, NULL);
+}
+
+void DownloadBackend::handleFinished()
+{
+    DM_PRIVATE(DownloadBackend);
+
+    DownloadState state = priv->m_downloadState;
+    if( state == DlFailed )
+    {
+        postEvent(Failed, NULL);  
+        return;
+    }
+    if( state == DlPaused )
+    {
+        postEvent(Paused, NULL);  
+        return;
+    }
+    if( state == DlCancelled )
+    {
+        postEvent(Cancelled, NULL);  
+        return;
+    }
+    if(priv->m_currentDownloadedSize < priv->m_totalSize)
+    {
+        // all packets are not recieved, so it is not last chunk 
+        // should be some network problem
+        store(priv->m_downloadCore->reply()->readAll(), false); 
+        postEvent(NetworkLoss, NULL);
+    }
+    else
+    {
+        //finish is successful
+        store(priv->m_downloadCore->reply()->readAll(), true);
+        //finish is successful
+        setDownloadState(DlCompleted);
+        priv->m_endTime = QDateTime::currentDateTime();
+        postEvent(Completed, NULL);
+    } 
+}
+
+void DownloadBackend::error(QNetworkReply::NetworkError code)
+{
+    DM_PRIVATE(DownloadBackend);
+    if((code == QNetworkReply::OperationCanceledError) && (priv->m_downloadState == DlCancelled))
+    { 
+        return;
+    }   
+    if(code == QNetworkReply::OperationCanceledError) 
+    {
+        // this means user has paused the download
+        setDownloadState(DlPaused);
+    }   
+    else if(code != QNetworkReply::NoError)
+    {
+        priv->m_downloadCore->setLastError(code);
+        if(priv->m_downloadCore->reply())
+        {
+            priv->m_downloadCore->setLastErrorString(priv->m_downloadCore->reply()->errorString());
+        }
+        setDownloadState(DlFailed);
+        postEvent(Error, NULL);
+    }
+}
+
+void DownloadBackend::postEvent(DEventType type, DlEventAttributeMap* attrMap)
+{
+    DM_PRIVATE(DownloadBackend);
+    // The client if it doesn't want progress events then it can set the DownloadMgrProgress mode as quiet
+    // If it wants progress events at regular intervals then it has to specify the KiloBytes at which it requires the progress event.
+    // By default, the DownloadMgrProgress Mode is non-quiet with progress events being sent at every 5KB downloaded. 
+    DownloadMgrProgressMode mode = (DownloadMgrProgressMode)(priv->m_download->downloadManager()->getAttribute(DlMgrProgressMode)).toInt();
+    if ((mode == Quiet) && (type == Progress))
+        return;
+
+    qlonglong kBytes = priv->m_download->getAttribute(DlProgressInterval).toLongLong() * 1024;
+    if (mode == NonQuiet && type == Progress)
+    {
+        if ((priv->m_currentDownloadedSize/(kBytes * priv->m_progressCounter)) > 0)
+        {
+            priv->m_progressCounter++;
+            postDownloadEvent(type, attrMap);
+        }
+    }
+    else
+        postDownloadEvent(type, attrMap);
+}
+
+DownloadState DownloadBackend::downloadState(void)
+{
+    DM_PRIVATE(DownloadBackend);
+    return priv->m_downloadState;
+}
+
+void DownloadBackend::setDownloadState(DownloadState state)
+{
+    DM_PRIVATE(DownloadBackend);
+    priv->m_downloadState = state;
+    // save the download state
+    setValue(DownloadInfo::EDlState, priv->m_downloadState);
+    if((state == DlFailed) || (state == DlCompleted) || (state == DlCancelled))
+    {
+        // remove dl info
+            deleteInfo();
+    }
+}
+
+void DownloadBackend::setDownloadedDataSize(qint64 size)
+{
+    DM_PRIVATE(DownloadBackend);
+    priv->m_currentDownloadedSize = size;
+    return;
+}
+
+void DownloadBackend::setTotalSize(qint64 size)
+{
+    DM_PRIVATE(DownloadBackend);
+    priv->m_totalSize = size;
+    setValue(DownloadInfo::ETotalSize, priv->m_totalSize);
+    return;
+}
+
+void DownloadBackend::setStartTime()
+{
+    DM_PRIVATE(DownloadBackend);
+    priv->m_startTime = QDateTime::currentDateTime();
+}
+
+ClientDownload* DownloadBackend::download(void)
+{
+    DM_PRIVATE(DownloadBackend);
+    return priv->m_download;
+}
+
+/* Helper functions to access download info */
+
+int DownloadBackend::setValue(DownloadInfo::Key aKey, const QString& aStrValue)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aStrValue, priv->m_download->parentId());
+}
+
+int DownloadBackend::setValueForChild(DownloadInfo::Key aKey, const QString& aStrValue, int aChildId)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->setValueForChild(priv->m_download->id(), aKey, aStrValue, aChildId);
+}
+
+int DownloadBackend::setValue(DownloadInfo::Key aKey, long aIntValue)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aIntValue, priv->m_download->parentId());
+}
+
+int DownloadBackend::setValueForChild(DownloadInfo::Key aKey, long aIntValue, int aChildId)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->setValueForChild(priv->m_download->id(), aKey, aIntValue, aChildId);
+}
+
+int DownloadBackend::setValue(DownloadInfo::Key aKey, const QList<QVariant>& aChildIds)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aChildIds);
+}
+
+int DownloadBackend::getValue(DownloadInfo::Key aKey, QString& aStrValue)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aStrValue, priv->m_download->parentId());
+}
+
+int DownloadBackend::getValueForChild(DownloadInfo::Key aKey, QString& aStrValue, int aChildId)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->getValueForChild(priv->m_download->id(), aKey, aStrValue, aChildId);
+}
+
+int DownloadBackend::getValue(DownloadInfo::Key aKey, long& aIntValue)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aIntValue, priv->m_download->parentId());
+}
+
+int DownloadBackend::getValueForChild(DownloadInfo::Key aKey, long& aIntValue, int aChildId)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->getValueForChild(priv->m_download->id(), aKey, aIntValue, aChildId);
+ 
+}
+
+int DownloadBackend::getValue(DownloadInfo::Key aKey, QList<QVariant>& aChildIds)
+{
+    DM_PRIVATE(DownloadBackend);
+    if(priv->m_infoDeleted)
+        return 0;
+    return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aChildIds);
+}
+
+int DownloadBackend::deleteInfo()
+{
+    DM_PRIVATE(DownloadBackend);
+    if ((InActive == priv->m_download->downloadManager()->getAttribute(DlMgrPersistantMode))
+        && (DlCompleted == priv->m_downloadState))
+        return 0;
+    priv->m_infoDeleted = true;
+    return priv->m_dlInfo->remove(priv->m_download->id(), priv->m_download->parentId()); 
+}
+void DownloadBackend::postDownloadEvent(DEventType type, DlEventAttributeMap* attrMap)
+{
+    DM_PRIVATE(DownloadBackend);
+    EventReceiverList list = priv->m_download->eventReceivers();
+    for(int i=0; i<list.size(); i++)
+    {
+        if(list[i])
+        {
+            DownloadEvent *event = new DownloadEvent(type, attrMap, priv->m_download->id());
+            QCoreApplication::postEvent(list[i], event);
+        }
+    }
+}