akabe / docker-iocaml-datascience

Dockerfile of Jupyter (IPython notebook) and IOCaml (OCaml kernel) with libraries for data science and machine learning
MIT License
28 stars 3 forks source link

cohttp.lwt cannot work on notebooks #34

Closed akabe closed 7 years ago

akabe commented 7 years ago

This works on the standard OCaml REPL, but blocks forever on IOCaml.

let main =
  Client.get (Uri.of_string "https://example.com/") >>= fun (resp, body) ->
  Cohttp_lwt_body.to_string body >|= fun body ->
  assert(Response.status resp = `OK) ;
  printf "%s@." body
;;
Lwt_main.run main ;;
akabe commented 7 years ago

This works sometimes...

#thread ;;
#require "cohttp.lwt" ;;
open Lwt.Infix ;;

let rec aux () = Lwt_main.yield () >>= aux in
Thread.create (fun () -> Lwt_main.run (aux ())) () ;; (* Start the main loop *)

let main =
  Cohttp_lwt_unix.Client.get (Uri.of_string "https://example.com/") >>= fun (resp, body) ->
  Cohttp_lwt_body.to_string body >|= fun body ->
  assert(Cohttp.Response.status resp = `OK) ;
  Format.printf "%s@." body ;;
akabe commented 7 years ago

getaddrinfo and getservbyname can work, but getaddrinfo after getservbyname cannot return...

#require "core" ;;
#require "cohttp.lwt" ;;
#require "cohttp.top" ;;
#require "yojson" ;;

open Core ;;
open Lwt.Infix ;;
open Lwt_unix ;;

let rec forever () = Lwt_main.yield () >>= fun () -> Lwt_unix.sleep 0.1 >>= forever in
Thread.create (fun () -> Lwt_main.run (forever ())) () ;; (* Start the LWT scheduler. *)

getservbyname "http" "tcp" >>= fun serv ->
printf "finish getservbyname: port=%d\n%!" serv.s_port ;
getaddrinfo "example.com" "80" [AI_SOCKTYPE SOCK_STREAM] >|= fun addrinfo ->
print_endline "finish getaddrinfo" ; addrinfo

However the standard blocking API works.

let open Caml.Unix in
let serv = getservbyname "http" "tcp" in
getaddrinfo "example.com" (string_of_int serv.Caml.Unix.s_port) [AI_SOCKTYPE SOCK_STREAM]

A partially-blocking cohttp works well:

let ctx =
  let blocking_resolver service uri =
    let open Caml.Unix in
    let host = match Uri.host uri with Some h -> h | None -> "localhost" in
    let port = match Uri.port uri with Some p -> p | None -> service.Resolver.port in
    match getaddrinfo host (string_of_int port) [AI_SOCKTYPE SOCK_STREAM] with
    | [] -> Lwt.return (`Unknown ("name resolution failed"))
    | {ai_addr=ADDR_INET (addr,port);_}::_ -> Lwt.return (`TCP (Ipaddr_unix.of_inet_addr addr, port))
    | {ai_addr=ADDR_UNIX file;_}::_ -> Lwt.return (`Unix_domain_socket file) in
  let resolver = Resolver_lwt.init ~service:Resolver_lwt_unix.system_service ~rewrites:["", blocking_resolver] () in
  Cohttp_lwt_unix_net.({ default_ctx with resolver })
;;

let main =
  Client.get ~ctx:ctx (Uri.of_string "http://example.com/") >>= fun (resp, body) ->
  Cohttp_lwt_body.to_string body >|= fun body ->
  printf "%s\n%!" body
akabe commented 7 years ago

Solved: https://github.com/akabe/docker-iocaml-datascience/blob/master/examples/cohttp_lwt_example.ipynb