root/src/filedownloadthread.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "filedownloadthread.h"
// TODO don't include curl result, move defaultClient elsewere
#include "curlresult.h"
#include <curl/curl.h>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QUrl>

FileDownloadThread::FileDownloadThread(QString url, QString downloadPath, bool overwriteExisting, bool keepRemoteName) :
    url(url),
    downloadPath(downloadPath),
    overwriteExisting(overwriteExisting),
    keepRemoteName(keepRemoteName)
{
}

void FileDownloadThread::run() {
    // create dir
    QDir dir;
    if (keepRemoteName) {
        dir = QDir(downloadPath);
    } else {
        dir = QFileInfo(downloadPath).absoluteDir();
    }

    if (!dir.exists()) {
        if (!QDir::root().mkpath(dir.absolutePath())) {
            qDebug() << "could not create director for fileDownload" << dir.absolutePath();
            return;
        }
    }

    QString finalPath;
    QString filename;
    if (keepRemoteName) {
        filename = QFileInfo(QUrl(url).path()).fileName();
        finalPath = dir.absoluteFilePath(filename);
    } else {
        finalPath = downloadPath;
        filename = QFileInfo(downloadPath).fileName();
    }

    if (QFile::exists(finalPath) && !overwriteExisting) {
        return;
    }

    const QString tmpFilename(QString().sprintf("%p", this).append(filename));
    QFile tmpFile(QDir::temp().absoluteFilePath(tmpFilename));
    if (tmpFile.open(QFile::WriteOnly)) {
        CURL* handle = curlClient(url.toLocal8Bit().data(), tmpFile);
        int error = curl_easy_perform(handle);
        curl_easy_cleanup(handle);
        tmpFile.close();

        if (error) {
            qDebug() << "could not fetch file " << url;
            tmpFile.remove();
        } else {
            qDebug() << "finished file-download of " << finalPath;
            emit downloadSucceeded(finalPath);
        }

        QFile::remove(finalPath);
        if (!tmpFile.rename(finalPath)) {
            qDebug() << "could not rename downloaded tmp file to destination file: " << finalPath;
            tmpFile.remove();
        }
    } else {
        qDebug() << "could not write download to " << finalPath;
    }
}

CURL* FileDownloadThread::curlClient(const char* url, QFile& file) {
    CURL* handle = CurlResult::defaultClient();
    curl_easy_setopt(handle, CURLOPT_URL, url);
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, FileDownloadThread::write_data);
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &file);
    return handle;
}

int FileDownloadThread::write_data(void *buffer, size_t characterSize, size_t bufferSize, void *userp)
{
       QFile* file = static_cast<QFile*>(userp);
       if (file) {
           return file->write((const char*)buffer, characterSize*bufferSize);
       }
       return 0;
}