Implement basic multi iterface.

This commit is contained in:
Alexey Melnichuk 2014-08-27 13:44:50 +05:00
parent bf72021579
commit d18fb3adca
6 changed files with 170 additions and 12 deletions

View File

@ -56,6 +56,43 @@ curl:easy()
) )
:perform() :perform()
:close() :close()
```
```Lua
-- Multi FTP Upload
-- We get error E_LOGIN_DENIED for this operation
e1 = curl:easy()
:setopt_url("ftp://moteus:999999@127.0.0.1/test1.dat")
:setopt_upload(true)
:setopt_readfunction(
function(t) return table.remove(t) end, {"1111", "2222"}
)
e2 = curl:easy()
:setopt_url("ftp://moteus:123456@127.0.0.1/test2.dat")
:setopt_upload(true)
:setopt_readfunction(get_bin_by(("e"):rep(1000), 5))
m = curl:multi()
m:add_handle(e1)
m:add_handle(e2)
while m:perform() > 0 do end
while true do
h, ok, err = m:info_read()
if h == 0 then break end
if h == e1 then
assert(ok == nil)
assert(err:name() == "LOGIN_DENIED")
assert(err:no() == curl.E_LOGIN_DENIED)
end
if h == e2 then
assert(ok == true)
end
end
``` ```

View File

@ -183,7 +183,7 @@ function setopt_writefunction() end
--- Set writer function. --- Set writer function.
-- --
-- This call same as easy:set_writefunction(writer.write, writer) -- This call same as easy:setopt_writefunction(writer.write, writer)
-- --
-- @tparam object writer -- @tparam object writer
-- @return[1] self -- @return[1] self
@ -205,7 +205,7 @@ function setopt_headerfunction() end
--- Set header function. --- Set header function.
-- --
-- This call same as easy:set_headerfunction(writer.header, writer) -- This call same as easy:setopt_headerfunction(writer.header, writer)
-- --
-- @tparam object writer -- @tparam object writer
-- @return[1] self -- @return[1] self
@ -228,7 +228,7 @@ function setopt_readfunction() end
--- Set reader function. --- Set reader function.
-- --
-- This call same as easy:set_readfunction(reader.read, reader) -- This call same as easy:setopt_readfunction(reader.read, reader)
-- --
-- @tparam object reader -- @tparam object reader
-- @return[1] self -- @return[1] self
@ -252,17 +252,19 @@ function setopt_readfunction() end
-- --
function setopt_progressfunction() end function setopt_progressfunction() end
--- Set reader function. --- Set progress function.
-- --
-- This call same as easy:set_readfunction(reader.read, reader) -- This call same as easy:setopt_progressfunction(progress.progress, progress)
-- --
-- @tparam object reader -- @tparam object progress
-- @return[1] self -- @return[1] self
-- --
function setopt_readfunction() end function setopt_progressfunction() end
--- Set HTTP multipart/formdata --- Set HTTP multipart/formdata
-- --
-- Caller does not have to save data.
--
-- @tparam httpform data -- @tparam httpform data
-- @return[1] self -- @return[1] self
function setopt_httpform() end function setopt_httpform() end
@ -281,7 +283,36 @@ end
-- --
do do
--- End multi session --- Add Easy object.
--
-- Caller must ensure that easy object is alive until end of operation.
--
-- @treturn multi self
-- @tparam easy handle
function add_handle() end
--- Remove Easy object.
--
-- @tparam easy handle
-- @treturn multi self
function remove_handle() end
--- reads/writes available data from each easy handle.
--
-- @treturn number handles number of active easy handles
function perfom() end
--- Read multi stack informationals.
--
-- @treturn[1] number 0 there no informationals
-- @treturn[2] easy handle
-- @treturn[2] boolean true
-- @treturn[3] easy handle
-- @treturn[3] nil
-- @treturn[3] error error code
function info_read() end
--- End multi session.
-- --
function close() end function close() end

View File

@ -15,6 +15,9 @@ int lcurl_multi_create(lua_State *L, int error_mode){
lcurl_multi_t *p = lutil_newudatap(L, lcurl_multi_t, LCURL_MULTI); lcurl_multi_t *p = lutil_newudatap(L, lcurl_multi_t, LCURL_MULTI);
p->curl = curl_multi_init(); p->curl = curl_multi_init();
if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, CURLM_INTERNAL_ERROR); if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, CURLM_INTERNAL_ERROR);
p->err_mode = error_mode;
lcurl_util_new_weak_table(L, "v");
p->h_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
return 1; return 1;
} }
@ -32,15 +35,89 @@ static int lcurl_multi_cleanup(lua_State *L){
p->curl = NULL; p->curl = NULL;
} }
if(p->h_ref != LUA_NOREF){
luaL_unref(L, LCURL_LUA_REGISTRY, p->h_ref);
p->h_ref = LUA_NOREF;
}
return 0; return 0;
} }
static int lcurl_multi_add_handle(lua_State *L){
lcurl_multi_t *p = lcurl_getmulti(L);
lcurl_easy_t *e = lcurl_geteasy_at(L, 2);
CURLMcode code = curl_multi_add_handle(p->curl, e->curl);
if(code != CURLM_OK){
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
}
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
lua_pushvalue(L, 2);
lua_rawsetp(L, -2, e->curl);
lua_settop(L, 1);
return 1;
}
static int lcurl_multi_remove_handle(lua_State *L){
lcurl_multi_t *p = lcurl_getmulti(L);
lcurl_easy_t *e = lcurl_geteasy_at(L, 2);
CURLMcode code = curl_multi_remove_handle(p->curl, e->curl);
if(code != CURLM_OK){
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
}
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
lua_pushnil(L);
lua_rawsetp(L, -2, e->curl);
lua_settop(L, 1);
return 1;
}
static int lcurl_multi_perform(lua_State *L){
lcurl_multi_t *p = lcurl_getmulti(L);
int running_handles = 0;
CURLMcode code = curl_multi_perform(p->curl, &running_handles);
if(code != CURLM_OK){
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
}
lua_pushnumber(L, running_handles);
return 1;
}
static int lcurl_multi_info_read(lua_State *L){
lcurl_multi_t *p = lcurl_getmulti(L);
int msgs_in_queue = 0;
CURLMsg *msg = curl_multi_info_read(p->curl, &msgs_in_queue);
lcurl_easy_t *e;
if(!msg){
lua_pushnumber(L, msgs_in_queue);
return 1;
}
if(msg->msg == CURLMSG_DONE){
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
lua_rawgetp(L, -1, msg->easy_handle);
e = lcurl_geteasy_at(L, -1);
if(msg->data.result == CURLE_OK){
lua_pushboolean(L, 1);
return 2;
}
return 1 + lcurl_fail_ex(L, LCURL_ERROR_RETURN, LCURL_ERROR_EASY, msg->data.result);
}
// @todo handle unknown message
lua_pushboolean(L, 0);
return 1;
}
//} //}
static const struct luaL_Reg lcurl_multi_methods[] = { static const struct luaL_Reg lcurl_multi_methods[] = {
{"close", lcurl_multi_cleanup }, {"add_handle", lcurl_multi_add_handle },
{"__gc", lcurl_multi_cleanup }, {"remove_handle", lcurl_multi_remove_handle },
{"perform", lcurl_multi_perform },
{"info_read", lcurl_multi_info_read },
{"close", lcurl_multi_cleanup },
{"__gc", lcurl_multi_cleanup },
{NULL,NULL} {NULL,NULL}
}; };

View File

@ -7,6 +7,7 @@
typedef struct lcurl_multi_tag{ typedef struct lcurl_multi_tag{
CURLM *curl; CURLM *curl;
int err_mode; int err_mode;
int h_ref;
}lcurl_multi_t; }lcurl_multi_t;
int lcurl_multi_create(lua_State *L, int error_mode); int lcurl_multi_create(lua_State *L, int error_mode);

View File

@ -116,3 +116,13 @@ int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c){
return 1; return 1;
} }
int lcurl_util_new_weak_table(lua_State*L, const char *mode){
int top = lua_gettop(L);
lua_newtable(L);
lua_newtable(L);
lua_pushstring(L, mode);
lua_setfield(L, -2, "__mode");
lua_setmetatable(L,-2);
assert((top+1) == lua_gettop(L));
return 1;
}

View File

@ -38,4 +38,6 @@ void lcurl_util_set_const(lua_State *L, const lcurl_const_t *reg);
int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c); int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c);
int lcurl_util_new_weak_table(lua_State*L, const char *mode);
#endif #endif