Updated addon repository URL and improved debug output on download
[supertux.git] / src / addon / downloader.cpp
index f07915e..905dd2b 100644 (file)
@@ -18,6 +18,7 @@
 #include "addon/downloader.hpp"
 
 #include <algorithm>
+#include <array>
 #include <assert.h>
 #include <memory>
 #include <physfs.h>
@@ -48,6 +49,18 @@ size_t my_curl_physfs_write(void* ptr, size_t size, size_t nmemb, void* userdata
 
 } // namespace
 
+void
+TransferStatus::abort()
+{
+  m_downloader.abort(id);
+}
+
+void
+TransferStatus::update()
+{
+  m_downloader.update();
+}
+
 class Transfer
 {
 private:
@@ -69,8 +82,8 @@ public:
     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)
@@ -99,8 +112,8 @@ public:
       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);
     }
   }
 
@@ -114,6 +127,11 @@ public:
     return m_status;
   }
 
+  const char* get_error_buffer() const
+  {
+    return m_error_buffer.data();
+  }
+
   TransferId get_id() const
   {
     return m_id;
@@ -135,14 +153,16 @@ public:
     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:
@@ -151,9 +171,9 @@ 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);
   }
@@ -228,6 +248,7 @@ Downloader::download(const std::string& url)
 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());
@@ -247,8 +268,22 @@ Downloader::abort(TransferId id)
   }
   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;
+      }
+    }
   }
 }
 
@@ -272,20 +307,49 @@ Downloader::update()
     {
       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;
@@ -300,6 +364,7 @@ Downloader::update()
 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));