@@ -341,69 +341,81 @@ end
341341module 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 )
438456end
0 commit comments