#include <errno.h>
#include <limits.h>
#include <stdlib.h>
+#include <sys/queue.h>
#include <json.h>
#include <pakfire/util.h>
#include <pakfire/xfer.h>
+struct pakfire_client_upload {
+ STAILQ_ENTRY(pakfire_client_upload) nodes;
+
+ // Client
+ struct pakfire_client* client;
+
+ // UUID
+ char uuid[UUID_STR_LEN];
+
+ // Filename
+ char filename[NAME_MAX];
+
+ // Stat Result
+ struct stat stat;
+
+ // File Handle
+ FILE* f;
+
+ // Hashes
+ struct pakfire_hashes hashes;
+
+ // Callback
+ pakfire_client_upload_callback callback;
+ void* data;
+};
+
struct pakfire_client {
struct pakfire_ctx* ctx;
int nrefs;
pakfire_client_auth_callback callback;
void* data;
} auth;
+
+ // Uploads
+ STAILQ_HEAD(uploads, pakfire_client_upload) uploads;
};
static int pakfire_client_xfer_create(struct pakfire_xfer** xfer,
if (r < 0)
goto ERROR;
+ // Initialize uploads
+ STAILQ_INIT(&self->uploads);
+
// Setup the authentication timer
r = sd_event_add_time_relative(self->loop, &self->auth.timer,
CLOCK_MONOTONIC, 0, 0, pakfire_client_auth_timer, self);
// Uploads
-static int pakfire_client_create_upload(struct pakfire_client* self,
- const char* path, const char* filename, FILE* f, char** uuid) {
- struct pakfire_hashes hashes = {};
- struct pakfire_xfer* xfer = NULL;
- struct json_object* response = NULL;
- struct json_object* request = NULL;
- char* hexdigest_blake2b512 = NULL;
- struct stat stat;
- int r;
+static void pakfire_client_upload_free(struct pakfire_client_upload* upload) {
+ // Close the file handle
+ if (upload->f)
+ fclose(upload->f);
- const int fd = fileno(f);
+ free(upload);
+}
- // Stat the file
- r = fstat(fd, &stat);
- if (r) {
- ERROR(self->ctx, "Could not stat %s: %s\n", path, strerror(errno));
+static int pakfire_client_upload_create(struct pakfire_client_upload** upload,
+ struct pakfire_client* client, const char* path, const char* filename,
+ pakfire_client_upload_callback callback, void* data) {
+ struct pakfire_client_upload* self = NULL;
+ char basename[NAME_MAX];
+ int r;
+
+ // Allocate a new object
+ self = calloc(1, sizeof(*self));
+ if (!self) {
r = -errno;
goto ERROR;
}
- // Compute the digest
- r = pakfire_hash_file(self->ctx, f, PAKFIRE_HASH_BLAKE2B512, &hashes);
- if (r < 0) {
- ERROR(self->ctx, "Could not compute the checksum of %s: %s\n",
- path, strerror(-r));
- goto ERROR;
- }
+ // Reference the client
+ self->client = client;
- // Convert the digest into hex format
- r = pakfire_hashes_get_hex(&hashes, PAKFIRE_HASH_BLAKE2B512, &hexdigest_blake2b512);
+ // Compute the basename
+ r = pakfire_path_basename(basename, path);
if (r < 0)
goto ERROR;
- // Create a new xfer
- r = pakfire_client_xfer_create(&xfer, self, "/api/v1/uploads");
- if (r < 0)
- goto ERROR;
+ // Set the basename as default filename
+ if (!filename)
+ filename = basename;
- // Enable authentication
- r = pakfire_client_xfer_auth(self, xfer);
+ // Store the filename
+ r = pakfire_string_set(self->filename, filename);
if (r < 0)
goto ERROR;
- // Make the request
- r = pakfire_json_new_object(&request);
- if (r < 0)
+ // Open the source file
+ self->f = fopen(path, "r");
+ if (!self->f) {
+ ERROR(client->ctx, "Could not open file for upload %s: %m\n", path);
+ r = -errno;
goto ERROR;
+ }
- // Add the filename parameter
- r = pakfire_json_add_string(request, "filename", filename);
- if (r < 0)
- goto ERROR;
+ // Fetch the file descriptor
+ const int fd = fileno(self->f);
- // Add the size parameter
- r = pakfire_json_add_int64(request, "size", stat.st_size);
- if (r < 0)
+ // Stat the file
+ r = fstat(fd, &self->stat);
+ if (r) {
+ ERROR(client->ctx, "Could not stat %s: %m\n", path);
+ r = -errno;
goto ERROR;
+ }
- // Add the hexdigest parameter
- r = pakfire_json_add_string(request, "hexdigest_blake2b512", hexdigest_blake2b512);
- if (r < 0)
+ // Compute the digest
+ r = pakfire_hash_file(client->ctx, self->f, PAKFIRE_HASH_BLAKE2B512, &self->hashes);
+ if (r < 0) {
+ ERROR(client->ctx, "Could not compute the checksum of %s: %s\n", path, strerror(-r));
goto ERROR;
+ }
- // Send the request
- r = pakfire_xfer_run_api_request(xfer, request, &response);
- if (r < 0)
- goto ERROR;
+ // Store the callback
+ self->callback = callback;
+ self->data = data;
- // Fetch the ID
- if (uuid) {
- r = pakfire_client_api_response_string(self, response, "uuid", uuid);
- if (r < 0)
- goto ERROR;
- }
+ // Append to the list
+ STAILQ_INSERT_TAIL(&client->uploads, self, nodes);
- // Success
- r = 0;
+ // Return a pointer to the upload
+ *upload = self;
+
+ return 0;
ERROR:
- if (xfer)
- pakfire_xfer_unref(xfer);
- if (response)
- json_object_put(response);
- if (request)
- json_object_put(request);
- if (hexdigest_blake2b512)
- free(hexdigest_blake2b512);
+ if (self)
+ pakfire_client_upload_free(self);
return r;
}
-static int pakfire_client_upload_payload(struct pakfire_client* self,
- const char* filename, const char* uuid, FILE* f) {
+static void pakfire_client_upload_remove(struct pakfire_client* self, struct pakfire_client_upload* upload) {
+ STAILQ_REMOVE(&self->uploads, upload, pakfire_client_upload, nodes);
+}
+
+static int pakfire_client_upload_payload(struct pakfire_client_upload* upload) {
+ struct pakfire_client* self = upload->client;
struct pakfire_xfer* xfer = NULL;
int r;
// Create a new xfer
- r = pakfire_client_xfer_create(&xfer, self, "/api/v1/uploads/%s", uuid);
+ r = pakfire_client_xfer_create(&xfer, self, "/api/v1/uploads/%s", upload->uuid);
if (r < 0)
goto ERROR;
// Set the title
- r = pakfire_xfer_set_title(xfer, filename);
+ r = pakfire_xfer_set_title(xfer, upload->filename);
if (r < 0)
goto ERROR;
// Enable authentication
r = pakfire_client_xfer_auth(self, xfer);
- if (r)
+ if (r < 0)
goto ERROR;
// Set source file
- r = pakfire_xfer_set_input(xfer, f);
- if (r)
+ r = pakfire_xfer_set_input(xfer, upload->f);
+ if (r < 0)
goto ERROR;
+ // XXX Set the callback
+
// Send the request
- r = pakfire_xfer_run_api_request(xfer, NULL, NULL);
- if (r)
+ r = pakfire_httpclient_enqueue(self->httpclient, xfer);
+ if (r < 0)
goto ERROR;
ERROR:
return r;
}
-int pakfire_client_upload(struct pakfire_client* self,
- const char* path, const char* filename, char** uuid) {
- char basename[NAME_MAX];
- FILE* f = NULL;
+static int pakfire_client_upload_response(struct pakfire_xfer* xfer,
+ pakfire_xfer_error_code_t code, struct json_object* response, void* data) {
+ struct pakfire_client_upload* self = data;
+ const char* uuid = NULL;
int r;
- // Compute the basename
- r = pakfire_path_basename(basename, path);
- if (r)
- goto ERROR;
+ switch (code) {
+ case PAKFIRE_XFER_OK:
+ // Fetch the UUID from the response
+ r = pakfire_json_get_string(response, "uuid", &uuid);
+ if (r < 0)
+ return r;
- // Set the basename as default filename
- if (!filename)
- filename = basename;
+ // Store the UUID
+ r = pakfire_string_set(self->uuid, uuid);
+ if (r < 0)
+ return r;
- // Open the source file
- f = fopen(path, "r");
- if (!f) {
- ERROR(self->ctx, "Could not open file for upload %s: %m\n", path);
- return -errno;
+ // Upload the payload
+ return pakfire_client_upload_payload(self);
+
+ // XXX Handle any errors
+ default:
+ break;
}
+ return -EINVAL;
+}
+
+int pakfire_client_upload(struct pakfire_client* self,
+ const char* path, const char* filename, pakfire_client_upload_callback callback, void* data) {
+ struct pakfire_client_upload* upload = NULL;
+ struct json_object* request = NULL;
+ char* hexdigest_blake2b512 = NULL;
+ struct pakfire_xfer* xfer = NULL;
+ int r;
+
// Create a new upload
- r = pakfire_client_create_upload(self, path, filename, f, uuid);
+ r = pakfire_client_upload_create(&upload, self, path, filename, callback, data);
if (r < 0) {
- ERROR(self->ctx, "Failed to create upload: %s\n", strerror(-r));
+ ERROR(self->ctx, "Failed to create a new upload: %s\n", strerror(-r));
goto ERROR;
}
- DEBUG(self->ctx, "Created a new upload (%s)\n", *uuid);
+ // Convert the digest into hex format
+ r = pakfire_hashes_get_hex(&upload->hashes, PAKFIRE_HASH_BLAKE2B512, &hexdigest_blake2b512);
+ if (r < 0)
+ goto ERROR;
- // Send the payload
- r = pakfire_client_upload_payload(self, filename, *uuid, f);
- if (r < 0) {
- ERROR(self->ctx, "Failed to upload the payload for %s: %s\n", *uuid, strerror(-r));
+ // Create a new xfer
+ r = pakfire_client_xfer_create(&xfer, self, "/api/v1/uploads");
+ if (r < 0)
goto ERROR;
- }
-ERROR:
- if (r) {
- if (*uuid)
- free(*uuid);
+ // Enable authentication
+ r = pakfire_client_xfer_auth(self, xfer);
+ if (r < 0)
+ goto ERROR;
- *uuid = NULL;
- }
- if (f)
- fclose(f);
+ // Make the request
+ r = pakfire_json_new_object(&request);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the filename parameter
+ r = pakfire_json_add_string(request, "filename", upload->filename);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the size parameter
+ r = pakfire_json_add_int64(request, "size", upload->stat.st_size);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the hexdigest parameter
+ r = pakfire_json_add_string(request, "hexdigest_blake2b512", hexdigest_blake2b512);
+ if (r < 0)
+ goto ERROR;
+
+ // Set the request body
+ r = pakfire_xfer_set_json_payload(xfer, request);
+ if (r < 0)
+ goto ERROR;
+
+ // Register the callback
+ r = pakfire_xfer_set_response_callback(xfer, pakfire_client_upload_response, upload);
+ if (r < 0)
+ goto ERROR;
+
+ // Enqueue the transfer
+ r = pakfire_httpclient_enqueue(self->httpclient, xfer);
+ if (r < 0)
+ goto ERROR;
+
+ERROR:
+ if (hexdigest_blake2b512)
+ free(hexdigest_blake2b512);
+ if (request)
+ json_object_put(request);
+ if (xfer)
+ pakfire_xfer_unref(xfer);
return r;
}