diff mbox series

[4/8] channel_curl: emit download progress

Message ID 20180305154006.18122-4-christian.storm@siemens.com
State Accepted
Headers show
Series [1/8] channel_curl: add support for Basic Auth credentials | expand

Commit Message

Storm, Christian March 5, 2018, 3:40 p.m. UTC
Emit the download progress via the notification system as
SUBPROCESS, so that it also gets forwarded to the progress
interface, in preparation to make the downloader process use
channel_curl and be able to report progress over the progress
interface.

Signed-off-by: Christian Storm <christian.storm@siemens.com>
---
 corelib/channel_curl.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

Comments

Stefano Babic March 7, 2018, 10:43 a.m. UTC | #1
Hi Christian,

On 05/03/2018 16:40, Christian Storm wrote:
> Emit the download progress via the notification system as
> SUBPROCESS, so that it also gets forwarded to the progress
> interface, in preparation to make the downloader process use
> channel_curl and be able to report progress over the progress
> interface.
> 
> Signed-off-by: Christian Storm <christian.storm@siemens.com>
> ---
>  corelib/channel_curl.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
> 
> diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
> index ea23f61..1bac778 100644
> --- a/corelib/channel_curl.c
> +++ b/corelib/channel_curl.c
> @@ -11,6 +11,7 @@
>  #include <assert.h>
>  #include <stdarg.h>
>  #include <unistd.h>
> +#include <math.h>
>  #include <curl/curl.h>
>  #include <json-c/json.h>
>  #include <generated/autoconf.h>
> @@ -327,6 +328,37 @@ channel_op_res_t channel_map_curl_error(CURLcode res)
>  	}
>  }
>  
> +static int channel_callback_xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow,
> +				     curl_off_t __attribute__((__unused__)) ultotal,
> +				     curl_off_t __attribute__((__unused__)) ulnow)
> +{
> +	if ((dltotal <= 0) || (dlnow > dltotal)) {
> +		return 0;
> +	}
> +	double percent = 100.0 * (dlnow/1024.0) / (dltotal/1024.0);
> +	double *last_percent = (double*)p;
> +	if ((int)*last_percent == (int)percent) {
> +		return 0;
> +	}
> +	*last_percent = percent;
> +	char *info;
> +	if (asprintf(&info,
> +					"{\"percent\": %d, \"msg\":\"Received %" CURL_FORMAT_CURL_OFF_T "B "
> +					"of %" CURL_FORMAT_CURL_OFF_T "B\"}",
> +					(int)percent, dlnow, dltotal) != ENOMEM_ASPRINTF) {
> +		notify(SUBPROCESS, RECOVERY_NO_ERROR, TRACELEVEL, info);
> +		free(info);
> +	}

I was thinking about if there is another and more readable way to do
this, calling a swupdate_progress* function....the progress interface
has a dwl_percent field, but it cannot be used due to separation of
processes. The installer is the one updating the progress, and in fact
this is the only case where we need to pass something else.

Nevertheless, the message is reaching the listeners, and they can
process it if they want to output the download's percentage.

Let's do in this way.


> +	return 0;
> +}
> +
> +static int channel_callback_xferinfo_legacy(void *p, double dltotal, double dlnow,
> +					    double ultotal, double ulnow)
> +{
> +	return channel_callback_xferinfo(p, (curl_off_t)dltotal, (curl_off_t)dlnow,
> +					 (curl_off_t)ultotal, (curl_off_t)ulnow);
> +}
> +
>  channel_op_res_t channel_set_options(channel_t *this,
>  					channel_data_t *channel_data,
>  					channel_method_t method)
> @@ -368,6 +400,28 @@ channel_op_res_t channel_set_options(channel_t *this,
>  		goto cleanup;
>  	}
>  
> +	double percent = -INFINITY;
> +	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_PROGRESSFUNCTION,
> +			      channel_callback_xferinfo_legacy) != CURLE_OK) ||
> +	    (curl_easy_setopt(channel_curl->handle, CURLOPT_PROGRESSDATA,
> +				  &percent) != CURLE_OK)) {
> +		result = CHANNEL_EINIT;
> +		goto cleanup;
> +	}
> +#if LIBCURL_VERSION_NUM >= 0x072000
> +	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_XFERINFOFUNCTION,
> +			      channel_callback_xferinfo) != CURLE_OK) ||
> +	    (curl_easy_setopt(channel_curl->handle, CURLOPT_XFERINFODATA,
> +				  &percent) != CURLE_OK)) {
> +		result = CHANNEL_EINIT;
> +		goto cleanup;
> +	}
> +#endif
> +	if (curl_easy_setopt(channel_curl->handle, CURLOPT_NOPROGRESS, 0L) != CURLE_OK) {
> +		result = CHANNEL_EINIT;
> +		goto cleanup;
> +	}
> +
>  	if (channel_data->strictssl == true) {
>  		if ((curl_easy_setopt(channel_curl->handle,
>  				      CURLOPT_SSL_VERIFYHOST,
> 


Best regards,
Stefano Babic
Storm, Christian March 7, 2018, 12:23 p.m. UTC | #2
Hi Stefano,

> > +	if (asprintf(&info,
> > +					"{\"percent\": %d, \"msg\":\"Received %" CURL_FORMAT_CURL_OFF_T "B "
> > +					"of %" CURL_FORMAT_CURL_OFF_T "B\"}",
> > +					(int)percent, dlnow, dltotal) != ENOMEM_ASPRINTF) {
> > +		notify(SUBPROCESS, RECOVERY_NO_ERROR, TRACELEVEL, info);
> > +		free(info);
> > +	}
> 
> I was thinking about if there is another and more readable way to do
> this, calling a swupdate_progress* function....the progress interface
> has a dwl_percent field, but it cannot be used due to separation of
> processes. The installer is the one updating the progress, and in fact
> this is the only case where we need to pass something else.
> 
> Nevertheless, the message is reaching the listeners, and they can
> process it if they want to output the download's percentage.
> 
> Let's do in this way.

yes, I also thought about this and came to the same conclusion :)
I envisioned a progress client that, e.g., drives some display which may
also be able to present some more information, hence I opted for JSON as
it's extensible should the need arise...


Kind regards,
   Christian
diff mbox series

Patch

diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
index ea23f61..1bac778 100644
--- a/corelib/channel_curl.c
+++ b/corelib/channel_curl.c
@@ -11,6 +11,7 @@ 
 #include <assert.h>
 #include <stdarg.h>
 #include <unistd.h>
+#include <math.h>
 #include <curl/curl.h>
 #include <json-c/json.h>
 #include <generated/autoconf.h>
@@ -327,6 +328,37 @@  channel_op_res_t channel_map_curl_error(CURLcode res)
 	}
 }
 
+static int channel_callback_xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow,
+				     curl_off_t __attribute__((__unused__)) ultotal,
+				     curl_off_t __attribute__((__unused__)) ulnow)
+{
+	if ((dltotal <= 0) || (dlnow > dltotal)) {
+		return 0;
+	}
+	double percent = 100.0 * (dlnow/1024.0) / (dltotal/1024.0);
+	double *last_percent = (double*)p;
+	if ((int)*last_percent == (int)percent) {
+		return 0;
+	}
+	*last_percent = percent;
+	char *info;
+	if (asprintf(&info,
+					"{\"percent\": %d, \"msg\":\"Received %" CURL_FORMAT_CURL_OFF_T "B "
+					"of %" CURL_FORMAT_CURL_OFF_T "B\"}",
+					(int)percent, dlnow, dltotal) != ENOMEM_ASPRINTF) {
+		notify(SUBPROCESS, RECOVERY_NO_ERROR, TRACELEVEL, info);
+		free(info);
+	}
+	return 0;
+}
+
+static int channel_callback_xferinfo_legacy(void *p, double dltotal, double dlnow,
+					    double ultotal, double ulnow)
+{
+	return channel_callback_xferinfo(p, (curl_off_t)dltotal, (curl_off_t)dlnow,
+					 (curl_off_t)ultotal, (curl_off_t)ulnow);
+}
+
 channel_op_res_t channel_set_options(channel_t *this,
 					channel_data_t *channel_data,
 					channel_method_t method)
@@ -368,6 +400,28 @@  channel_op_res_t channel_set_options(channel_t *this,
 		goto cleanup;
 	}
 
+	double percent = -INFINITY;
+	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_PROGRESSFUNCTION,
+			      channel_callback_xferinfo_legacy) != CURLE_OK) ||
+	    (curl_easy_setopt(channel_curl->handle, CURLOPT_PROGRESSDATA,
+				  &percent) != CURLE_OK)) {
+		result = CHANNEL_EINIT;
+		goto cleanup;
+	}
+#if LIBCURL_VERSION_NUM >= 0x072000
+	if ((curl_easy_setopt(channel_curl->handle, CURLOPT_XFERINFOFUNCTION,
+			      channel_callback_xferinfo) != CURLE_OK) ||
+	    (curl_easy_setopt(channel_curl->handle, CURLOPT_XFERINFODATA,
+				  &percent) != CURLE_OK)) {
+		result = CHANNEL_EINIT;
+		goto cleanup;
+	}
+#endif
+	if (curl_easy_setopt(channel_curl->handle, CURLOPT_NOPROGRESS, 0L) != CURLE_OK) {
+		result = CHANNEL_EINIT;
+		goto cleanup;
+	}
+
 	if (channel_data->strictssl == true) {
 		if ((curl_easy_setopt(channel_curl->handle,
 				      CURLOPT_SSL_VERIFYHOST,