From 03d0e811c80b391438e272941c6f2ddf81a5a17d Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Tue, 26 Aug 2014 15:41:31 +0500 Subject: [PATCH] Add. ProgressFunction option --- doc/lcurl.ldoc | 42 ++++++++++++++++++++ src/lceasy.c | 104 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/doc/lcurl.ldoc b/doc/lcurl.ldoc index 7687d72..21b3332 100644 --- a/doc/lcurl.ldoc +++ b/doc/lcurl.ldoc @@ -112,6 +112,11 @@ do --- Set writer function. -- +-- A callback accepting one or two parameters. +-- The first is the writer context if any, and the second is a string with the data to be written. +-- Function must return `true` or full data length or nothing to continue operation. +-- Otherwise the transfer will be aborted with an error. +-- -- @tparam function writer -- @param[opt] context writer context -- @return[1] self @@ -129,6 +134,11 @@ function easy:setopt_writefunction() end --- Set header function. -- +-- A callback accepting one or two parameters. +-- The first is the writer context if any, and the second is a string with the data to be written. +-- Function must return `true` or full data length or nothing to continue operation. +-- Otherwise the transfer will be aborted with an error. +-- -- @tparam function writer -- @param[opt] context writer context -- @return[1] self @@ -146,6 +156,12 @@ function easy:setopt_headerfunction() end --- Set reader function. -- +-- A callback accepting one or two parameters. +-- The first is the reader context if any, and the second is the maximum amount of data to be read. +-- You can ignore second argument and pass as mach data as you need. lcurl can split data. +-- Function must return data to continue operation. To stop operation it must return empty string. +-- Otherwise the transfer will be aborted with an error. +-- -- @tparam function reader -- @param[opt] context reader context -- @return[1] self @@ -161,6 +177,32 @@ function easy:setopt_readfunction() end -- function easy:setopt_readfunction() end +--- Set progress function. +-- +-- A callback accepting four or five parameters. +-- The first is the reader context if any, the second is the total number +-- of bytes expected to be downloaded in this transfer, +-- the third is the number of bytes downloaded so far, +-- the fourth is the total number of bytes expected to be uploaded +-- in this transfer, and the fifth is the number of bytes uploaded so far. +-- Function must return `true` or or nothing to continue operation. +-- Otherwise the transfer will be aborted with an error. +-- +-- @tparam function progress +-- @param[opt] context progress context +-- @return[1] self +-- +function easy:setopt_progressfunction() end + +--- Set reader function. +-- +-- This call same as easy:set_readfunction(reader.read, reader) +-- +-- @tparam object reader +-- @return[1] self +-- +function easy:setopt_readfunction() end + --- Set HTTP multipart/formdata -- -- @tparam httppost data diff --git a/src/lceasy.c b/src/lceasy.c index 497b8fc..8b269be 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -41,6 +41,7 @@ typedef struct lcurl_easy_tag{ lcurl_callback_t wr; lcurl_callback_t rd; lcurl_callback_t hd; + lcurl_callback_t pr; lcurl_read_buffer_t rbuffer; }lcurl_easy_t; @@ -58,6 +59,7 @@ int lcurl_easy_create(lua_State *L, int error_mode){ p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF; p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF; p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF; + p->pr.cb_ref = p->pr.ud_ref = LUA_NOREF; p->rbuffer.ref = LUA_NOREF; for(i = 0; i < LCURL_LIST_COUNT; ++i){ p->lists[i] = LUA_NOREF; @@ -451,7 +453,6 @@ static int lcurl_write_callback_(lua_State*L, return ret; } - //{ Writer static int lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){ @@ -552,6 +553,74 @@ static int lcurl_easy_set_HEADERFUNCTION(lua_State *L){ //} +//{ Progress + +static int lcurl_xferinfo_callback(void *arg, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + lcurl_easy_t *p = arg; + lua_State *L = p->L; + + int ret = 0; + int top = lua_gettop(L); + int n = lcurl_util_push_cb(L, &p->pr); + + lua_pushnumber( L, dltotal ); + lua_pushnumber( L, dlnow ); + lua_pushnumber( L, ultotal ); + lua_pushnumber( L, ulnow ); + + if(lua_pcall(L, n+3, LUA_MULTRET, 0)){ + assert(lua_gettop(L) >= top); + lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG); + lua_insert(L, top+1); + return 0; + } + + if(lua_gettop(L) > top){ + if(lua_isnil(L, top + 1)) return 1; + if(lua_isboolean(L, top + 1)) + ret = lua_toboolean(L, top + 1)?0:1; + else ret = (size_t)lua_tonumber(L, top + 1); + } + + lua_settop(L, top); + return ret; +} + +static int lcurl_progress_callback(void *arg, double dltotal, double dlnow, + double ultotal, double ulnow) +{ + return lcurl_xferinfo_callback(arg, + (curl_off_t)dltotal, + (curl_off_t)dlnow, + (curl_off_t)ultotal, + (curl_off_t)ulnow + ); +} + + + +static int lcurl_easy_set_PROGRESSFUNCTION(lua_State *L){ + lcurl_easy_t *p = lcurl_geteasy(L); + int n = lcurl_easy_set_callback(L, p, &p->pr, + CURLOPT_PROGRESSFUNCTION, CURLOPT_PROGRESSDATA, + "progress", lcurl_progress_callback + ); + +#if LCURL_CURL_VER_GE(7,32,0) + if(p->pr.cb_ref != LUA_NOREF){ + CURLcode code; + code = curl_easy_setopt(p->curl, CURLOPT_XFERINFOFUNCTION, lcurl_xferinfo_callback); + code = curl_easy_setopt(p->curl, CURLOPT_XFERINFODATA, p); + } +#endif + + return n; +} + +//} + //} static int lcurl_easy_setopt(lua_State *L){ @@ -562,11 +631,12 @@ static int lcurl_easy_setopt(lua_State *L){ #define OPT_ENTRY(l, N, T, S) case CURLOPT_##N: return lcurl_easy_set_##N(L); switch(opt){ #include "lcopteasy.h" - OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) - OPT_ENTRY(httppost, HTTPPOST, TTT, 0) - OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) - OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) - OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) + OPT_ENTRY(httppost, HTTPPOST, TTT, 0) + OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) + OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) + OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) } #undef OPT_ENTRY @@ -579,11 +649,12 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #define OPT_ENTRY(L, N, T, S) { "setopt_"#L, lcurl_easy_set_##N }, #include "lcopteasy.h" - OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) - OPT_ENTRY(httppost, HTTPPOST, TTT, 0) - OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) - OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) - OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) + OPT_ENTRY(httppost, HTTPPOST, TTT, 0) + OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) + OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) + OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N }, @@ -604,11 +675,12 @@ static const lcurl_const_t lcurl_easy_opt[] = { #define OPT_ENTRY(L, N, T, S) { "OPT_"#N, CURLOPT_##N }, #include "lcopteasy.h" - OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) - OPT_ENTRY(httppost, HTTPPOST, TTT, 0) - OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) - OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) - OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(postfields, POSTFIELDS, TTT, 0) + OPT_ENTRY(httppost, HTTPPOST, TTT, 0) + OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0) + OPT_ENTRY(readfunction, READFUNCTION, TTT, 0) + OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0) + OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0) #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S) { "INFO_"#N, CURLINFO_##N },