#include "addon/downloader.hpp"
#include <algorithm>
+#include <array>
#include <assert.h>
#include <memory>
#include <physfs.h>
} // namespace
+void
+TransferStatus::abort()
+{
+ m_downloader.abort(id);
+}
+
+void
+TransferStatus::update()
+{
+ m_downloader.update();
+}
+
class Transfer
{
private:
m_id(id),
m_url(url),
m_handle(),
- m_error_buffer(),
- m_status(new TransferStatus(id)),
+ m_error_buffer({{'\0'}}),
+ m_status(new TransferStatus(m_downloader, id)),
m_fout(PHYSFS_openWrite(outfile.c_str()), PHYSFS_close)
{
if (!m_fout)
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(m_handle, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(m_handle, CURLOPT_XFERINFODATA, this);
- curl_easy_setopt(m_handle, CURLOPT_XFERINFOFUNCTION, &Transfer::on_progress_wrap);
+ curl_easy_setopt(m_handle, CURLOPT_PROGRESSDATA, this);
+ curl_easy_setopt(m_handle, CURLOPT_PROGRESSFUNCTION, &Transfer::on_progress_wrap);
}
}
return m_status;
}
+ const char* get_error_buffer() const
+ {
+ return m_error_buffer.data();
+ }
+
TransferId get_id() const
{
return m_id;
return size * nmemb;
}
- void on_progress(curl_off_t dltotal, curl_off_t dlnow,
- curl_off_t ultotal, curl_off_t ulnow)
+ int on_progress(double dltotal, double dlnow,
+ double ultotal, double ulnow)
{
- m_status->dltotal = dltotal;
- m_status->dlnow = dlnow;
+ m_status->dltotal = static_cast<int>(dltotal);
+ m_status->dlnow = static_cast<int>(dlnow);
+
+ m_status->ultotal = static_cast<int>(ultotal);
+ m_status->ulnow = static_cast<int>(ulnow);
- m_status->ultotal = ultotal;
- m_status->ulnow = ulnow;
+ return 0;
}
private:
return static_cast<Transfer*>(userdata)->on_data(ptr, size, nmemb);
}
- static void on_progress_wrap(void* userdata,
- curl_off_t dltotal, curl_off_t dlnow,
- curl_off_t ultotal, curl_off_t ulnow)
+ static int on_progress_wrap(void* userdata,
+ double dltotal, double dlnow,
+ double ultotal, double ulnow)
{
return static_cast<Transfer*>(userdata)->on_progress(dltotal, dlnow, ultotal, ulnow);
}
void
Downloader::download(const std::string& url, const std::string& filename)
{
+ log_info << "download: " << url << " to " << filename << std::endl;
std::unique_ptr<PHYSFS_file, int(*)(PHYSFS_File*)> fout(PHYSFS_openWrite(filename.c_str()),
PHYSFS_close);
download(url, my_curl_physfs_write, fout.get());
}
else
{
+ TransferStatusPtr status = (*it)->get_status();
+
curl_multi_remove_handle(m_multi_handle, (*it)->get_curl_handle());
m_transfers.erase(it);
+
+ for(auto& callback : status->callbacks)
+ {
+ try
+ {
+ callback(false);
+ }
+ catch(const std::exception& err)
+ {
+ log_warning << "Illegal exception in Downloader: " << err.what() << std::endl;
+ }
+ }
}
}
{
case CURLMSG_DONE:
{
- log_info << "Download completed" << std::endl;
+ log_info << "Download completed with " << msg->data.result << std::endl;
curl_multi_remove_handle(m_multi_handle, msg->easy_handle);
+
auto it = std::find_if(m_transfers.begin(), m_transfers.end(),
[&msg](const std::unique_ptr<Transfer>& rhs) {
return rhs->get_curl_handle() == msg->easy_handle;
});
assert(it != m_transfers.end());
TransferStatusPtr status = (*it)->get_status();
+ status->error_msg = (*it)->get_error_buffer();
m_transfers.erase(it);
- status->status = TransferStatus::COMPLETED;
- if (status->callback)
+ if (msg->data.result == CURLE_OK)
+ {
+ bool success = true;
+ for(auto& callback : status->callbacks)
+ {
+ try
+ {
+ callback(success);
+ }
+ catch(const std::exception& err)
+ {
+ success = false;
+ log_warning << "Exception in Downloader: " << err.what() << std::endl;
+ status->error_msg = err.what();
+ }
+ }
+ }
+ else
{
- status->callback();
+ log_warning << "Error: " << curl_easy_strerror(msg->data.result) << std::endl;
+ for(auto& callback : status->callbacks)
+ {
+ try
+ {
+ callback(false);
+ }
+ catch(const std::exception& err)
+ {
+ log_warning << "Illegal exception in Downloader: " << err.what() << std::endl;
+ }
+ }
}
}
break;
TransferStatusPtr
Downloader::request_download(const std::string& url, const std::string& outfile)
{
+ log_info << "request_download: " << url << std::endl;
std::unique_ptr<Transfer> transfer(new Transfer(*this, m_next_transfer_id++, url, outfile));
curl_multi_add_handle(m_multi_handle, transfer->get_curl_handle());
m_transfers.push_back(std::move(transfer));