Implement FileArchive progress/cancel
* Use PBD::Progress API * Allow to cancel extraction and compression * Fix querying download size
This commit is contained in:
parent
2cb4e8a6ca
commit
c9929698ee
|
@ -39,6 +39,7 @@
|
||||||
#include "pbd/file_archive.h"
|
#include "pbd/file_archive.h"
|
||||||
#include "pbd/file_utils.h"
|
#include "pbd/file_utils.h"
|
||||||
#include "pbd/pthread_utils.h"
|
#include "pbd/pthread_utils.h"
|
||||||
|
#include "pbd/progress.h"
|
||||||
|
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
|
@ -69,11 +70,14 @@ get_url (void* arg)
|
||||||
curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
|
||||||
/* get size */
|
/* get size */
|
||||||
if (r->mp.progress) {
|
if (r->mp.query_length) {
|
||||||
|
double content_length = 0;
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
|
curl_easy_setopt(curl, CURLOPT_HEADER, 0L);
|
||||||
curl_easy_perform (curl);
|
curl_easy_perform (curl);
|
||||||
curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &r->mp.length);
|
if (CURLE_OK == curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length) && content_length > 0) {
|
||||||
|
r->mp.length = content_length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
|
||||||
|
@ -113,8 +117,8 @@ ar_read (struct archive* a, void* d, const void** buff)
|
||||||
p->size -= rv;
|
p->size -= rv;
|
||||||
p->processed += rv;
|
p->processed += rv;
|
||||||
*buff = p->buf;
|
*buff = p->buf;
|
||||||
if (p->progress) {
|
if (p->progress && p->length > 0) {
|
||||||
p->progress->progress (p->processed, p->length);
|
p->progress->set_progress ((float)p->processed / p->length);
|
||||||
}
|
}
|
||||||
p->unlock ();
|
p->unlock ();
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -153,8 +157,9 @@ setup_archive ()
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileArchive::FileArchive (const std::string& url)
|
FileArchive::FileArchive (const std::string& url, Progress* p)
|
||||||
: _req (url)
|
: _req (url, p)
|
||||||
|
, _progress (p)
|
||||||
, _current_entry (0)
|
, _current_entry (0)
|
||||||
, _archive (0)
|
, _archive (0)
|
||||||
{
|
{
|
||||||
|
@ -164,9 +169,9 @@ FileArchive::FileArchive (const std::string& url)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_req.is_remote ()) {
|
if (_req.is_remote ()) {
|
||||||
_req.mp.progress = this;
|
_req.mp.query_length = true;
|
||||||
} else {
|
} else {
|
||||||
_req.mp.progress = 0;
|
_req.mp.query_length = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,12 +183,6 @@ FileArchive::~FileArchive ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
FileArchive::require_progress ()
|
|
||||||
{
|
|
||||||
_req.mp.progress = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
FileArchive::fetch (const std::string & url, const std::string & destdir) const
|
FileArchive::fetch (const std::string & url, const std::string & destdir) const
|
||||||
{
|
{
|
||||||
|
@ -213,26 +212,6 @@ FileArchive::fetch (const std::string & url, const std::string & destdir) const
|
||||||
return Glib::build_filename (destdir, Glib::path_get_basename (url));
|
return Glib::build_filename (destdir, Glib::path_get_basename (url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
FileArchive::make_local (const std::string& destdir)
|
|
||||||
{
|
|
||||||
if (!_req.is_remote()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string downloaded = fetch (_req.url, destdir);
|
|
||||||
|
|
||||||
if (downloaded.empty()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_req.url = strdup (downloaded.c_str());
|
|
||||||
_req.mp.progress = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
FileArchive::inflate (const std::string& destdir)
|
FileArchive::inflate (const std::string& destdir)
|
||||||
{
|
{
|
||||||
|
@ -277,10 +256,9 @@ FileArchive::next_file_name ()
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = archive_read_next_header (_archive, &_current_entry);
|
int r = archive_read_next_header (_archive, &_current_entry);
|
||||||
if (!_req.mp.progress) {
|
if (_progress && _req.mp.length > 0) {
|
||||||
// file i/o -- not URL
|
|
||||||
const uint64_t read = archive_filter_bytes (_archive, -1);
|
const uint64_t read = archive_filter_bytes (_archive, -1);
|
||||||
progress (read, _req.mp.length);
|
_progress->set_progress ((float) read / _req.mp.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == ARCHIVE_EOF) {
|
if (r == ARCHIVE_EOF) {
|
||||||
|
@ -384,7 +362,6 @@ FileArchive::extract_url ()
|
||||||
{
|
{
|
||||||
_req.mp.reset ();
|
_req.mp.reset ();
|
||||||
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
pthread_create (&_tid, NULL, get_url, (void*)&_req);
|
||||||
|
|
||||||
struct archive* a = setup_archive ();
|
struct archive* a = setup_archive ();
|
||||||
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
archive_read_open (a, (void*)&_req.mp, NULL, ar_read, NULL);
|
||||||
int rv = do_extract (a);
|
int rv = do_extract (a);
|
||||||
|
@ -400,10 +377,9 @@ FileArchive::get_contents (struct archive* a)
|
||||||
struct archive_entry* entry;
|
struct archive_entry* entry;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int r = archive_read_next_header (a, &entry);
|
int r = archive_read_next_header (a, &entry);
|
||||||
if (!_req.mp.progress) {
|
if (_progress && _req.mp.length > 0) {
|
||||||
// file i/o -- not URL
|
|
||||||
const uint64_t read = archive_filter_bytes (a, -1);
|
const uint64_t read = archive_filter_bytes (a, -1);
|
||||||
progress (read, _req.mp.length);
|
_progress->set_progress ((float) read / _req.mp.length);
|
||||||
}
|
}
|
||||||
if (r == ARCHIVE_EOF) {
|
if (r == ARCHIVE_EOF) {
|
||||||
break;
|
break;
|
||||||
|
@ -435,10 +411,13 @@ FileArchive::do_extract (struct archive* a)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int r = archive_read_next_header (a, &entry);
|
int r = archive_read_next_header (a, &entry);
|
||||||
|
|
||||||
if (_req.mp.progress) {
|
if (_progress && _req.mp.length > 0) {
|
||||||
// file i/o -- not URL
|
|
||||||
const uint64_t read = archive_filter_bytes (a, -1);
|
const uint64_t read = archive_filter_bytes (a, -1);
|
||||||
progress (read, _req.mp.length);
|
_progress->set_progress ((float)read / _req.mp.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_progress && _progress->cancelled ()) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == ARCHIVE_EOF) {
|
if (r == ARCHIVE_EOF) {
|
||||||
|
@ -468,6 +447,10 @@ FileArchive::do_extract (struct archive* a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_progress && !_progress->cancelled ()) {
|
||||||
|
_progress->set_progress (1.f);
|
||||||
|
}
|
||||||
|
|
||||||
archive_read_close (a);
|
archive_read_close (a);
|
||||||
archive_read_free (a);
|
archive_read_free (a);
|
||||||
archive_write_close(ext);
|
archive_write_close(ext);
|
||||||
|
@ -503,6 +486,10 @@ FileArchive::create (const std::string& srcdir, CompressionLevel compression_lev
|
||||||
int
|
int
|
||||||
FileArchive::create (const std::map<std::string, std::string>& filemap, CompressionLevel compression_level)
|
FileArchive::create (const std::map<std::string, std::string>& filemap, CompressionLevel compression_level)
|
||||||
{
|
{
|
||||||
|
if (_req.is_remote ()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct archive *a;
|
struct archive *a;
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
|
|
||||||
|
@ -521,7 +508,9 @@ FileArchive::create (const std::map<std::string, std::string>& filemap, Compress
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
progress (0, total_bytes);
|
if (_progress) {
|
||||||
|
_progress->set_progress (0);
|
||||||
|
}
|
||||||
|
|
||||||
a = archive_write_new ();
|
a = archive_write_new ();
|
||||||
archive_write_set_format_pax_restricted (a);
|
archive_write_set_format_pax_restricted (a);
|
||||||
|
@ -574,16 +563,32 @@ FileArchive::create (const std::map<std::string, std::string>& filemap, Compress
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
read_bytes += len;
|
read_bytes += len;
|
||||||
archive_write_data (a, buf, len);
|
archive_write_data (a, buf, len);
|
||||||
progress (read_bytes, total_bytes);
|
if (_progress) {
|
||||||
|
_progress->set_progress ((float)read_bytes / total_bytes);
|
||||||
|
if (_progress->cancelled ()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
len = read (fd, buf, sizeof (buf));
|
len = read (fd, buf, sizeof (buf));
|
||||||
}
|
}
|
||||||
close (fd);
|
close (fd);
|
||||||
|
if (_progress && _progress->cancelled ()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
archive_entry_free (entry);
|
archive_entry_free (entry);
|
||||||
archive_write_close (a);
|
archive_write_close (a);
|
||||||
archive_write_free (a);
|
archive_write_free (a);
|
||||||
|
|
||||||
|
if (_progress) {
|
||||||
|
if (_progress->cancelled ()) {
|
||||||
|
g_unlink (_req.url);
|
||||||
|
} else {
|
||||||
|
_progress->set_progress (1.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const int64_t elapsed_time_us = g_get_monotonic_time() - archive_start_time;
|
const int64_t elapsed_time_us = g_get_monotonic_time() - archive_start_time;
|
||||||
std::cerr << "archived in " << std::fixed << std::setprecision (2) << elapsed_time_us / 1000000. << " sec\n";
|
std::cerr << "archived in " << std::fixed << std::setprecision (2) << elapsed_time_us / 1000000. << " sec\n";
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
Inflater::Inflater (std::string const & ap, std::string const & dd)
|
Inflater::Inflater (std::string const & ap, std::string const & dd)
|
||||||
: FileArchive (ap)
|
: FileArchive (ap, this)
|
||||||
, thread (0)
|
, thread (0)
|
||||||
, _status (-1) /* means "unknown" */
|
, _status (-1) /* means "unknown" */
|
||||||
, archive_path (ap)
|
, archive_path (ap)
|
||||||
|
@ -51,8 +51,6 @@ Inflater::start ()
|
||||||
void
|
void
|
||||||
Inflater::threaded_inflate ()
|
Inflater::threaded_inflate ()
|
||||||
{
|
{
|
||||||
require_progress ();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string pwd (Glib::get_current_dir ());
|
std::string pwd (Glib::get_current_dir ());
|
||||||
|
|
||||||
|
@ -72,6 +70,11 @@ Inflater::threaded_inflate ()
|
||||||
* set to be >= 0
|
* set to be >= 0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
progress (1, 1);
|
set_progress (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Inflater::set_overall_progress (float p)
|
||||||
|
{
|
||||||
|
Progress (p); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
|
|
|
@ -30,18 +30,17 @@
|
||||||
|
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
|
class Progress;
|
||||||
|
|
||||||
class LIBPBD_API FileArchive
|
class LIBPBD_API FileArchive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileArchive (const std::string& url);
|
FileArchive (const std::string& url, Progress* p = NULL);
|
||||||
~FileArchive ();
|
~FileArchive ();
|
||||||
|
|
||||||
int inflate (const std::string& destdir);
|
int inflate (const std::string& destdir);
|
||||||
std::vector<std::string> contents ();
|
std::vector<std::string> contents ();
|
||||||
|
|
||||||
int make_local (const std::string& destdir);
|
|
||||||
|
|
||||||
std::string next_file_name ();
|
std::string next_file_name ();
|
||||||
int extract_current_file (const std::string& destpath);
|
int extract_current_file (const std::string& destpath);
|
||||||
|
|
||||||
|
@ -57,15 +56,12 @@ class LIBPBD_API FileArchive
|
||||||
int create (const std::string& srcdir, CompressionLevel compression_level = CompressGood);
|
int create (const std::string& srcdir, CompressionLevel compression_level = CompressGood);
|
||||||
int create (const std::map <std::string, std::string>& filemap, CompressionLevel compression_level = CompressGood);
|
int create (const std::map <std::string, std::string>& filemap, CompressionLevel compression_level = CompressGood);
|
||||||
|
|
||||||
PBD::Signal2<void, size_t, size_t> progress; // TODO
|
|
||||||
|
|
||||||
void require_progress ();
|
|
||||||
|
|
||||||
struct MemPipe {
|
struct MemPipe {
|
||||||
public:
|
public:
|
||||||
MemPipe ()
|
MemPipe (Progress* p)
|
||||||
: data (NULL)
|
: data (NULL)
|
||||||
, progress (0)
|
, query_length (false)
|
||||||
|
, progress (p)
|
||||||
{
|
{
|
||||||
pthread_mutex_init (&_lock, NULL);
|
pthread_mutex_init (&_lock, NULL);
|
||||||
pthread_cond_init (&_ready, NULL);
|
pthread_cond_init (&_ready, NULL);
|
||||||
|
@ -90,7 +86,7 @@ class LIBPBD_API FileArchive
|
||||||
size = 0;
|
size = 0;
|
||||||
done = false;
|
done = false;
|
||||||
processed = 0;
|
processed = 0;
|
||||||
length = -1;
|
length = 0;
|
||||||
unlock ();
|
unlock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,9 +100,11 @@ class LIBPBD_API FileArchive
|
||||||
size_t size;
|
size_t size;
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
size_t processed;
|
size_t processed;
|
||||||
size_t length;
|
size_t length;
|
||||||
FileArchive* progress;
|
bool query_length;
|
||||||
|
|
||||||
|
Progress* progress;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pthread_mutex_t _lock;
|
pthread_mutex_t _lock;
|
||||||
|
@ -115,7 +113,8 @@ class LIBPBD_API FileArchive
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
public:
|
public:
|
||||||
Request (const std::string& u)
|
Request (const std::string& u, Progress* p)
|
||||||
|
: mp (p)
|
||||||
{
|
{
|
||||||
if (u.size () > 0) {
|
if (u.size () > 0) {
|
||||||
url = strdup (u.c_str());
|
url = strdup (u.c_str());
|
||||||
|
@ -142,7 +141,6 @@ class LIBPBD_API FileArchive
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int process_file ();
|
int process_file ();
|
||||||
int process_url ();
|
int process_url ();
|
||||||
|
|
||||||
|
@ -159,13 +157,15 @@ class LIBPBD_API FileArchive
|
||||||
|
|
||||||
struct archive* setup_file_archive ();
|
struct archive* setup_file_archive ();
|
||||||
|
|
||||||
|
std::string fetch (const std::string & url, const std::string& destdir) const;
|
||||||
|
|
||||||
Request _req;
|
Request _req;
|
||||||
pthread_t _tid;
|
pthread_t _tid;
|
||||||
|
|
||||||
|
Progress* _progress;
|
||||||
|
|
||||||
struct archive_entry* _current_entry;
|
struct archive_entry* _current_entry;
|
||||||
struct archive* _archive;
|
struct archive* _archive;
|
||||||
|
|
||||||
std::string fetch (const std::string & url, const std::string& destdir) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "pbd/file_archive.h"
|
#include "pbd/file_archive.h"
|
||||||
#include "pbd/libpbd_visibility.h"
|
#include "pbd/libpbd_visibility.h"
|
||||||
|
#include "pbd/progress.h"
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
class Thread;
|
class Thread;
|
||||||
|
@ -30,7 +31,7 @@ namespace PBD {
|
||||||
|
|
||||||
namespace PBD {
|
namespace PBD {
|
||||||
|
|
||||||
class LIBPBD_API Inflater : public PBD::FileArchive
|
class LIBPBD_API Inflater : public PBD::FileArchive , public PBD::Progress
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Inflater (std::string const & archive_path, std::string const & destdir);
|
Inflater (std::string const & archive_path, std::string const & destdir);
|
||||||
|
@ -40,13 +41,17 @@ class LIBPBD_API Inflater : public PBD::FileArchive
|
||||||
bool running() const { return thread != 0; }
|
bool running() const { return thread != 0; }
|
||||||
int status() const { return _status; }
|
int status() const { return _status; }
|
||||||
|
|
||||||
private:
|
PBD::Signal1<void, float> Progress;
|
||||||
|
|
||||||
|
private:
|
||||||
PBD::Thread* thread;
|
PBD::Thread* thread;
|
||||||
int _status;
|
int _status;
|
||||||
std::string archive_path;
|
std::string archive_path;
|
||||||
std::string destdir;
|
std::string destdir;
|
||||||
|
|
||||||
void threaded_inflate ();
|
void threaded_inflate ();
|
||||||
|
|
||||||
|
void set_overall_progress (float p);
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
Loading…
Reference in New Issue