Skip to content

Commit 936e562

Browse files
committed
use ezcurl_lwt for lwt
1 parent 204b901 commit 936e562

File tree

4 files changed

+70
-52
lines changed

4 files changed

+70
-52
lines changed

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
(zarr (= :version))
6868
(lwt (>= 2.5.1))
6969
(aws-s3-lwt (>= 4.8.1))
70-
(cohttp-lwt (>= 6.0.0))
70+
(ezcurl-lwt (>= 0.2.4))
7171
(odoc :with-doc)
7272
(ounit2 :with-test)
7373
(tiny_httpd :with-test)

zarr-lwt.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ depends: [
1414
"zarr" {= version}
1515
"lwt" {>= "2.5.1"}
1616
"aws-s3-lwt" {>= "4.8.1"}
17-
"cohttp-lwt" {>= "6.0.0"}
17+
"ezcurl-lwt" {>= "0.2.4"}
1818
"odoc" {with-doc}
1919
"ounit2" {with-test}
2020
"tiny_httpd" {with-test}

zarr-lwt/src/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
(libraries
55
zarr
66
aws-s3-lwt
7-
cohttp-lwt-unix
7+
ezcurl-lwt
88
lwt
99
lwt.unix)
1010
(ocamlopt_flags

zarr-lwt/src/storage.ml

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -341,69 +341,81 @@ end
341341
module HttpStore = struct
342342
exception Not_implemented
343343
exception Request_failed of int * string
344+
open Deferred.Syntax
345+
346+
let raise_error (code, s) =
347+
raise (Request_failed (Curl.int_of_curlCode code, s))
344348

345-
let raise_status_error s =
346-
let c = Cohttp.Code.code_of_status s in
347-
raise (Request_failed (c, Cohttp.Code.reason_phrase_of_code c))
349+
let fold_result = Result.fold ~error:raise_error ~ok:Fun.id
348350

349351
module IO = struct
350352
module Deferred = Deferred
351-
open Deferred.Syntax
352-
open Deferred.Infix
353-
open Cohttp_lwt_unix
354353

355-
type t = {base_url : Uri.t}
354+
type t =
355+
{tries : int
356+
;base_url : string
357+
;client : Ezcurl_lwt.t
358+
;config : Ezcurl_lwt.Config.t}
356359

357360
let get t key =
358-
let url = Uri.with_path t.base_url key in
359-
let* resp, body = Client.get url in
360-
match Response.status resp with
361-
| #Cohttp.Code.success_status -> Cohttp_lwt.Body.to_string body
362-
| #Cohttp.Code.client_error_status as e when e = `Not_found ->
363-
raise (Zarr.Storage.Key_not_found key)
364-
| e -> raise_status_error e
361+
let tries = t.tries and client = t.client and config = t.config in
362+
let url = t.base_url ^ key in
363+
let+ res = Ezcurl_lwt.get ~tries ~client ~config ~url () in
364+
match fold_result res with
365+
| {code; body; _} when code = 200 -> body
366+
| {code; body; _} -> raise (Request_failed (code, body))
365367

366368
let size t key = Lwt.catch
367-
(fun () -> get t key >>| String.length)
369+
(fun () ->
370+
let+ data = get t key in
371+
String.length data)
368372
(function
369-
| Zarr.Storage.Key_not_found _ -> Deferred.return 0
373+
| Request_failed (404, _) -> Deferred.return 0
370374
| exn -> raise exn)
371-
(*let size t key =
372-
let url = Uri.with_path t.base_url key in
373-
let* resp = Client.head url in
374-
match Response.status resp with
375-
| #Cohttp.Code.success_status ->
376-
begin match Cohttp.Header.get (Response.headers resp) "Content-Length" with
377-
| Some l -> Deferred.return (int_of_string l)
378-
| None ->
379-
let+ data = get t key in
380-
String.length data
381-
end
382-
| #Cohttp.Code.client_error_status as e when e = `Not_found -> Deferred.return 0
383-
| e -> raise_status_error e *)
375+
(*let size t key =
376+
let tries = t.tries and client = t.client and config = t.config in
377+
let url = t.base_url ^ key in
378+
let type' = if String.ends_with ~suffix:".json" key then "json" else "octet-stream" in
379+
let headers = [("Content-Type", "application/" ^ type')] in
380+
let res = Ezcurl.http ~headers ~tries ~client ~config ~url ~meth:HEAD () in
381+
match fold_result res with
382+
| {code; _} when code = 404 -> 0
383+
| {headers; _} ->
384+
match List.assoc_opt "content-length" headers with
385+
| (Some "0" | None) ->
386+
begin try print_endline "empty content-length header"; String.length (get t key) with
387+
| Request_failed (404, _) -> 0 end
388+
| Some l -> int_of_string l *)
384389

385390
let is_member t key =
386391
let+ s = size t key in
387392
if s = 0 then false else true
388393

389394
let get_partial_values t key ranges =
390-
let read_range ~data ~size (ofs, len) = match len with
391-
| None -> String.sub data ofs (size - ofs)
392-
| Some l -> String.sub data ofs l
395+
let tries = t.tries and client = t.client and config = t.config and url = t.base_url ^ key in
396+
let fetch range = Ezcurl_lwt.get ~range ~tries ~client ~config ~url () in
397+
let end_index ofs l = Printf.sprintf "%d-%d" ofs (ofs + l - 1) in
398+
let read_range acc (ofs, len) =
399+
let none = Printf.sprintf "%d-" ofs in
400+
let range = Option.fold ~none ~some:(end_index ofs) len in
401+
let+ res = fetch range in
402+
let response = fold_result res in
403+
response.body :: acc
393404
in
394-
let+ data = get t key in
395-
let size = String.length data in
396-
List.map (read_range ~data ~size) ranges
405+
Deferred.fold_left read_range [] (List.rev ranges)
397406

398407
let set t key data =
399-
let url = Uri.with_path t.base_url key in
400-
let body = Cohttp_lwt.Body.of_string data in
401-
let headers = Cohttp.Header.of_list [("Content-Length", string_of_int (String.length data))] in
402-
let* resp, _ = Client.post ~body ~headers url in
403-
match Response.status resp with
404-
| #Cohttp.Code.success_status -> Deferred.return_unit
405-
| e -> raise_status_error e
406-
408+
let tries = t.tries and client = t.client and config = t.config
409+
and url = t.base_url ^ key and content = `String data in
410+
let type' = if String.ends_with ~suffix:".json" key then "json" else "octet-stream" in
411+
let headers =
412+
[("Content-Length", string_of_int (String.length data))
413+
;("Content-Type", "application/" ^ type')] in
414+
let+ res = Ezcurl_lwt.post ~params:[] ~headers ~tries ~client ~config ~url ~content () in
415+
match fold_result res with
416+
| {code; _} when code = 200 || code = 201 -> ()
417+
| {code; body; _} -> raise (Request_failed (code, body))
418+
407419
let set_partial_values t key ?(append=false) rsv =
408420
let* size = size t key in
409421
let* ov = match size with
@@ -419,20 +431,26 @@ module HttpStore = struct
419431
in
420432
set t key (List.fold_left f ov rsv)
421433

434+
(* make reshaping arrays possible *)
422435
let erase t key =
423-
let url = Uri.with_path t.base_url key in
424-
let* resp, _ = Client.delete url in
425-
match Response.status resp with
426-
| #Cohttp.Code.success_status -> Deferred.return_unit
427-
| e -> raise_status_error e
436+
let tries = t.tries and client = t.client and config = t.config in
437+
let url = t.base_url ^ key in
438+
let+ res = Ezcurl_lwt.http ~tries ~client ~config ~url ~meth:DELETE () in
439+
match fold_result res with
440+
| {code; _} when code = 200 -> ()
441+
| {code; body; _} -> raise (Request_failed (code, body))
428442

429443
let erase_prefix _ = raise Not_implemented
430444
let list _ = raise Not_implemented
431445
let list_dir _ = raise Not_implemented
432446
let rename _ = raise Not_implemented
433447
end
434448

435-
let with_open url f = f IO.{base_url = Uri.of_string url}
449+
let with_open ?(redirects=5) ?(tries=3) ?(timeout=5) url f =
450+
let config = Ezcurl_lwt.Config.(default |> max_redirects redirects |> follow_location true) in
451+
let perform client = f IO.{tries; client; config; base_url = url ^ "/"} in
452+
let set_opts client = Curl.set_connecttimeout client timeout in
453+
Ezcurl_lwt.with_client ~set_opts perform
436454

437455
include Zarr.Storage.Make(IO)
438456
end

0 commit comments

Comments
 (0)