|
19 | 19 |
|
20 | 20 | module ZipStore = Zarr.Zip.Make(Deferred) |
21 | 21 | module MemoryStore = Zarr.Memory.Make(Deferred) |
| 22 | +module HttpStore = Zarr.Http.Make(Deferred)(Ezcurl_lwt) |
22 | 23 |
|
23 | 24 | module FilesystemStore = struct |
24 | 25 | module IO = struct |
@@ -337,120 +338,3 @@ module AmazonS3Store = struct |
337 | 338 |
|
338 | 339 | include Zarr.Storage.Make(IO) |
339 | 340 | end |
340 | | - |
341 | | -module HttpStore = struct |
342 | | - exception Not_implemented |
343 | | - 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)) |
348 | | - |
349 | | - let fold_result = Result.fold ~error:raise_error ~ok:Fun.id |
350 | | - |
351 | | - module IO = struct |
352 | | - module Deferred = Deferred |
353 | | - |
354 | | - type t = |
355 | | - {tries : int |
356 | | - ;base_url : string |
357 | | - ;client : Ezcurl_lwt.t |
358 | | - ;config : Ezcurl_lwt.Config.t} |
359 | | - |
360 | | - let get t key = |
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)) |
367 | | - |
368 | | - let size t key = Lwt.catch |
369 | | - (fun () -> |
370 | | - let+ data = get t key in |
371 | | - String.length data) |
372 | | - (function |
373 | | - | Request_failed (404, _) -> Deferred.return 0 |
374 | | - | exn -> raise exn) |
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 *) |
389 | | - |
390 | | - let is_member t key = |
391 | | - let+ s = size t key in |
392 | | - if s = 0 then false else true |
393 | | - |
394 | | - let get_partial_values t key ranges = |
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 |
404 | | - in |
405 | | - Deferred.fold_left read_range [] (List.rev ranges) |
406 | | - |
407 | | - let set t key data = |
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 | | - |
419 | | - let set_partial_values t key ?(append=false) rsv = |
420 | | - let* size = size t key in |
421 | | - let* ov = match size with |
422 | | - | 0 -> Deferred.return String.empty |
423 | | - | _ -> get t key |
424 | | - in |
425 | | - let f = if append || ov = String.empty then |
426 | | - fun acc (_, v) -> acc ^ v else |
427 | | - fun acc (rs, v) -> |
428 | | - let s = Bytes.unsafe_of_string acc in |
429 | | - Bytes.blit_string v 0 s rs String.(length v); |
430 | | - Bytes.unsafe_to_string s |
431 | | - in |
432 | | - set t key (List.fold_left f ov rsv) |
433 | | - |
434 | | - (* make reshaping arrays possible *) |
435 | | - let erase t key = |
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)) |
442 | | - |
443 | | - let erase_prefix _ = raise Not_implemented |
444 | | - let list _ = raise Not_implemented |
445 | | - let list_dir _ = raise Not_implemented |
446 | | - let rename _ = raise Not_implemented |
447 | | - end |
448 | | - |
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 |
454 | | - |
455 | | - include Zarr.Storage.Make(IO) |
456 | | -end |
0 commit comments