#!/usr/bin/unfold ~/u/webs
-require re;;
-require angstrom;;
-require (topcore%>files);;
-require ppx_typst;;
-require topcore_cprg;;
-require cow;;
-mod_use [%unfold "~/u/colon-options-2"];;
-mod_use "%/../l9-plumbing.ml";;
-mod_use (Sys.getenv "HOME" ^ "/u/webs/run__http.ml");;
-use "%/../run_.ml";;
module Services =
struct
let dir fs = Path.(fs / Sys.getenv "HOME" / "s")
end
let addr = \`Tcp (Net.Ipaddr.V4.any, 3999)
let port_80 = \`Tcp (Net.Ipaddr.V4.any, 80)
let __id = ref 0
module Port =
struct
(* sudo socat TCP-LISTEN:80,fork TCP:0.0.0.0:4999 *)
let map ~process_mgr (`Tcp (_, redirect_to)) (`Tcp (_, at)) =
Process.run process_mgr ["socat"; "TCP-LISTEN:"^string_of_int at^",fork"; "TCP:0.0.0.0:"^string_of_int redirect_to]
end
let main ?(addr = addr) env =
Switch.run @@ fun sw ->
(* Fiber.fork_daemon ~sw (fun () -> Port.map ~process_mgr:(Stdenv.process_mgr env) addr port_80; `Stop_daemon); *)
Fiber.fork_daemon ~sw (fun () ->
let myid = !__id in
while Time.sleep (Stdenv.clock env) 1.0; myid = !__id do () done;
failwith "ok" );
let fs = Stdenv.fs env and
process_mgr = Stdenv.process_mgr env and
net = Stdenv.net env in
let route = Runcode.run @@
let \`pats plugins, \`aboutpats aboutpats = L9_plumbing
.plugins ~fs ~process_mgr ~servicedir:(Services.dir (Stdenv.fs env)) ~about_make_pat () in
p (plugins @ aboutpats) in
traceln "layer9: running server at port %d" (match addr with \`Tcp (_, n) -> n);
Net.run_server (Net.listen net ~sw
~reuse_addr:true ~backlog:5 (addr :> Net.Sockaddr.stream))
~on_error:(traceln "layer9: error: %a" Fmt.exn) @@ fun flow addr ->
(* NOTE(kinten) during the development of ~/u/unity-peripherals/reference, the html of FSharp.Formatting sometimes sends a resource request whose length may have been quite long for whatever reasons. We once set max_size to 100 instead of 1_000_000. The result is that some connection failed prematurely, they got truncated and silently failed (needs investigation). *)
let from_client = Buf_read.of_flow flow ~max_size:1_000_000 in
let method_, (path, params), httpver =
Buf_read.line from_client
|> Angstrom.parse_string ~consume:All Run__http.x
|> (function Ok x -> x | Error k -> failwith k) in
route ((String.split_on_char '/' path |> List.tl), params, (object
method process_mgr = env#process_mgr
method clock = env#clock
method fs = env#fs
method writer = flow
method sw = sw
end))
and stop () =
__id := !__id + 1
open Colon_options_2
let main' ~env =
Cmd.make ( Cmd.info "layer9"
~doc:{%typ| web server |} ) @@
let open Term.Syntax in
let+ () = Arg.(value & flag &
info ["h"; "help"] ~doc:{%typ| Show help menu. |})
>>| function false -> () | true -> Io.Flow.copy_string "Usage: ~/layer9 <options>\noptions are\n :port <num>\t\t\tExpose server process to port <num> of this computer\n" (Stdenv.stderr env); exit 0
and+ addr = Arg.(value & opt string "" &
info ["p"; "port"] ~docv:"PORT" ~doc:{%typ| #PORT is port number of the server process which will be exposed. |})
>>| function p when p <> "" -> Some (\`Tcp (Net.Ipaddr.V4.any, int_of_string p)) | _ -> None in
main ?addr env
let () =
if !Sys.interactive then () else
Io_main.run @@ fun env ->
exit @@ Cmd.eval (object end) @@ main' ~env