···11+(* Kinda findlib, sorta *)
22+33+44+type library = {
55+ name : string;
66+ meta_uri : Uri.t;
77+ archive_name : string option;
88+ dir : string option;
99+ deps : string list;
1010+ mutable loaded : bool;
1111+}
1212+1313+let read_libraries_from_pkg_defs ~library_name meta_uri pkg_defs =
1414+ try
1515+ let archive_filename =
1616+ try Some (Fl_metascanner.lookup "archive" [ "byte" ] pkg_defs)
1717+ with _ -> (
1818+ try Some (Fl_metascanner.lookup "archive" [ "native" ] pkg_defs)
1919+ with _ -> None)
2020+ in
2121+2222+ let deps_str = Fl_metascanner.lookup "requires" [] pkg_defs in
2323+ let deps = Astring.String.fields ~empty:false deps_str in
2424+ let dir =
2525+ List.find_opt (fun d -> d.Fl_metascanner.def_var = "directory") pkg_defs
2626+ in
2727+ let dir = Option.map (fun d -> d.Fl_metascanner.def_value) dir in
2828+ let archive_name =
2929+ Option.bind archive_filename (fun a ->
3030+ let file_name_len = String.length a in
3131+ if file_name_len > 0 then Some (Filename.chop_extension a) else None)
3232+ in
3333+ [ { name = library_name; archive_name; dir; deps; meta_uri; loaded=false } ]
3434+ with Not_found -> []
3535+3636+3737+type t = library list
3838+3939+let dcs_filename = "dynamic_cmis.json"
4040+4141+let fetch_dynamic_cmis url =
4242+ match Jslib.sync_get url with
4343+ | None -> Error (`Msg "Failed to fetch dynamic cmis")
4444+ | Some json ->
4545+ let rpc = Jsonrpc.of_string json in
4646+ Rpcmarshal.unmarshal Js_top_worker_rpc.Toplevel_api_gen.typ_of_dynamic_cmis rpc
4747+4848+let init findlib_metas : t =
4949+ let metas = List.filter_map (fun x ->
5050+ match Jslib.sync_get x with
5151+ | Some meta -> Some (x, meta)
5252+ | None -> None) findlib_metas in
5353+ List.flatten @@ List.filter_map (fun (x, meta) ->
5454+ match Angstrom.parse_string ~consume:All Uri.Parser.uri_reference x with
5555+ | Ok uri -> (
5656+ Jslib.log "Parsed uri: %s" (Uri.path uri);
5757+ let path = Uri.path uri in
5858+ let file = Fpath.v path in
5959+ let base_library_name =
6060+ if Fpath.basename file = "META" then Fpath.parent file |> Fpath.basename
6161+ else Fpath.get_ext file
6262+ in
6363+6464+ let lexing = Lexing.from_string meta in
6565+ try
6666+ let meta = Fl_metascanner.parse_lexing lexing in
6767+ let rec extract_name_and_archive ~prefix
6868+ ((name, pkg_expr) : string * Fl_metascanner.pkg_expr) =
6969+ let library_name = prefix ^ "." ^ name in
7070+ let libraries =
7171+ read_libraries_from_pkg_defs ~library_name uri pkg_expr.pkg_defs
7272+ in
7373+ let child_libraries =
7474+ pkg_expr.pkg_children
7575+ |> List.map (extract_name_and_archive ~prefix:library_name)
7676+ |> List.flatten
7777+ in
7878+ libraries @ child_libraries
7979+ in
8080+ let libraries =
8181+ read_libraries_from_pkg_defs ~library_name:base_library_name uri meta.pkg_defs
8282+ in
8383+ let libraries =
8484+ libraries
8585+ @ (meta.pkg_children
8686+ |> List.map (extract_name_and_archive ~prefix:base_library_name)
8787+ |> List.flatten) in
8888+ Some libraries
8989+ with _ ->
9090+ Jslib.log "Failed to parse meta: %s" (Uri.path uri);
9191+ None)
9292+ | Error m ->
9393+ Jslib.log "Failed to parse uri: %s" m; None) metas
9494+9595+9696+let require v packages =
9797+ let rec require dcss package : Js_top_worker_rpc.Toplevel_api_gen.dynamic_cmis list =
9898+ match List.find (fun lib -> lib.name = package) v with
9999+ | exception Not_found ->
100100+ Jslib.log "Package %s not found" package;
101101+ dcss
102102+ | lib ->
103103+ if lib.loaded
104104+ then dcss
105105+ else begin
106106+ let dep_dcs = List.fold_left require dcss lib.deps in
107107+ let path = Uri.path lib.meta_uri in
108108+ let dir = Fpath.v path |> Fpath.parent in
109109+ let dcs = Fpath.(dir / dcs_filename |> to_string) in
110110+ let uri = Uri.with_path lib.meta_uri dcs in
111111+ match fetch_dynamic_cmis (Uri.to_string uri) with
112112+ | Ok dcs ->
113113+ let () = match lib.archive_name with
114114+ | None -> ()
115115+ | Some archive ->
116116+ let dir = match lib.dir with None -> dir | Some d -> Fpath.append dir (Fpath.v d) in
117117+ let archive_js = Fpath.(dir / (archive ^ ".cma.js") |> to_string) in
118118+ Js_of_ocaml.Worker.import_scripts [(Uri.with_path uri archive_js |> Uri.to_string)];
119119+ lib.loaded <- true
120120+ in
121121+ dcs :: dep_dcs
122122+ | Error (`Msg m) ->
123123+ Jslib.log "Failed to unmarshal dynamic_cms from url %s: %s" (Uri.to_string uri) m;
124124+ dcss
125125+ end
126126+ in
127127+ List.fold_left require [] packages
+23-1
lib/impl.ml
···34343535end
3636module type S = sig
3737+ type findlib_t
3738 val capture : (unit -> 'a) -> unit -> captured * 'a
3839 val create_file : name:string -> content:string -> unit
3940 val sync_get : string -> string option
40414142 val import_scripts : string list -> unit
4243 val init_function : string -> (unit -> unit )
4444+4545+ val get_stdlib_dcs : string -> Toplevel_api_gen.dynamic_cmis list
4646+4747+ val findlib_init : string list -> findlib_t
4848+4949+ val require : findlib_t -> string list -> Toplevel_api_gen.dynamic_cmis list
4350end
44514552module Make (S : S) = struct
4653 let functions : (unit -> unit) list option ref = ref None
5454+ let requires : string list ref = ref []
4755 let path : string option ref = ref None
5656+ let findlib_v : S.findlib_t option ref = ref None
48574958 let refill_lexbuf s p ppf buffer len =
5059 if !p = String.length s then 0
···278287 Logs.info (fun m -> m "init()");
279288 path := Some init_libs.path;
280289290290+ findlib_v := Some (S.findlib_init init_libs.findlib_metas);
291291+292292+ (match S.get_stdlib_dcs init_libs.stdlib_dcs with
293293+ |[dcs] -> add_dynamic_cmis dcs
294294+ | _ -> ());
281295 Clflags.no_check_prims := true;
282296 List.iter
283297 (fun { Toplevel_api_gen.sc_name; sc_content } ->
···291305292306 S.import_scripts
293307 (List.map (fun cma -> cma.Toplevel_api_gen.url) init_libs.cmas);
308308+309309+ requires := init_libs.findlib_requires;
294310 functions :=
295311 Some
296312 (List.map
···328344 let err = Format.asprintf "%a" Env.report_error e in
329345 failwith ("Error: " ^ err))
330346 in
331331-347347+348348+ let dcs = (match !findlib_v with
349349+ | Some v ->
350350+ S.require v !requires
351351+ | None -> []) in
352352+ List.iter add_dynamic_cmis dcs;
353353+332354 Logs.info (fun m -> m "setup() finished");
333355334356 IdlM.ErrM.return
+21
lib/jslib.ml
···11+let log fmt =
22+ Format.kasprintf
33+ (fun s -> Js_of_ocaml.(Console.console##log (Js.string s)))
44+ fmt
55+66+let sync_get url =
77+ let open Js_of_ocaml in
88+ let x = XmlHttpRequest.create () in
99+ x##.responseType := Js.string "arraybuffer";
1010+ x##_open (Js.string "GET") (Js.string url) Js._false;
1111+ x##send Js.null;
1212+ match x##.status with
1313+ | 200 ->
1414+ Js.Opt.case
1515+ (File.CoerceTo.arrayBuffer x##.response)
1616+ (fun () ->
1717+ Console.console##log (Js.string "Failed to receive file");
1818+ None)
1919+ (fun b -> Some (Typed_array.String.of_arrayBuffer b))
2020+ | _ -> None
2121+
+14-27
lib/worker.ml
···11open Js_top_worker_rpc
22open Js_top_worker
3344-let optbind : 'a option -> ('a -> 'b option) -> 'b option =
55- fun x fn -> match x with None -> None | Some a -> fn a
66-77-let log fmt =
88- Format.kasprintf
99- (fun s -> Js_of_ocaml.(Console.console##log (Js.string s)))
1010- fmt
1111-1212-let sync_get url =
1313- let open Js_of_ocaml in
1414- let x = XmlHttpRequest.create () in
1515- x##.responseType := Js.string "arraybuffer";
1616- x##_open (Js.string "GET") (Js.string url) Js._false;
1717- x##send Js.null;
1818- match x##.status with
1919- | 200 ->
2020- Js.Opt.case
2121- (File.CoerceTo.arrayBuffer x##.response)
2222- (fun () ->
2323- Console.console##log (Js.string "Failed to receive file");
2424- None)
2525- (fun b -> Some (Typed_array.String.of_arrayBuffer b))
2626- | _ -> None
2727-284module Server = Toplevel_api_gen.Make (Impl.IdlM.GenServer ())
295306(* OCamlorg toplevel in a web worker
···3410 thread" keeping the page responsive. *)
35113612let server process e =
3737- log "Worker received: %s" e;
1313+ Jslib.log "Worker received: %s" e;
3814 let _, id, call = Jsonrpc.version_id_and_call_of_string e in
3915 Impl.M.bind (process call) (fun response ->
4016 let rtxt = Jsonrpc.string_of_response ~id response in
4141- log "Worker sending: %s" rtxt;
1717+ Jslib.log "Worker sending: %s" rtxt;
4218 Js_of_ocaml.Worker.post_message rtxt;
4319 Impl.M.return ())
4420···5733 | _ -> None
58345935module S : Impl.S = struct
3636+ type findlib_t = Findlibish.t
3737+6038 let capture : (unit -> 'a) -> unit -> Impl.captured * 'a =
6139 fun f () ->
6240 let stdout_buff = Buffer.create 1024 in
···7452 in
7553 (captured, x)
76547777- let sync_get = sync_get
5555+ let sync_get = Jslib.sync_get
7856 let create_file = Js_of_ocaml.Sys_js.create_file
79575858+ let get_stdlib_dcs uri =
5959+ Findlibish.fetch_dynamic_cmis uri |> Result.to_list
6060+8061 let import_scripts = Js_of_ocaml.Worker.import_scripts
6262+6363+ let findlib_init = Findlibish.init
6464+6565+ let require v = function
6666+ | [] -> []
6767+ | packages -> Findlibish.require v packages
81688269 let init_function func_name =
8370 let open Js_of_ocaml in