#include <json.h>
#include <pakfire/downloader.h>
+#include <pakfire/i18n.h>
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
+#include <pakfire/progressbar.h>
#include <pakfire/types.h>
#include <pakfire/util.h>
Pakfire pakfire;
int nrefs;
+ struct pakfire_progressbar* progressbar;
unsigned int parallel;
// cURL multi handle
pakfire_transfer_free(transfer);
}
+ if (downloader->progressbar)
+ pakfire_progressbar_unref(downloader->progressbar);
+
if (downloader->curl)
curl_multi_cleanup(downloader->curl);
if (r)
goto ERROR;
+ // Create the progressbar
+ r = pakfire_progressbar_create(&d->progressbar, d->pakfire, NULL);
+ if (r)
+ goto ERROR;
+
*downloader = d;
return 0;
}
#endif
-int pakfire_downloader_add_transfer(struct pakfire_downloader* downloader,
- struct pakfire_mirrorlist* mirrors, const char* url, const char* path) {
+static struct pakfire_transfer* pakfire_downloader_create_transfer(
+ struct pakfire_downloader* downloader, struct pakfire_mirrorlist* mirrors,
+ const char* url, const char* path) {
DEBUG(downloader->pakfire, "Adding download of %s\n", url);
// Do not allow relative URLs when no mirrors are set
if (!pakfire_url_is_absolute(url) && !mirrors) {
ERROR(downloader->pakfire, "Relative URLs cannot be used without a mirrorlist\n");
- return EINVAL;
+ errno = EINVAL;
+ return NULL;
}
struct pakfire_transfer* transfer = calloc(1, sizeof(*transfer));
if (!transfer)
- return ENOMEM;
+ return NULL;
// Copy URL
snprintf(transfer->url, sizeof(transfer->url) - 1, "%s", url);
curl_easy_setopt(transfer->handle, CURLOPT_WRITEDATA, transfer->f);
- // Push this transfer onto the queue
- TAILQ_INSERT_HEAD(&downloader->transfers, transfer, nodes);
-
// Success
- return 0;
+ return transfer;
ERROR:
pakfire_transfer_free(transfer);
- return 1;
+ return NULL;
+}
+
+int pakfire_downloader_add_transfer(struct pakfire_downloader* downloader,
+ struct pakfire_mirrorlist* mirrors, const char* url, const char* path) {
+ struct pakfire_transfer* transfer = pakfire_downloader_create_transfer(
+ downloader, mirrors, url, path);
+ if (!transfer)
+ return 1;
+
+ // Push this transfer onto the queue
+ TAILQ_INSERT_HEAD(&downloader->transfers, transfer, nodes);
+
+ return 0;
}
static int pakfire_transfer_select_mirror(struct pakfire_downloader* downloader,
}
static int pakfire_transfer_fail(struct pakfire_downloader* downloader,
- struct pakfire_transfer* transfer) {
+ struct pakfire_transfer* transfer, int code) {
int r;
DEBUG(downloader->pakfire, "Transfer failed\n");
}
static int pakfire_transfer_done(struct pakfire_downloader* downloader,
- struct pakfire_transfer* transfer, CURLMsg* msg) {
+ struct pakfire_transfer* transfer, int code) {
CURL* h = transfer->handle;
int r;
curl_off_t speed;
DEBUG(downloader->pakfire, "cURL transfer done: %d - %s\n",
- msg->data.result, curl_easy_strerror(msg->data.result));
+ code, curl_easy_strerror(code));
// Protocol
curl_easy_getinfo(h, CURLINFO_PROTOCOL, &protocol);
// Treat all other response codes as an error
default:
- r = pakfire_transfer_fail(downloader, transfer);
+ r = pakfire_transfer_fail(downloader, transfer, code);
if (r)
return r;
return 0;
}
-int pakfire_downloader_retrieve(struct pakfire_downloader* downloader,
- struct pakfire_mirrorlist* mirrors, const char* url, const char* path) {
- // Do not run this when there are transfers pending
- if (!TAILQ_EMPTY(&downloader->transfers))
- return EBUSY;
-
- // Add the transfer
- int r = pakfire_downloader_add_transfer(downloader, mirrors, url, path);
- if (r)
- return r;
-
- // Run it
- return pakfire_downloader_run(downloader);
-}
-
-static int pakfire_downloader_activate_transfer(struct pakfire_downloader* downloader,
+static int pakfire_downloader_prepare_transfer(struct pakfire_downloader* downloader,
struct pakfire_transfer* transfer) {
// Increment tries
transfer->tries++;
return 1;
}
- // Add the handle to cURL
- int r = curl_multi_add_handle(downloader->curl, transfer->handle);
- if (r) {
- ERROR(downloader->pakfire, "Adding handle failed\n");
+ return 0;
+}
+
+/*
+ This function performs one single transfer in blocking mode.
+*/
+static int pakfire_downloader_perform(
+ struct pakfire_downloader* downloader, struct pakfire_transfer* transfer) {
+ int r;
+
+ // Prepare the transfer
+ r = pakfire_downloader_prepare_transfer(downloader, transfer);
+ if (r)
return r;
- }
- return 0;
+ // Perform the download
+ r = curl_easy_perform(transfer->handle);
+
+ if (r == CURLE_OK)
+ return pakfire_transfer_done(downloader, transfer, r);
+
+ // Handle errors
+ r = pakfire_transfer_fail(downloader, transfer, r);
+ if (r == EAGAIN)
+ return pakfire_downloader_perform(downloader, transfer);
+
+ return r;
+}
+
+int pakfire_downloader_retrieve(struct pakfire_downloader* downloader,
+ struct pakfire_mirrorlist* mirrors, const char* url, const char* path) {
+ struct pakfire_transfer* transfer = pakfire_downloader_create_transfer(
+ downloader, mirrors, url, path);
+ if (!transfer)
+ return 1;
+
+ // Perform the download
+ int r = pakfire_downloader_perform(downloader, transfer);
+ pakfire_transfer_free(transfer);
+
+ return r;
}
int pakfire_downloader_run(struct pakfire_downloader* downloader) {
transfer = TAILQ_LAST(&downloader->transfers, transfers);
TAILQ_REMOVE(&downloader->transfers, transfer, nodes);
- r = pakfire_downloader_activate_transfer(downloader, transfer);
+ // Prepare the transfer
+ r = pakfire_downloader_prepare_transfer(downloader, transfer);
+ if (r) {
+ pakfire_transfer_free(transfer);
+ return r;
+ }
+
+ // Add the handle to cURL
+ r = curl_multi_add_handle(downloader->curl, transfer->handle);
if (r) {
- ERROR(downloader->pakfire, "Could not activate transfer\n");
+ ERROR(downloader->pakfire, "Adding handle failed\n");
pakfire_transfer_free(transfer);
- continue;
+ return r;
}
transfers++;
curl_multi_remove_handle(downloader->curl, transfer->handle);
// Handle whatever comes after the transfer
- r = pakfire_transfer_done(downloader, transfer, msg);
+ r = pakfire_transfer_done(downloader, transfer, msg->data.result);
if (r) {
// We will try another mirror and therefore insert this
// transfer to be picked up again next