How do I concurrently run a cohttp-server and my custom REPL?

Hi all,

I am trying to add a cohttp server to my application and am having trouble setting it up. The reproduction below is adapted from the official example. The issue is that the server does not start properly: the browser never finishes loading, and no content is shown. I suspect the answer will be rather simple. I also tried running it with fork_daemon and both, but I have to admit I am brand new to concurrent programming in ocaml, so I don’t really understand what’s going on here. The important thing for a fix is that the terminal is available for user input.

Thanks!

let text = "Hello world"

let handler _socket request _body =
  match Http.Request.resource request with
  | "/" -> (Http.Response.make (), Cohttp_eio.Body.of_string text)
  | "/html" ->
      ( Http.Response.make
          ~headers:(Http.Header.of_list [ ("content-type", "text/html") ])
          (),
        (* Use a plain flow to test chunked encoding *)
        Eio.Flow.string_source text )
  | _ -> (Http.Response.make ~status:`Not_found (), Cohttp_eio.Body.of_string "")

let log_warning ex = Logs.warn (fun f -> f "%a" Eio.Exn.pp ex)

let run ~env ~port =
  Eio.Switch.run @@ fun sw ->
  let socket =
    Eio.Net.listen env#net ~sw ~backlog:128 ~reuse_addr:true
      (`Tcp (Eio.Net.Ipaddr.V4.loopback, port))
  and server = Cohttp_eio.Server.make ~callback:handler () in
  Cohttp_eio.Server.run socket server ~on_error:log_warning

let rec repl () =
  let str = read_line () in
  let _ = print_endline str in
  repl ()

let () =
  Eio_main.run @@ fun env ->
  Eio.Switch.run @@ fun sw ->
  let () =
    Eio.Fiber.fork ~sw @@ fun () ->
    run ~env ~port:8000
  in 
  repl ()

The stdlib’s read_line will cause everything to stop. Using Eio.Buf_read.line should fix it. e.g.

let rec repl stdin =
  let str = Eio.Buf_read.line stdin in
  let _ = print_endline str in
  repl stdin

let () =
  Eio_main.run @@ fun env ->
  Eio.Switch.run @@ fun sw ->
  let () =
    Eio.Fiber.fork ~sw @@ fun () ->
    run ~env ~port:8000
  in 
  repl (Eio.Buf_read.of_flow env#stdin ~max_size:max_int)
1 Like

I suppose this means it’s not possible to use linenoise in my application, as it blocks on input.

You can also use Eio_unix.run_in_systhread if you need to call functions that block.

1 Like