#include "upload.h"
#include "davcontroller.h"
#include "window.h"
#include <cx/printf.h>
#include "config.h"
#include "system.h"
#include "common/context.h"
#include <libidav/config.h>
#include <libidav/utils.h>
static double upload_progress(DavFileUpload *upload) {
return ((
double)upload->progress.transferred_bytes / (
double)upload->progress.total_bytes) *
100;
}
static void update_upload_labels(DavFileUpload *upload) {
char *sz_total = util_size_str(
FALSE, upload->progress.total_bytes);
char *sz_uploaded = util_size_str2(
FALSE, upload->progress.transferred_bytes, upload->progress.total_bytes,
2);
char *sz_uploaded_end = strchr(sz_uploaded,
' ');
if (sz_uploaded_end) {
*sz_uploaded_end =
0;
}
double progress = upload_progress(upload);
ui_set(upload->progressbar, progress);
upload->trans.progress = progress;
time_t t = time(
NULL);
cxmutstr label1;
if (upload->progress.total_files + upload->progress.total_directories >
1) {
label1 = cx_asprintf(
"%s/%s %zu/%zu files",
sz_uploaded,
sz_total,
upload->progress.transferred_files+upload->progress.transferred_directories,
upload->progress.total_files+upload->progress.total_directories);
}
else {
label1 = cx_asprintf(
"%s/%s",
sz_uploaded,
sz_total);
}
ui_set(upload->label_top_left, label1.ptr);
free(sz_total);
free(label1.ptr);
if (upload->progress.current_file_size >
0) {
cxmutstr file_label = cx_asprintf(
"%s (%.0f%%)", upload->current_file_name, ((
float)upload->progress.current_file_transferred/(
float)upload->progress.current_file_size)*
100);
ui_set(upload->label_top_right, file_label.ptr);
free(file_label.ptr);
}
time_t start = upload->progress.speedtest_start;
if(t >= upload->progress.speedtest_start +
4) {
uint64_t bytesPerSeconds = dav_transfer_speed(&upload->progress, t);
if(start >
0) {
char *szps = util_size_str(
FALSE, bytesPerSeconds);
cxmutstr label3 = cx_asprintf(
"%s/s", szps);
free(szps);
ui_set(upload->label_bottom_left, label3.ptr);
free(label3.ptr);
}
}
}
static int uithr_update_upload_labels(
void *data) {
update_upload_labels(data);
return 0;
}
static void upload_dav_progress(DavResource *res,
int64_t total,
int64_t now,
void *data) {
DavFileUpload *upload = data;
if (upload->upload_file) {
if (now > upload->progress.current_file_size) {
int64_t extra = now - upload->progress.current_file_size;
upload->progress.current_file_size += extra;
upload->progress.total_bytes += extra;
}
int64_t new_progress = now - upload->progress.current_file_transferred;
upload->progress.transferred_bytes += new_progress;
upload->progress.current_file_transferred = now;
ui_call_mainthread(uithr_update_upload_labels, upload);
}
}
typedef struct FileNameUpdate {
DavFileUpload *upload;
char *name;
char *path;
DavBool iscollection;
} FileNameUpdate;
static int uithr_update_file_label(FileNameUpdate *update) {
if(update->upload->cancel) {
return 0;
}
if (update->upload->current_file_name) {
free(update->upload->current_file_name);
}
update->upload->current_file_name = update->name;
ui_set(update->upload->label_top_right, update->name);
DavFileUpload *upload = update->upload;
DavBrowser *browser = upload->browser;
if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
char *parent = util_parent_path(update->path);
cxstring parent_s = cx_str(parent);
cxstring colpath_s = cx_str(upload->collection->path);
if (parent_s.length >
0 && parent_s.ptr[parent_s.length -
1] ==
'/') {
parent_s.length--;
}
if (colpath_s.length >
0 && colpath_s.ptr[colpath_s.length -
1] ==
'/') {
colpath_s.length--;
}
if (!cx_strcmp(parent_s, colpath_s)) {
DavResource *ui_res = dav_resource_new(upload->collection->session, update->path);
ui_res->iscollection = update->iscollection;
ui_res->lastmodified = time(
NULL);
ui_res->creationdate = time(
NULL);
upload->current_resource = ui_res;
ui_list_append(browser->resources, ui_res);
browser->resources->update(browser->resources,
0);
}
else {
upload->current_resource =
NULL;
}
free(parent);
}
free(update->path);
free(update);
return 0;
}
static size_t dufile_read(
void *buf,
size_t size,
size_t count,
void *stream) {
DUFile *f = (DUFile*)stream;
if(f->upload->cancel) {
return 0;
}
return fread(buf, size, count, f->fd);
}
static int dufile_seek(
const void *stream,
long off,
int whence) {
DUFile *f = (DUFile*)stream;
return fseek(f->fd, off, whence);
}
static int qthr_file_upload(
void *data) {
DUFile *f = data;
DavFileUpload *upload = f->upload;
DavSession *sn = upload->sn;
if(upload->cancel) {
return 0;
}
FILE *in = sys_fopen(f->path,
"rb");
if (!in) {
return 0;
}
f->fd = in;
upload->upload_file =
TRUE;
upload->progress.current_file_size = f->bytes;
upload->progress.current_file_transferred =
0;
DavResource *res = dav_resource_new(sn, f->upload_path);
FileNameUpdate *ui_update = malloc(
sizeof(FileNameUpdate));
ui_update->upload = upload;
ui_update->name = strdup(res->name);
ui_update->path = strdup(res->path);
ui_update->iscollection =
FALSE;
ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
dav_set_content(res, f, (dav_read_func)dufile_read, (dav_seek_func)dufile_seek);
if (dav_store(res)) {
f->error = sn->error;
}
dav_resource_free(res);
fclose(in);
upload->upload_file =
FALSE;
return 0;
}
static void uithr_file_uploaded(UiEvent *event,
void *data) {
DUFile *file = data;
DavFileUpload *upload = file->upload;
upload->progress.transferred_files++;
double progress = upload_progress(upload);
ui_set(upload->progressbar, upload_progress(upload));
update_upload_labels(upload);
DavBrowser *browser = upload->browser;
if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
if (upload->current_resource) {
upload->current_resource->contentlength = upload->progress.current_file_transferred;
browser->resources->update(browser->resources,
0);
}
}
upload->current_resource =
NULL;
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;
FileNameUpdate *ui_update = malloc(
sizeof(FileNameUpdate));
ui_update->upload = upload;
ui_update->name = strdup(res->name);
ui_update->path = strdup(res->path);
ui_update->iscollection =
TRUE;
ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
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->progress.transferred_directories++;
update_upload_labels(upload);
upload->current_resource =
NULL;
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;
if(upload->cancel) {
ui_set(upload->label_bottom_left,
"Canceled");
}
if(upload->dialog->ref >
1) {
ui_close(upload->dialog);
}
ui_object_unref(upload->dialog);
}
static int jobthr_upload_scan(
void *data) {
DavFileUpload *upload = data;
CxList *stack = cxLinkedListCreateSimple(
CX_STORE_POINTERS);
for (
int i =
0; i < upload->files.nfiles; i++) {
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 (cxListSize(stack) >
0 && !upload->cancel) {
DUFile *f = cxListAt(stack,
0);
char *path = util_concat_path(upload->base_path, f->upload_path);
cxListRemove(stack,
0);
SYS_STAT s;
if (!sys_stat(f->path, &s)) {
if (
S_ISDIR(s.st_mode)) {
f->isdirectory =
TRUE;
upload->progress.total_directories++;
ui_threadpool_job(upload->queue, upload->dialog, qthr_dir_upload, f, uithr_dir_uploaded, f);
SYS_DIR dir = sys_opendir(f->path);
if (dir) {
SysDirEnt *entry;
int nument =
0;
while((entry = sys_readdir(dir)) !=
NULL) {
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 = 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)) {
f->isdirectory =
FALSE;
f->bytes = s.st_size;
upload->progress.total_files++;
upload->progress.total_bytes += s.st_size;
ui_threadpool_job(upload->queue, upload->dialog, qthr_file_upload, f, uithr_file_uploaded, f);
}
}
else {
}
}
ui_threadpool_job(upload->queue, upload->dialog, qthr_upload_finished, upload, uithr_upload_finished, upload);
ui_filelist_free(upload->files);
return 0;
}
static void uithr_upload_scan_finished(UiEvent *event,
void *data) {
DavFileUpload *upload = data;
update_upload_labels(upload);
}
static void upload_window_closed(UiEvent *event,
void *data) {
DavFileUpload *upload = event->window;
ui_threadpool_destroy(upload->queue);
dav_session_destroy(upload->sn);
}
void action_upload_cancel(UiEvent *event,
void *data) {
DavFileUpload *upload = event->window;
if(!upload->cancel) {
ui_set(upload->label_bottom_left,
"Cancel...");
upload->cancel =
TRUE;
}
}
static void dav_file_upload_cleanup(DavFileUpload *upload) {
application_remove_transfer(&upload->trans);
ui_object_unref(upload->browser->window);
}
DavFileUpload* dav_upload_create(DavBrowser *browser, UiObject *obj, UiFileList files) {
UiContext *ctx = obj->ctx;
CxMempool *mp = ui_cx_mempool(ctx);
DavFileUpload *upload = ui_malloc(ctx,
sizeof(DavFileUpload));
memset(upload,
0,
sizeof(DavFileUpload));
upload->dialog = obj;
obj->window = upload;
ui_object_ref(obj);
ui_object_ref(browser->window);
size_t label_len = strlen(util_resource_name(files.files[
0])) +
16;
upload->trans.label = cxCalloc(mp->allocator, label_len,
1);
upload->trans.label_len = snprintf(upload->trans.label, label_len,
"> %s%s", util_resource_name(files.files[
0]), files.nfiles >
1 ?
" ..." :
"");
upload->trans.window = obj;
upload->progressbar = ui_double_new(ctx,
"progressbar");
upload->label_top_left = ui_string_new(ctx,
"label_top_left");
upload->label_top_right = ui_string_new(ctx,
"label_top_right");
upload->label_bottom_left = ui_string_new(ctx,
"label_bottom_left");
upload->label_bottom_right = ui_string_new(ctx,
"label_bottom_right");
DavSession *upload_session = dav_session_clone(browser->sn);
dav_session_set_progresscallback(upload_session,
NULL, upload_dav_progress, upload);
upload->browser = browser;
upload->sn = upload_session;
upload->files = files;
upload->base_path = ui_strdup(ctx, browser->current->path);
upload->queue = ui_threadpool_create(
1);
upload->collection = browser->current;
upload->collection_ctn = browser->res_counter;
cxMempoolRegister(mp, upload_session, (cx_destructor_func)dav_session_destroy);
cxMempoolRegister(mp, upload->queue, (cx_destructor_func)ui_threadpool_destroy);
cxMempoolSetDestructor(upload, (cx_destructor_func)dav_file_upload_cleanup);
ui_set(upload->label_top_left,
"");
ui_set(upload->label_top_right,
"");
ui_set(upload->label_bottom_left,
"");
ui_set(upload->label_bottom_right,
"");
ui_set(upload->progressbar,
0);
return upload;
}
void dav_upload_start(DavFileUpload *upload) {
ui_show(upload->dialog);
ui_job(upload->dialog, jobthr_upload_scan, upload, uithr_upload_scan_finished, upload);
}