mirror of
https://github.com/c-cube/ezcurl.git
synced 2025-12-07 03:35:39 -05:00
Tweak streaming API
This commit is contained in:
parent
8d783dc626
commit
322b4da0ed
3 changed files with 52 additions and 37 deletions
|
|
@ -265,13 +265,6 @@ module type S = sig
|
||||||
@param headers headers of the query
|
@param headers headers of the query
|
||||||
*)
|
*)
|
||||||
|
|
||||||
(** Push-stream of bytes
|
|
||||||
@since NEXT_RELEASE *)
|
|
||||||
class type input_stream = object
|
|
||||||
method on_close : unit -> unit
|
|
||||||
method on_input : bytes -> int -> int -> unit
|
|
||||||
end
|
|
||||||
|
|
||||||
val http_stream :
|
val http_stream :
|
||||||
?tries:int ->
|
?tries:int ->
|
||||||
?client:t ->
|
?client:t ->
|
||||||
|
|
@ -281,7 +274,10 @@ module type S = sig
|
||||||
?headers:header list ->
|
?headers:header list ->
|
||||||
url:string ->
|
url:string ->
|
||||||
meth:meth ->
|
meth:meth ->
|
||||||
write_into:#input_stream ->
|
?on_respond:((unit response, curl_error) result -> unit) ->
|
||||||
|
on_write:(bytes -> length:int -> unit) ->
|
||||||
|
?on_close:(unit -> unit) ->
|
||||||
|
?on_progress:(downloaded:int64 -> expected:int64 option -> [`Continue | `Abort]) ->
|
||||||
unit ->
|
unit ->
|
||||||
(unit response, curl_error) result io
|
(unit response, curl_error) result io
|
||||||
(** HTTP call via cURL, with a streaming response body.
|
(** HTTP call via cURL, with a streaming response body.
|
||||||
|
|
@ -355,11 +351,6 @@ module Make (IO : IO) : S with type 'a io = 'a IO.t = struct
|
||||||
| `String s -> Some (String.length s)
|
| `String s -> Some (String.length s)
|
||||||
| `Write _ -> None
|
| `Write _ -> None
|
||||||
|
|
||||||
class type input_stream = object
|
|
||||||
method on_close : unit -> unit
|
|
||||||
method on_input : bytes -> int -> int -> unit
|
|
||||||
end
|
|
||||||
|
|
||||||
type http_state_ = {
|
type http_state_ = {
|
||||||
client: client;
|
client: client;
|
||||||
do_cleanup: bool;
|
do_cleanup: bool;
|
||||||
|
|
@ -489,27 +480,56 @@ module Make (IO : IO) : S with type 'a io = 'a IO.t = struct
|
||||||
loop tries
|
loop tries
|
||||||
|
|
||||||
let http_stream ?(tries = 1) ?client ?config ?range ?content ?headers ~url
|
let http_stream ?(tries = 1) ?client ?config ?range ?content ?headers ~url
|
||||||
~meth ~(write_into : #input_stream) () : (unit response, _) result io =
|
~meth ?(on_respond=ignore) ~on_write ?(on_close=ignore) ?on_progress ()
|
||||||
|
: (unit response, _) result io =
|
||||||
let tries = max tries 1 in
|
let tries = max tries 1 in
|
||||||
let st =
|
let st =
|
||||||
http_setup_ ?client ?config ?range ?content ?headers ~url ~meth ()
|
http_setup_ ?client ?config ?range ?content ?headers ~url ~meth ()
|
||||||
in
|
in
|
||||||
|
|
||||||
|
let responded = ref false in
|
||||||
|
let respond () =
|
||||||
|
if not !responded then (
|
||||||
|
responded := true;
|
||||||
|
on_respond (mk_res st ())
|
||||||
|
)
|
||||||
|
in
|
||||||
|
|
||||||
Curl.set_writefunction st.client.curl (fun s ->
|
Curl.set_writefunction st.client.curl (fun s ->
|
||||||
let n = String.length s in
|
respond ();
|
||||||
write_into#on_input (Bytes.unsafe_of_string s) 0 n;
|
let length = String.length s in
|
||||||
n);
|
on_write (Bytes.unsafe_of_string s) ~length;
|
||||||
|
length);
|
||||||
|
|
||||||
|
opt_iter on_progress ~f:(fun on_progress ->
|
||||||
|
Curl.set_xferinfofunction st.client.curl
|
||||||
|
(fun dltotal dlnow _ultotal _ulnow ->
|
||||||
|
match
|
||||||
|
on_progress
|
||||||
|
~downloaded:dlnow
|
||||||
|
~expected:(if dltotal = 0L then None else Some dltotal)
|
||||||
|
with
|
||||||
|
| `Continue -> false
|
||||||
|
| `Abort -> true
|
||||||
|
);
|
||||||
|
Curl.set_noprogress st.client.curl false;
|
||||||
|
);
|
||||||
|
|
||||||
let rec loop i =
|
let rec loop i =
|
||||||
IO.perform st.client.curl >>= function
|
IO.perform st.client.curl >>= function
|
||||||
| Curl.CURLE_OK ->
|
| Curl.CURLE_OK ->
|
||||||
let r = mk_res st () in
|
let r = mk_res st () in
|
||||||
write_into#on_close ();
|
if not !responded then (
|
||||||
|
responded := true;
|
||||||
|
on_respond r;
|
||||||
|
);
|
||||||
|
on_close ();
|
||||||
if st.do_cleanup then Curl.cleanup st.client.curl;
|
if st.do_cleanup then Curl.cleanup st.client.curl;
|
||||||
return r
|
return r
|
||||||
| Curl.CURLE_AGAIN when i > 1 -> loop (i - 1) (* try again *)
|
| Curl.CURLE_AGAIN when i > 1 -> loop (i - 1) (* try again *)
|
||||||
| c ->
|
| c ->
|
||||||
write_into#on_close ();
|
respond ();
|
||||||
|
on_close ();
|
||||||
if st.do_cleanup then Curl.cleanup st.client.curl;
|
if st.do_cleanup then Curl.cleanup st.client.curl;
|
||||||
return (Error (c, Curl.strerror c))
|
return (Error (c, Curl.strerror c))
|
||||||
in
|
in
|
||||||
|
|
|
||||||
|
|
@ -164,13 +164,6 @@ module type S = sig
|
||||||
@param headers headers of the query
|
@param headers headers of the query
|
||||||
*)
|
*)
|
||||||
|
|
||||||
(** Push-based stream of bytes
|
|
||||||
@since NEXT_RELEASE *)
|
|
||||||
class type input_stream = object
|
|
||||||
method on_close : unit -> unit
|
|
||||||
method on_input : bytes -> int -> int -> unit
|
|
||||||
end
|
|
||||||
|
|
||||||
val http_stream :
|
val http_stream :
|
||||||
?tries:int ->
|
?tries:int ->
|
||||||
?client:t ->
|
?client:t ->
|
||||||
|
|
@ -180,13 +173,19 @@ module type S = sig
|
||||||
?headers:header list ->
|
?headers:header list ->
|
||||||
url:string ->
|
url:string ->
|
||||||
meth:meth ->
|
meth:meth ->
|
||||||
write_into:#input_stream ->
|
?on_respond:((unit response, curl_error) result -> unit) ->
|
||||||
unit ->
|
on_write:(bytes -> length:int -> unit) ->
|
||||||
(unit response, curl_error) result io
|
?on_close:(unit -> unit) ->
|
||||||
|
?on_progress:(downloaded:int64 ->
|
||||||
|
expected:int64 option -> [ `Abort | `Continue ]) ->
|
||||||
|
unit -> (unit response, curl_error) result io
|
||||||
(** HTTP call via cURL, with a streaming response body.
|
(** HTTP call via cURL, with a streaming response body.
|
||||||
The body is given to [write_into] by chunks,
|
[on_respond] is called as soon as the response code and headers are
|
||||||
then [write_into#on_close ()] is called
|
available. If the call failed, the response code will be zero.
|
||||||
and the response is returned.
|
Then the body is given to [on_write] by chunks, and, finally [on_close ()]
|
||||||
|
is called and the response is returned.
|
||||||
|
[on_progress] is regularly called to give the opportunity to track the
|
||||||
|
progress of a large or slow transfer and to abort it.
|
||||||
@since NEXT_RELEASE *)
|
@since NEXT_RELEASE *)
|
||||||
|
|
||||||
val get :
|
val get :
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,7 @@ let () =
|
||||||
let buf = Buffer.create 32 in
|
let buf = Buffer.create 32 in
|
||||||
match
|
match
|
||||||
Ezcurl.http_stream ~meth:GET ~url
|
Ezcurl.http_stream ~meth:GET ~url
|
||||||
~write_into:
|
~on_write:(fun bs ~length -> Buffer.add_subbytes buf bs 0 length)
|
||||||
(object
|
|
||||||
method on_input bs i len = Buffer.add_subbytes buf bs i len
|
|
||||||
method on_close () = ()
|
|
||||||
end)
|
|
||||||
()
|
()
|
||||||
with
|
with
|
||||||
| Error (code, msg) ->
|
| Error (code, msg) ->
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue