- Improved a lot downloading from url using libcommoncpp2 instead of libcurl

- TODO soon:
  - Updated configure file
	- Add url download error handling
This commit is contained in:
Christophe Dumez 2007-07-20 15:55:50 +00:00
parent 347b03d699
commit 7c8677d787
7 changed files with 61 additions and 93 deletions

View file

@ -24,6 +24,7 @@
- FEATURE: Real torrent share ratio is now displayed in transfer list
- FEATURE: Added keyboard shortcuts for main actions (see wiki)
- FEATURE: Added a popup menu to set priority for multiple fies at once
- FEATURE: Improved a lot downloading from urls (using libcommoncpp2 instead of libcurl)
- I18N: Added Hungarian translation
- BUGFIX: Progress of paused torrents is now correct on restart
- BUGFIX: Progress column gets sorted on restart it is was during last execution

3
TODO
View file

@ -42,9 +42,8 @@
- update sorting when a new torrent is added?
- Allow to hide columns (gtsoul)
- Complete documentation and english translation
- Fix downloader thread (again). Try to use another lib than libcurl:
- libcommoncpp has a URLStream class. This C++ class allow you to download a file using HTTP. See demo/urlfetch.cpp in commoncpp2-1.3.19.tar.gz
* beta2
- Fix configure file for libcommoncpp
- Wait for some bug fixes in libtorrent :
- upload/download limit per torrent
- ipfilter crash

View file

@ -50,7 +50,7 @@ bittorrent::bittorrent(){
ETARefresher.start(6000);
// To download from urls
downloader = new downloadThread(this);
connect(downloader, SIGNAL(downloadFinished(const QString&, const QString&, int, const QString&)), this, SLOT(processDownloadedFile(const QString&, const QString&, int, const QString&)));
connect(downloader, SIGNAL(downloadFinished(const QString&, const QString&)), this, SLOT(processDownloadedFile(const QString&, const QString&)));
}
// Main destructor
@ -1013,13 +1013,13 @@ void bittorrent::downloadFromUrl(const QString& url){
}
// Add to bittorrent session the downloaded torrent file
void bittorrent::processDownloadedFile(const QString& url, const QString& file_path, int return_code, const QString& errorBuffer){
if(return_code){
// Download failed
emit downloadFromUrlFailure(url, errorBuffer);
QFile::remove(file_path);
return;
}
void bittorrent::processDownloadedFile(const QString& url, const QString& file_path){
// if(return_code){
// // Download failed
// emit downloadFromUrlFailure(url, errorBuffer);
// QFile::remove(file_path);
// return;
// }
// Add file to torrent download list
emit newDownloadedTorrent(file_path, url);
}

View file

@ -136,7 +136,7 @@ class bittorrent : public QObject{
void cleanDeleter(deleteThread* deleter);
void scanDirectory();
void readAlerts();
void processDownloadedFile(const QString&, const QString&, int, const QString&);
void processDownloadedFile(const QString&, const QString&);
void resumeUnfinished();
bool loadTrackerFile(const QString& hash);
void saveTrackerFile(const QString& hash);

View file

@ -28,11 +28,15 @@
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include <curl/curl.h>
#include <iostream>
#include <cc++/common.h>
#include "misc.h"
#ifdef CCXX_NAMESPACES
using namespace std;
using namespace ost;
#endif
class downloadThread : public QThread {
Q_OBJECT
@ -41,9 +45,10 @@ class downloadThread : public QThread {
QMutex mutex;
QWaitCondition condition;
bool abort;
URLStream url_stream;
signals:
void downloadFinished(const QString& url, const QString& file_path, int return_code, const QString& errorBuffer);
void downloadFinished(const QString& url, const QString& file_path);
public:
downloadThread(QObject* parent) : QThread(parent){
@ -84,80 +89,41 @@ class downloadThread : public QThread {
QString url = url_list.takeFirst();
mutex.unlock();
qDebug("In Download thread RUN, mutex unlocked (got url)");
CURL *curl;
QString filePath;
int return_code, response;
// XXX: Trick to get a unique filename
QTemporaryFile *tmpfile = new QTemporaryFile;
QString filePath;
QTemporaryFile *tmpfile = new QTemporaryFile();
if (tmpfile->open()) {
filePath = tmpfile->fileName();
}
delete tmpfile;
if(abort)
return;
FILE *file = fopen((const char*)filePath.toUtf8(), "w");
if(!file){
std::cerr << "Error: could not open temporary file...\n";
return;
QFile dest_file(filePath);
if(!dest_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: could't create temporary file: " << (const char*)filePath.toUtf8() << '\n';
continue;
}
// Initilization required by libcurl
curl = curl_easy_init();
if(!curl){
std::cerr << "Error: Failed to init curl...\n";
fclose(file);
return;
URLStream::Error status = url_stream.get((const char*)url.toUtf8());
if(status){
// Failure
//TODO: handle this
QString error_msg = QString(misc::toString(status).c_str());
qDebug("Download failed for %s, reason: %s", (const char*)url.toUtf8(), (const char*)error_msg.toUtf8());
url_stream.close();
continue;
}
// Set url to download
curl_easy_setopt(curl, CURLOPT_URL, url.toLocal8Bit().constData());
qDebug("Url: %s", url.toLocal8Bit().constData());
// Define our callback to get called when there's data to be written
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, misc::my_fwrite);
// Set destination file
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
// Some SSL mambo jambo
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
// Disable progress meter
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
// Any kind of authentication
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// Auto referrer
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
// Follow redirections
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
// Enable cookies
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
// We want error message:
char errorBuffer[CURL_ERROR_SIZE];
errorBuffer[0]=0; /* prevent junk from being output */
return_code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
if(return_code){
std::cerr << "Error: failed to set error buffer in curl\n";
fclose(file);
QFile::remove(filePath);
return;
qDebug("Downloading %s...", (const char*)url.toUtf8());
char cbuf[1024];
int len;
while(!url_stream.eof()) {
url_stream.read(cbuf, sizeof(cbuf));
len = url_stream.gcount();
if(len > 0){
dest_file.write(cbuf, len);
}
}
unsigned short retries = 0;
bool to_many_users = false;
do{
// Perform Download
return_code = curl_easy_perform(curl);
// We want HTTP response code
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
qDebug("HTTP response code: %d", response);
if(response/100 == 5){
to_many_users = true;
++retries;
SleeperThread::msleep(1000);
}
}while(to_many_users && retries < 10 && response!=0);
// Cleanup
curl_easy_cleanup(curl);
// Close tmp file
fclose(file);
emit downloadFinished(url, filePath, return_code, QString(errorBuffer));
qDebug("In Download thread RUN, signal emitted, ErrorBuffer: %s", errorBuffer);
dest_file.close();
url_stream.close();
emit downloadFinished(url, filePath);
qDebug("In Download thread RUN, signal emitted");
}else{
qDebug("In Download thread RUN, mutex still locked (no urls) -> sleeping");
condition.wait(&mutex);

View file

@ -137,21 +137,21 @@ class RssStream : public QObject{
public slots :
// read and store the downloaded rss' informations
void processDownloadedFile(const QString&, const QString& file_path, int return_code, const QString&) {
void processDownloadedFile(const QString&, const QString& file_path) {
// delete the former file
if(QFile::exists(filePath)) {
QFile::remove(filePath);
}
filePath = file_path;
if(return_code){
// Download failed
qDebug("(download failure) "+file_path.toUtf8());
if(QFile::exists(filePath)) {
QFile::remove(filePath);
}
emit refreshFinished(url, NEWS);
return;
}
// if(return_code){
// // Download failed
// qDebug("(download failure) "+file_path.toUtf8());
// if(QFile::exists(filePath)) {
// QFile::remove(filePath);
// }
// emit refreshFinished(url, NEWS);
// return;
// }
openRss();
emit refreshFinished(url, NEWS);
}
@ -189,7 +189,7 @@ class RssStream : public QObject{
read = true;
downloaderRss = new downloadThread(this);
downloaderIcon = new downloadThread(this);
connect(downloaderRss, SIGNAL(downloadFinished(const QString&, const QString&, int, const QString&)), this, SLOT(processDownloadedFile(const QString&, const QString&, int, const QString&)));
connect(downloaderRss, SIGNAL(downloadFinished(const QString&, const QString&)), this, SLOT(processDownloadedFile(const QString&, const QString&)));
downloaderRss->downloadUrl(url);
// XXX: remove it when gif can be displayed
iconPath = ":/Icons/rss.png";
@ -216,7 +216,6 @@ class RssStream : public QObject{
}
void refresh() {
connect(downloaderRss, SIGNAL(downloadFinished(const QString&, const QString&, int, const QString&)), this, SLOT(processDownloadedFile(const QString&, const QString&, int, const QString&)));
downloaderRss->downloadUrl(url);
lastRefresh.start();
}
@ -276,7 +275,7 @@ class RssStream : public QObject{
QString getLastRefresh() const{
return QString::number(lastRefresh.hour())+"h"+QString::number(lastRefresh.minute())+"m";
}
}
bool isRead() const {
return read;

View file

@ -2,6 +2,9 @@
LANG_PATH = lang
ICONS_PATH = Icons
LIBS += -lccext2
LIBS += -lccgnu2
#Set the following variable to 1 to enable debug
DEBUG_MODE = 1