diff --git a/.gitignore b/.gitignore index c000a5911a5..55a4eb0e31b 100644 --- a/.gitignore +++ b/.gitignore @@ -194,3 +194,4 @@ scripts/templates/vs2019/emptyExample.vcxproj.user libs/openFrameworksCompiled/project/android/build-*/ +examples/utils/urlFileLoaderExample/bin/data diff --git a/examples/utils/urlFileLoaderExample/bin/data/.gitkeep b/examples/utils/urlFileLoaderExample/bin/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/utils/urlFileLoaderExample/src/main.cpp b/examples/utils/urlFileLoaderExample/src/main.cpp new file mode 100644 index 00000000000..946adb5c408 --- /dev/null +++ b/examples/utils/urlFileLoaderExample/src/main.cpp @@ -0,0 +1,13 @@ +#include "ofMain.h" +#include "ofApp.h" + +//======================================================================== +int main() { + ofGLWindowSettings settings; + settings.setSize(720, 240); + settings.windowMode = OF_WINDOW; + + auto window = ofCreateWindow(settings); + ofRunApp(window, std::make_shared()); + ofRunMainLoop(); +} diff --git a/examples/utils/urlFileLoaderExample/src/ofApp.cpp b/examples/utils/urlFileLoaderExample/src/ofApp.cpp new file mode 100644 index 00000000000..29a19dae318 --- /dev/null +++ b/examples/utils/urlFileLoaderExample/src/ofApp.cpp @@ -0,0 +1,36 @@ +#include "ofApp.h" + +//-------------------------------------------------------------- +void ofApp::setup() { + ofSetWindowTitle("URL file loader progress"); + ofSetBackgroundColor(30); + + const std::string url = "https://raw.githubusercontent.com/openframeworks/openFrameworks/master/examples/graphics/fontShapesExample/bin/data/Batang.ttf"; + ofHttpRequest request(url, ofToDataPath("Batang.ttf"), true); + request.progressCallback = [this](const ofHttpRequest &, float value) { + progress.store(value); + }; + request.done = [this](const ofHttpResponse & response) { + status = response.status; + finished = true; + }; + loader.handleRequestAsync(request); +} + +//-------------------------------------------------------------- +void ofApp::draw() { + const float value = progress.load(); + const float width = ofGetWidth() - 80.0f; + + ofSetColor(90); + ofDrawRectangle(40, 100, width, 24); + ofSetColor(70, 180, 255); + ofDrawRectangle(40, 100, width * value, 24); + + ofSetColor(255); + ofDrawBitmapString("Downloading Batang.ttf", 40, 70); + ofDrawBitmapString(ofToString(value * 100.0f, 1) + "%", 40, 150); + if (finished) { + ofDrawBitmapString("Finished with HTTP status " + ofToString(status), 40, 185); + } +} diff --git a/examples/utils/urlFileLoaderExample/src/ofApp.h b/examples/utils/urlFileLoaderExample/src/ofApp.h new file mode 100644 index 00000000000..ba076b26a90 --- /dev/null +++ b/examples/utils/urlFileLoaderExample/src/ofApp.h @@ -0,0 +1,17 @@ +#pragma once + +#include "ofMain.h" + +#include + +class ofApp : public ofBaseApp { +public: + void setup() override; + void draw() override; + +private: + ofURLFileLoader loader; + std::atomic progress{ 0.0f }; + bool finished = false; + int status = 0; +}; diff --git a/libs/openFrameworks/utils/ofURLFileLoader.cpp b/libs/openFrameworks/utils/ofURLFileLoader.cpp index b35893abe83..297aafc40f2 100644 --- a/libs/openFrameworks/utils/ofURLFileLoader.cpp +++ b/libs/openFrameworks/utils/ofURLFileLoader.cpp @@ -348,18 +348,12 @@ size_t readBody_cb(void * ptr, size_t size, size_t nmemb, void * userdata) { } return 0; /* no more data left to deliver */ } -int progress_cb(void* ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { - auto & request = *static_cast(ptr); - if (request.progressCallback) { - float progress = 0.0f; - if (request.method == ofHttpRequest::GET && dltotal > 0) { - progress = (float)dlnow / (float)dltotal; - // note: we may want to support upload and download for POST - } else if ((request.method == ofHttpRequest::PUT || request.method == ofHttpRequest::POST) && ultotal > 0) { - progress = (float)ulnow / (float)ultotal; - } - - request.progressCallback(request, progress); +int transferProgress_cb(void * userdata, curl_off_t downloadTotal, curl_off_t downloaded, curl_off_t uploadTotal, curl_off_t uploaded) { + const auto & request = *static_cast(userdata); + if (request.method == ofHttpRequest::GET && downloadTotal > 0) { + request.progressCallback(request, static_cast(downloaded) / static_cast(downloadTotal)); + } else if ((request.method == ofHttpRequest::PUT || request.method == ofHttpRequest::POST) && uploadTotal > 0) { + request.progressCallback(request, static_cast(uploaded) / static_cast(uploadTotal)); } return 0; } @@ -536,13 +530,13 @@ ofHttpResponse ofURLFileLoaderImpl::handleRequest(const ofHttpRequest & request) // start request and receive response ofHttpResponse response(request, 0, ""); CURLcode err = CURLE_OK; - + if (request.progressCallback) { - curl_easy_setopt(curl.get(), CURLOPT_XFERINFOFUNCTION, progress_cb); + curl_easy_setopt(curl.get(), CURLOPT_XFERINFOFUNCTION, transferProgress_cb); curl_easy_setopt(curl.get(), CURLOPT_XFERINFODATA, &request); curl_easy_setopt(curl.get(), CURLOPT_NOPROGRESS, 0L); } - + if (request.saveTo) { ofFile saveTo(request.name, ofFile::WriteOnly, true); curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &saveTo); diff --git a/libs/openFrameworks/utils/ofURLFileLoader.h b/libs/openFrameworks/utils/ofURLFileLoader.h index e32b2786ec8..0e637acdf3a 100644 --- a/libs/openFrameworks/utils/ofURLFileLoader.h +++ b/libs/openFrameworks/utils/ofURLFileLoader.h @@ -23,7 +23,8 @@ class ofHttpRequest { std::string body; ///< POST body data std::string contentType; ///< POST data mime type std::function done; - std::function progressCallback = nullptr; ///< pass a function for progress of download + /// the URL loader's worker thread. range [0, 1] + std::function progressCallback = nullptr; // it reports upload/download progress. Asynchronous requests invoke this callback size_t timeoutSeconds = 0; bool headerOnly = false;