···6677- Add your SSH key to the tangled.sh login under 'Settings'.
8899-- use port 2222 for the SSH !!! Put the following into `~/.ssh/config`:
99+- use port 2222 for the SSH !!!
1010+ Put the following into `~/.ssh/config`:
10111112```
1213Host git.recoil.org
-18
mvp/bellairs.mli
···11-22-type dir
33-type file
44-55-type entry = {
66- name: string;
77- file: file;
88-}
99-1010-val root : dir
1111-val list : dir -> entry list
1212-1313-val create : dir -> string -> file
1414-val open_ : dir -> string -> file
1515-val delete : dir -> string -> unit
1616-1717-val size : file -> int64
1818-val read : file -> ?off:int64 -> ?len:int64 -> string
···11+module type Storage = sig
22+ type dir
33+ type file
44+ type entry = { name : string; file : file }
55+66+ val list : dir -> entry list
77+ val create : dir -> string -> file
88+ val open_ : dir -> string -> file
99+ val delete : dir -> string -> unit
1010+ val size : file -> int64
1111+ val read : ?off:int64 -> ?len:int64 -> file -> string
1212+end
1313+1414+module type Sigs = sig
1515+ module type Storage = Storage
1616+end
+59
mvp/ocaml/client/client.ml
···11+open Capnp_rpc.Std
22+open Eio.Std
33+44+module Storage :
55+ Bellairs.Storage
66+ with type file = [ `File_e62ce624f782d37e ] Capability.t
77+ and type dir = [ `Directory_8e98f5ea254aace5 ] Capability.t = struct
88+ module API = Schema.Storage.MakeRPC (Capnp_rpc)
99+1010+ type file = API.Client.File.t Capability.t
1111+ type dir = API.Client.Directory.t Capability.t
1212+ type entry = { name : string; file : file }
1313+1414+ let entry r =
1515+ let name = API.Reader.Directory.Entry.name_get r in
1616+ let file = API.Reader.Directory.Entry.file_get r in
1717+ match file with
1818+ | Some file -> { name; file }
1919+ | None -> failwith "missing entry.file"
2020+2121+ let todo msg = failwith ("Storage." ^ msg)
2222+2323+ let list t =
2424+ let open API.Client.Directory.List in
2525+ let request = Capability.Request.create_no_args () in
2626+ let results = Capability.call_for_value_exn t method_id request in
2727+ let entries = Results.entries_get_list results in
2828+ List.map entry entries
2929+3030+ let create _ = todo "create"
3131+ let open_ _ = todo "open"
3232+ let delete _ = todo "delete"
3333+ let size _ = todo "size"
3434+ let read ?off:_ ?len:_ _ = todo "read"
3535+end
3636+3737+let ls net uri =
3838+ Switch.run @@ fun sw ->
3939+ let client_vat = Capnp_rpc_unix.client_only_vat ~sw net in
4040+ let sr = Capnp_rpc_unix.Vat.import_exn client_vat uri in
4141+ let entries = Capnp_rpc_unix.with_cap_exn sr Storage.list in
4242+ List.iter (fun { Storage.name; _ } -> Fmt.pr "- %s\n" name) entries
4343+4444+open Cmdliner
4545+4646+let () =
4747+ Logs.set_level (Some Logs.Warning);
4848+ Logs.set_reporter (Logs_fmt.reporter ())
4949+5050+let connect_addr =
5151+ let i = Arg.info [] ~docv:"ADDR" ~doc:"Address of server (capnp://...)" in
5252+ Arg.(required @@ pos 0 (some Capnp_rpc_unix.sturdy_uri) None i)
5353+5454+let ls_cmd env =
5555+ let doc = "run the client" in
5656+ let info = Cmd.info "ls" ~doc in
5757+ Cmd.v info Term.(const (ls env#net) $ connect_addr)
5858+5959+let () = exit @@ Eio_main.run @@ fun env -> Cmd.eval (ls_cmd env)
···11+open Eio.Std
22+open Capnp_rpc_net
33+44+let cap_file = "storage.cap"
55+66+module API = Schema.Storage.MakeRPC (Capnp_rpc)
77+open Capnp_rpc.Std
88+99+let todo msg = failwith ("TODO: " ^ msg)
1010+1111+module Impl : sig
1212+ include Bellairs.Storage
1313+1414+ val root : unit -> dir
1515+end = struct
1616+ type file = { content : string; size : int64 }
1717+ type dir = (string, file) Hashtbl.t
1818+ type entry = { name : string; file : file }
1919+2020+ let create files name =
2121+ let file = { content = ""; size = 0L } in
2222+ Hashtbl.add files name file;
2323+ file
2424+2525+ let root () =
2626+ let tbl = Hashtbl.create 10 in
2727+ let _ = create tbl "foo" in
2828+ let _ = create tbl "bar" in
2929+ tbl
3030+3131+ let open_ (files : dir) name =
3232+ try Hashtbl.find files name with Not_found -> failwith "file not found"
3333+3434+ let delete files name = Hashtbl.remove files name
3535+3636+ let read ?(off = 0L) ?(len = Int64.max_int) file =
3737+ let content_len = String.length file.content in
3838+ let off = Int64.to_int off in
3939+ let len = Int64.to_int len in
4040+ let off = max 0 (min off content_len) in
4141+ let max_len = content_len - off in
4242+ let len = if len >= max_len then max_len else len in
4343+ String.sub file.content off len
4444+4545+ let size file = file.size
4646+4747+ let list files =
4848+ Hashtbl.fold (fun name file acc -> { name; file } :: acc) files []
4949+end
5050+5151+module File = struct
5252+ let local file =
5353+ let module File = API.Service.File in
5454+ File.local
5555+ @@ object
5656+ inherit File.service
5757+5858+ method read_impl params release_param_caps =
5959+ let open File.Read in
6060+ let off = Stdint.Int64.of_uint64 (Params.off_get params) in
6161+ let len = Stdint.Int64.of_uint64 (Params.len_get params) in
6262+ release_param_caps ();
6363+ let response, results =
6464+ Service.Response.create Results.init_pointer
6565+ in
6666+ let data = Impl.read file ~off ~len in
6767+ Results.data_set results data;
6868+ Service.return response
6969+7070+ method size_impl _ release_param_caps =
7171+ let open File.Size in
7272+ release_param_caps ();
7373+ let response, results =
7474+ Service.Response.create Results.init_pointer
7575+ in
7676+ let size = Stdint.Int64.to_uint64 (Impl.size file) in
7777+ Results.size_set results size;
7878+ Service.return response
7979+ end
8080+end
8181+8282+module Directory = struct
8383+ let local dir =
8484+ let module Directory = API.Service.Directory in
8585+ Directory.local
8686+ @@ object
8787+ inherit Directory.service
8888+ method create_impl _ = todo "create_impl"
8989+9090+ method list_impl _ release_param_caps =
9191+ let open Directory.List in
9292+ release_param_caps ();
9393+ let response, results =
9494+ Service.Response.create Results.init_pointer
9595+ in
9696+ let entries = Impl.list dir in
9797+9898+ let entries_array =
9999+ Results.entries_init results (List.length entries)
100100+ in
101101+ List.iteri
102102+ (fun i e ->
103103+ let entry = Capnp.Array.get entries_array i in
104104+ API.Builder.Directory.Entry.name_set entry e.Impl.name;
105105+ API.Builder.Directory.Entry.file_set entry
106106+ (Some (File.local e.Impl.file)))
107107+ entries;
108108+109109+ Service.return response
110110+111111+ method size_impl _ = todo "size_impl"
112112+ method open_impl _ = todo "open_impl"
113113+ method delete_impl _ = todo "delete_impl"
114114+ end
115115+end
116116+117117+let serve config =
118118+ Switch.run @@ fun sw ->
119119+ let service_id = Capnp_rpc_unix.Vat_config.derived_id config "main" in
120120+ let restore = Restorer.single service_id (Directory.local (Impl.root ())) in
121121+ let vat = Capnp_rpc_unix.serve ~sw ~restore config in
122122+ match Capnp_rpc_unix.Cap_file.save_service vat service_id cap_file with
123123+ | Error (`Msg m) -> failwith m
124124+ | Ok () ->
125125+ traceln "Server running. Connect using %S." cap_file;
126126+ Fiber.await_cancel ()
127127+128128+open Cmdliner
129129+130130+let () =
131131+ Logs.set_level (Some Logs.Warning);
132132+ Logs.set_reporter (Logs_fmt.reporter ())
133133+134134+let serve_cmd env =
135135+ let doc = "run the server" in
136136+ let info = Cmd.info "serve" ~doc in
137137+ Cmd.v info Term.(const serve $ Capnp_rpc_unix.Vat_config.cmd env)
138138+139139+let () = exit @@ Eio_main.run @@ fun env -> Cmd.eval (serve_cmd env)