adds primitive progress indicator

Mon, 18 Dec 2017 16:24:32 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 18 Dec 2017 16:24:32 +0100
changeset 355
5da2cf15eb44
parent 354
067ea2315a8a
child 356
699781a1d6fd
child 361
b6f2462ee055

adds primitive progress indicator

dav/main.c file | annotate | diff | comparison | revisions
dav/main.h file | annotate | diff | comparison | revisions
dav/optparser.c file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/session.c file | annotate | diff | comparison | revisions
libidav/session.h file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
--- a/dav/main.c	Mon Dec 18 11:56:11 2017 +0100
+++ b/dav/main.c	Mon Dec 18 16:24:32 2017 +0100
@@ -374,6 +374,35 @@
     return sn;
 }
 
+int update_progress(DavResource *res, int64_t total, int64_t now, Progress *p) {
+    int ret = 0;
+    if(res != p->last_resource) {
+        p->cur += p->last_res_total - p->last_res_cur;
+        ret = 1;
+    } else {
+        p->cur += now - p->last_res_cur;
+    }
+    
+    p->last_resource = res;
+    p->last_res_cur = now;
+    p->last_res_total = total;
+    
+    return ret;
+}
+
+void download_progress(DavResource *res, int64_t total, int64_t now, void *data) {
+    Progress *p = data;
+    int newres = update_progress(res, total, now, p);
+    
+    time_t newts = time(NULL);
+    if(newres || (p->ts != newts)) {
+        fprintf(p->out, "[%s]: %" PRId64 "k/%" PRId64 "k total: %" PRId64 "M/%" PRId64 "M\n", res->name, now/1024, total/1024, p->cur/(1024*1024), p->total/(1024*1024));
+        fflush(p->out);
+    }
+    p->ts = newts;
+}
+
+
 #define LIST_QUERY_ORDER_BY_NAME "select `idav:crypto-name`,`idav:crypto-key`,D:lockdiscovery,apache:executable from %s with depth = %d where lastmodified > %t order by iscollection desc, name"
 #define LIST_QUERY_ORDER_BY_DATE "select `idav:crypto-name`,`idav:crypto-key`,D:lockdiscovery,apache:executable from %s with depth = %d where lastmodified > %t order by iscollection desc, lastmodified desc"
 
@@ -656,6 +685,21 @@
         return -1;
     }
     
+    char *progressfile = cmd_getoption(a, "progressfile");
+    Progress pdata;
+    memset(&pdata, 0, sizeof(Progress));
+    if(progressfile) {
+        if(!strcmp(progressfile, "-")) {
+            pdata.out = stdout;
+            pdata.isstdout = 1;
+        } else {
+            pdata.out = fopen(progressfile, "w");
+        }
+        if(pdata.out) {
+            dav_session_set_progresscallback(sn, download_progress, NULL, &pdata);
+        }
+    }
+    
     char *update = cmd_getoption(a, "update");
     time_t t = -1;
     if(update) {
@@ -764,6 +808,8 @@
     }
     
     // download resources
+    pdata.total = totalsize;
+    
     int ret;
     getfunc get;
     TarOutputStream *tout = NULL;
@@ -798,6 +844,9 @@
     ucx_list_free(reslist);
     free(path);
     
+    if(pdata.out && !pdata.isstdout) {
+        fclose(pdata.out);
+    }
     return ret;
 }
 
--- a/dav/main.h	Mon Dec 18 11:56:11 2017 +0100
+++ b/dav/main.h	Mon Dec 18 16:24:32 2017 +0100
@@ -29,6 +29,7 @@
 #ifndef MAIN_H
 #define	MAIN_H
 
+#include <time.h>
 #include <curl/curl.h>
 #include "optparser.h"
 #include <libidav/webdav.h>
@@ -45,12 +46,26 @@
     char        *path;
 } GetResource;
 
+typedef struct {
+    FILE        *out;
+    int         isstdout;
+    int64_t     total;
+    int64_t     cur;
+    int64_t     last_res_cur;
+    int64_t     last_res_total;
+    DavResource *last_resource;
+    time_t      ts;
+} Progress;
+
 typedef int(*getfunc)(Repository *, GetResource *, CmdArgs *, void *);
     
 void print_usage(char *cmd);
 char* password_input(char *prompt);
 int request_auth(Repository *repo, DavSession *sn, CmdArgs *args);
 
+int update_progress(DavResource *res, int64_t total, int64_t now, Progress *p);
+void download_progress(DavResource *res, int64_t total, int64_t now, void *data);
+
 int cmd_list(CmdArgs *args);
 void ls_print_list_elm(DavResource *res, char *parent, CmdArgs *args);
 void ls_print_elm(DavResource *res, char *parent, CmdArgs *args);
--- a/dav/optparser.c	Mon Dec 18 11:56:11 2017 +0100
+++ b/dav/optparser.c	Mon Dec 18 16:24:32 2017 +0100
@@ -210,6 +210,20 @@
                         }
                         break;
                     }
+                    case 'F': {
+                        if(!option) {
+                            option = "progressfile";
+                            optchar = 'F';
+                        } else {
+                            fprintf(
+                                    stderr,
+                                    "Missing argument for option -%c\n",
+                                    optchar);
+                            cmd_args_free(a);
+                            return NULL;
+                        }
+                        break;
+                    }
                 }
             }
         } else if(option) {
--- a/libidav/resource.c	Mon Dec 18 11:56:11 2017 +0100
+++ b/libidav/resource.c	Mon Dec 18 16:24:32 2017 +0100
@@ -765,9 +765,21 @@
     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_fnc);
     curl_easy_setopt(handle, CURLOPT_WRITEDATA, stream);
     
+    if(sn->get_progress) {
+        curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, dav_session_get_progress);
+        curl_easy_setopt(handle, CURLOPT_XFERINFODATA, res);
+        curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
+    }
+    
     long status = 0;
     CURLcode ret = dav_session_curl_perform(sn, &status);
     
+    if(sn->get_progress) {
+        curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, NULL);
+        curl_easy_setopt(handle, CURLOPT_XFERINFODATA, NULL);
+        curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1L);
+    }
+    
     char *hash = NULL;
     if(dec) {
         aes_decrypter_shutdown(dec); // get final bytes
--- a/libidav/session.c	Mon Dec 18 11:56:11 2017 +0100
+++ b/libidav/session.c	Mon Dec 18 16:24:32 2017 +0100
@@ -47,6 +47,7 @@
         return NULL;
     }
     DavSession *sn = malloc(sizeof(DavSession));
+    memset(sn, 0, sizeof(DavSession));
     sn->mp = ucx_mempool_new(DAV_SESSION_MEMPOOL_SIZE);
     sn->pathcache = ucx_map_new_a(sn->mp->allocator, DAV_PATH_CACHE_SIZE);
     sn->key = NULL;
@@ -145,6 +146,12 @@
     sn->authprompt_userdata = userdata;
 }
 
+void dav_session_set_progresscallback(DavSession *sn, dav_progress_func get, dav_progress_func put, void *userdata) {
+    sn->get_progress = get;
+    sn->put_progress = put;
+    sn->progress_userdata = userdata;
+}
+
 CURLcode dav_session_curl_perform(DavSession *sn, long *status) {
     return dav_session_curl_perform_buf(sn, NULL, NULL, status);
 }
@@ -171,6 +178,24 @@
     return ret;
 }
 
+int dav_session_get_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
+    DavResource *res = clientp;
+    DavSession *sn = res->session;
+    if(sn->get_progress) {
+        sn->get_progress(res, (int64_t)dltotal, (int64_t)dlnow, sn->progress_userdata);
+    }
+    return 0;
+}
+
+int dav_session_put_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
+    DavResource *res = clientp;
+    DavSession *sn = res->session;
+    if(sn->put_progress) {
+        sn->put_progress(res, (int64_t)ultotal, (int64_t)ulnow, sn->progress_userdata);
+    }
+    return 0;
+}
+
 void dav_session_set_error(DavSession *sn, CURLcode c, int status) {
     if(status > 0) {
         switch(status) {
--- a/libidav/session.h	Mon Dec 18 11:56:11 2017 +0100
+++ b/libidav/session.h	Mon Dec 18 16:24:32 2017 +0100
@@ -82,6 +82,9 @@
 CURLcode dav_session_curl_perform(DavSession *sn, long *status);
 CURLcode dav_session_curl_perform_buf(DavSession *sn, UcxBuffer *request, UcxBuffer *response, long *status);
 
+int dav_session_get_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
+int dav_session_put_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
+
 void dav_session_set_error(DavSession *sn, CURLcode c, int status);
 void dav_session_set_errstr(DavSession *sn, const char *str);
 
--- a/libidav/webdav.h	Mon Dec 18 11:56:11 2017 +0100
+++ b/libidav/webdav.h	Mon Dec 18 16:24:32 2017 +0100
@@ -64,6 +64,7 @@
 typedef size_t(*dav_write_func)(const void*, size_t, size_t, void*);
 
 typedef int(*dav_auth_func)(DavSession *, void *);
+typedef void(*dav_progress_func)(DavResource *, int64_t, int64_t, void *);
 
 enum DavError {
     DAV_OK = 0,
@@ -145,6 +146,10 @@
     
     int(*auth_prompt)(DavSession *sn, void *userdata);
     void *authprompt_userdata;
+    
+    void(*get_progress)(DavResource *res, int64_t total, int64_t now, void *userdata);
+    void(*put_progress)(DavResource *res, int64_t total, int64_t now, void *userdata);
+    void *progress_userdata;
 };
 
 struct DavContext {
@@ -224,6 +229,7 @@
 void dav_session_enable_encryption(DavSession *sn, DavKey *key, int flags);
 
 void dav_session_set_authcallback(DavSession *sn, dav_auth_func func, void *userdata);
+void dav_session_set_progresscallback(DavSession *sn, dav_progress_func get, dav_progress_func put, void *userdata);
 
 void dav_session_destroy(DavSession *sn);
 

mercurial