add a very basic upload progress bar

Tue, 06 Feb 2024 19:01:52 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 06 Feb 2024 19:01:52 +0100
changeset 19
813c97c5b6d3
parent 18
af411868ab9b
child 20
db263186edf3

add a very basic upload progress bar

application/davcontroller.c file | annotate | diff | comparison | revisions
ui/common/types.c file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/davcontroller.c	Tue Feb 06 14:17:22 2024 +0100
+++ b/application/davcontroller.c	Tue Feb 06 19:01:52 2024 +0100
@@ -246,6 +246,14 @@
     DavSession *sn;
     UiFileList files;
     char *base_path;
+    UiThreadpool *queue;
+
+    size_t total_bytes;
+    size_t total_files;
+    size_t total_directories;
+    size_t uploaded_bytes;
+    size_t uploaded_files;
+    size_t uploaded_directories;
 
     UiObject *dialog;
     UiDouble *progress;
@@ -256,30 +264,119 @@
 typedef struct DUFile {
     char *path;
     char *upload_path;
+    size_t bytes;
+    DavBool isdirectory;
+    DavFileUpload *upload;
+    DavError error;
 } DUFile;
 
-static int jobthr_file_upload(void *data) {
+static double upload_progress(DavFileUpload *upload) {
+    return ((double)upload->uploaded_bytes / (double)upload->total_bytes) * 100;
+}
+
+static int qthr_file_upload(void *data) {
+    DUFile *f = data;
+    DavFileUpload *upload = f->upload;
+    DavSession *sn = upload->sn;
+
+    FILE *in = sys_fopen(f->path, "rb");
+    if (!in) {
+        // TODO: error msg
+        return 0;
+    }
+
+    DavResource *res = dav_resource_new(sn, f->upload_path);
+    dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)fseek);
+    if (dav_store(res)) {
+        f->error = sn->error;
+    }
+    dav_resource_free(res);
+
+    fclose(in);
+
+    return 0;
+}
+
+static void uithr_file_uploaded(UiEvent *event, void *data) {
+    DUFile *file = data;
+    DavFileUpload *upload = file->upload;
+
+    upload->uploaded_files++;
+    upload->uploaded_bytes += file->bytes;
+
+    double progress = upload_progress(upload);
+    ui_set(upload->progress, upload_progress(upload));
+
+    free(file->path);
+    free(file->upload_path);
+}
+
+static int qthr_dir_upload(void *data) {
+    DUFile *f = data;
+    DavFileUpload *upload = f->upload;
+    DavSession *sn = upload->sn;
+
+    DavResource *res = dav_resource_new(sn, f->upload_path);
+    res->iscollection = TRUE;
+
+    if (dav_create(res)) {
+        f->error = sn->error;
+    }
+
+    dav_resource_free(res);
+
+    return 0;
+}
+
+static void uithr_dir_uploaded(UiEvent *event, void *data) {
+    DUFile *file = data;
+    DavFileUpload *upload = file->upload;
+
+    upload->uploaded_directories++;
+
+    free(file->path);
+    free(file->upload_path);
+}
+
+static int qthr_upload_finished(void *data) {
+    return 0;
+}
+
+static void uithr_upload_finished(UiEvent *event, void *data) {
+    DavFileUpload *upload = data;
+    ui_threadpool_destroy(upload->queue);
+
+    free(upload->base_path);
+    dav_session_destroy(upload->sn);
+}
+
+static int jobthr_upload_scan(void *data) {
     DavFileUpload *upload = data;
 
-    CxList *stack = cxLinkedListCreateSimple(sizeof(DUFile));
+    CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
     for (int i = 0; i < upload->files.nfiles; i++) {
-        DUFile f;
-        f.path = upload->files.files[i];
-        f.upload_path = util_path_file_name(f.path);
-        cxListInsert(stack, 0, &f);
+        DUFile *f = malloc(sizeof(DUFile));
+        f->path = strdup(upload->files.files[i]);
+        f->upload_path = util_concat_path(upload->base_path, util_path_file_name(f->path));
+        f->isdirectory = FALSE;
+        f->bytes = 0;
+        f->upload = upload;
+        f->error = 0;
+        cxListInsert(stack, 0, f);
     }
 
     while (stack->size > 0) {
         DUFile *f = cxListAt(stack, 0);
 
         char *path = util_concat_path(upload->base_path, f->upload_path);
-        DavResource *res = dav_resource_new(upload->sn, path);
+        cxListRemove(stack, 0);
 
         SYS_STAT s;
         if (!stat(f->path, &s)) {
             if (S_ISDIR(s.st_mode)) {
-                res->iscollection = 1;
-                dav_create(res);
+                f->isdirectory = TRUE;
+                upload->total_directories++;
+                ui_threadpool_job(upload->queue, upload->ui, qthr_dir_upload, f, uithr_dir_uploaded, f);
 
                 SYS_DIR dir = sys_opendir(f->path);
                 if (dir) {
@@ -289,43 +386,40 @@
                         if(!strcmp(entry->name, ".") || !strcmp(entry->name, "..")) {
                             continue;
                         }
-                        
+
                         cxmutstr newpath = util_concat_sys_path(cx_str(f->path), cx_str(entry->name));
                         char *new_upload_path = util_concat_path(f->upload_path, entry->name);
 
-                        DUFile child;
-                        child.path = newpath.ptr;
-                        child.upload_path = new_upload_path;
-                        cxListAdd(stack, &child);
+                        DUFile *child = malloc(sizeof(DUFile));
+                        child->path = newpath.ptr;
+                        child->upload_path = new_upload_path;
+                        child->isdirectory = FALSE;
+                        child->bytes = 0;
+                        child->upload = upload;
+                        child->error = 0;
+                        cxListAdd(stack, child);
                     }
 
                     sys_closedir(dir);
                 }
             } else if (S_ISREG(s.st_mode)) {
-                FILE *in = sys_fopen(f->path, "rb");
-                if (in) {
-                    dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)fseek);
-                    //dav_set_content_length(res, s.st_size);
-                    int err = dav_store(res);
-                    if (err) {
-                        // TODO: error
+                f->isdirectory = FALSE;
+                f->bytes = s.st_size;
+                upload->total_files++;
+                upload->total_bytes += s.st_size;
+                ui_threadpool_job(upload->queue, upload->ui, qthr_file_upload, f, uithr_file_uploaded, f);
+            }
+        }
+    } // TODO: else error msg
 
-                    }
-                    fclose(in);
-                }
-            }
-        } // TODO: else error msg
+    ui_threadpool_job(upload->queue, upload->ui, qthr_upload_finished, upload, uithr_upload_finished, upload);
 
-        dav_resource_free(res);
-        free(path);
-
-        cxListRemove(stack, 0);
-    }
+    ui_filelist_free(upload->files);
 
     return 0;
 }
 
-static void uithr_file_upload_finished(UiEvent *event, void *data) {
+static void uithr_upload_scan_finished(UiEvent *event, void *data) {
     DavFileUpload *upload = data;
 }
 
@@ -341,11 +435,14 @@
 
     // create upload obj, that contains all relevant data for the upload
     DavFileUpload *upload = malloc(sizeof(DavFileUpload));
+    memset(upload, 0, sizeof(DavFileUpload));
+
     upload->ui = ui;
     upload->browser = browser;
     upload->sn = upload_session;
     upload->files = files;
     upload->base_path = strdup(browser->current->path);
+    upload->queue = ui_threadpool_create(1);
 
     // create upload progress window
     UiObject *dialog = ui_simple_window("Upload", upload);
@@ -365,8 +462,8 @@
     ui_set(upload->speed_label, "");
     ui_set(upload->progress, 0);
 
-    //ui_show(dialog);
+    ui_show(dialog);
 
     // start upload and stat threads
-    ui_job(ui, jobthr_file_upload, upload, uithr_file_upload_finished, upload);
+    ui_job(ui, jobthr_upload_scan, upload, uithr_upload_scan_finished, upload);
 }
--- a/ui/common/types.c	Tue Feb 06 14:17:22 2024 +0100
+++ b/ui/common/types.c	Tue Feb 06 19:01:52 2024 +0100
@@ -459,16 +459,16 @@
 
 
 
-UiStr ui_str(char *cstr) {
+UIEXPORT UiStr ui_str(char *cstr) {
     return (UiStr) { cstr, NULL };
 }
 
-UiStr ui_str_free(char *str, void (*freefunc)(void *v)) {
+UIEXPORT UiStr ui_str_free(char *str, void (*freefunc)(void *v)) {
     return (UiStr) { str, freefunc };
 }
 
 
-UiFileList ui_filelist_copy(UiFileList list) {
+UIEXPORT UiFileList ui_filelist_copy(UiFileList list) {
     char **newlist = calloc(sizeof(char*), list.nfiles);
     for (int i = 0; i < list.nfiles; i++) {
         newlist[i] = strdup(list.files[i]);
@@ -476,7 +476,7 @@
     return (UiFileList) { newlist, list.nfiles };
 }
 
-void ui_filelist_free(UiFileList list) {
+UIEXPORT void ui_filelist_free(UiFileList list) {
     for (int i = 0; i < list.nfiles; i++) {
         free(list.files[i]);
     }
--- a/ui/ui/toolkit.h	Tue Feb 06 14:17:22 2024 +0100
+++ b/ui/ui/toolkit.h	Tue Feb 06 19:01:52 2024 +0100
@@ -460,8 +460,8 @@
 UIEXPORT void  ui_list_addobsv(UiList *list, ui_callback f, void *data);
 UIEXPORT void  ui_list_notify(UiList *list);
 
-UiFileList ui_filelist_copy(UiFileList list);
-void ui_filelist_free(UiFileList list);
+UIEXPORT UiFileList ui_filelist_copy(UiFileList list);
+UIEXPORT void ui_filelist_free(UiFileList list);
 
 UIEXPORT void ui_clipboard_set(char *str);
 UIEXPORT char* ui_clipboard_get();
@@ -485,8 +485,8 @@
 UIEXPORT UiIcon* ui_fileicon(size_t size);
 
 
-UiStr ui_str(char *cstr);
-UiStr ui_str_free(char *str, void (*free)(void *v));
+UIEXPORT UiStr ui_str(char *cstr);
+UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v));
 
 #ifdef	__cplusplus
 }

mercurial