···99 val delete : dir -> string -> unit
1010 val size : file -> int64
1111 val read : ?off:int64 -> ?len:int64 -> file -> string
1212+ val write : ?off:int64 -> ?len:int64 -> file -> string -> unit
1213end
13141415module type Sigs = sig
+78-28
mvp/ocaml/client/client.ml
···3131 let results = Capability.call_for_value_exn t method_id request in
3232 match Results.file_get results with
3333 | Some file -> file
3434- | None -> failwith "create: no file returned"
3434+ | None -> failwith "Storage.create: no file returned"
35353636 let open_ t name =
3737 let open API.Client.Directory.Open in
3838 let request, params = Capability.Request.create Params.init_pointer in
3939 Params.name_set params name;
4040- let results = Capability.call_for_value_exn t method_id request in
4141- match Results.file_get results with
4242- | Some file -> file
4343- | None -> failwith "open: no file returned"
4040+ Capability.call_for_caps t method_id request Results.file_get_pipelined
44414542 let delete t name =
4643 let open API.Client.Directory.Delete in
···7067 in
7168 let results = Capability.call_for_value_exn t method_id request in
7269 Results.data_get results
7070+7171+ let write ?off ?len t d =
7272+ let open API.Client.File.Write in
7373+ let request, params = Capability.Request.create Params.init_pointer in
7474+ let () =
7575+ match off with
7676+ | None -> ()
7777+ | Some off -> Params.off_set params (Stdint.Int64.to_uint64 off)
7878+ in
7979+ let () =
8080+ match len with
8181+ | None -> ()
8282+ | Some len -> Params.len_set params (Stdint.Int64.to_uint64 len)
8383+ in
8484+ Params.data_set params d;
8585+ Capability.call_for_unit_exn t method_id request
7386end
74877588let connect net uri f =
···8194let pp_name ppf name = Fmt.pf ppf "%a" Fmt.(styled `Bold string) name
8295let pp_entry ppf entry = pp_name ppf entry.Storage.name
83968484-let ls net uri =
9797+let ls net () uri =
8598 connect net uri @@ fun dir ->
8699 let entries = Storage.list dir in
8787- Printf.printf "total %d:\n" (List.length entries);
100100+ Fmt.pr "total %d:\n" (List.length entries);
88101 List.iter (Fmt.pr "- %a\n" pp_entry) entries;
89102 Fmt.pr "%!"
901039191-let create net uri name =
104104+let create net () uri name data =
92105 connect net uri @@ fun dir ->
9393- let _file = Storage.create dir name in
9494- Fmt.pr "Created file '%a'\n" pp_name name
106106+ let file = Storage.create dir name in
107107+ Storage.write file data;
108108+ Fmt.pr "%a is created.\n%!" pp_name name
951099696-let open_file net uri name =
110110+let open_file net () uri name =
97111 connect net uri @@ fun dir ->
98112 let _file = Storage.open_ dir name in
9999- Fmt.pr "Opened file <raw>\n"
113113+ Fmt.pr "%a: <raw>.\n%!" pp_name name
100114101101-let delete net uri name =
115115+let delete net () uri name =
102116 connect net uri @@ fun dir ->
103117 Storage.delete dir name;
104104- Fmt.pr "Deleted file '%a'\n" pp_name name
118118+ Fmt.pr "%a is deleted.\n%!" pp_name name
105119106106-let size net uri name =
120120+let size net () uri name =
107121 connect net uri @@ fun dir ->
108122 let file = Storage.open_ dir name in
109123 let size = Storage.size file in
110110- Fmt.pr "Size of '%s': %Ld bytes\n" name size
124124+ Fmt.pr "%a: %Ld bytes.\n%!" pp_name name size
111125112112-let read net addr name offset length =
113113- connect net addr @@ fun dir ->
114114- let file = Storage.open_ dir name in
126126+let read net () uri name offset length =
127127+ connect net uri @@ fun dir ->
128128+ Capability.with_ref (Storage.open_ dir name) @@ fun file ->
115129 let data = Storage.read ?off:offset ?len:length file in
116116- Printf.printf "Contents of '%s':\n%s\n" name data
130130+ Fmt.pr "%a: %S\n%!" pp_name name data
131131+132132+let write net () uri name offset length data =
133133+ connect net uri @@ fun dir ->
134134+ Capability.with_ref (Storage.open_ dir name) @@ fun file ->
135135+ Storage.write ?off:offset ?len:length file data;
136136+ Fmt.pr "%d bytes successfully written into %a.\n%!" (String.length data)
137137+ pp_name name
117138118139open Cmdliner
119140···122143 Logs.set_reporter (Logs_fmt.reporter ())
123144124145let connect_addr =
125125- let i = Arg.info [] ~docv:"ADDR" ~doc:"Address of server (capnp://...)" in
126126- Arg.(required @@ pos 0 (some Capnp_rpc_unix.sturdy_uri) None i)
146146+ let env = Cmd.Env.info "BELLAIRS_CAP" in
147147+ let i =
148148+ Arg.info ~env [ "cap" ] ~docv:"CAP" ~doc:"capabilities file(capnp://...)"
149149+ in
150150+ Arg.(required @@ opt (some Capnp_rpc_unix.sturdy_uri) None i)
127151128152let name_arg =
129153 let i = Arg.info [] ~docv:"NAME" ~doc:"Name of the file" in
154154+ Arg.(required @@ pos 0 (some string) None i)
155155+156156+let data_arg =
157157+ let i = Arg.info [] ~docv:"DATA" ~doc:"Data of the file" in
130158 Arg.(required @@ pos 1 (some string) None i)
131159132160let offset_arg =
···143171 in
144172 Arg.(value @@ opt (some int64) None i)
145173174174+let setup_log style_renderer level =
175175+ Fmt_tty.setup_std_outputs ?style_renderer ();
176176+ Logs.set_level level;
177177+ Logs.set_reporter (Logs_fmt.reporter ());
178178+ ()
179179+180180+let setup_log =
181181+ Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ())
182182+146183let ls_cmd env =
147184 let doc = "List files in the directory" in
148185 let info = Cmd.info "ls" ~doc in
149149- Cmd.v info Term.(const (ls env#net) $ connect_addr)
186186+ Cmd.v info Term.(const (ls env#net) $ setup_log $ connect_addr)
150187151188let create_cmd env =
152189 let doc = "Create a new file" in
153190 let info = Cmd.info "create" ~doc in
154154- Cmd.v info Term.(const (create env#net) $ connect_addr $ name_arg)
191191+ Cmd.v info
192192+ Term.(
193193+ const (create env#net) $ setup_log $ connect_addr $ name_arg $ data_arg)
155194156195let open_cmd env =
157196 let doc = "Open an existing file and show its ID" in
158197 let info = Cmd.info "open" ~doc in
159159- Cmd.v info Term.(const (open_file env#net) $ connect_addr $ name_arg)
198198+ Cmd.v info
199199+ Term.(const (open_file env#net) $ setup_log $ connect_addr $ name_arg)
160200161201let delete_cmd env =
162202 let doc = "Delete a file" in
163203 let info = Cmd.info "delete" ~doc in
164164- Cmd.v info Term.(const (delete env#net) $ connect_addr $ name_arg)
204204+ Cmd.v info Term.(const (delete env#net) $ setup_log $ connect_addr $ name_arg)
165205166206let size_cmd env =
167207 let doc = "Get the size of a file" in
168208 let info = Cmd.info "size" ~doc in
169169- Cmd.v info Term.(const (size env#net) $ connect_addr $ name_arg)
209209+ Cmd.v info Term.(const (size env#net) $ setup_log $ connect_addr $ name_arg)
170210171211let read_cmd env =
172212 let doc = "Read the contents of a file" in
173213 let info = Cmd.info "read" ~doc in
174214 Cmd.v info
175215 Term.(
176176- const (read env#net) $ connect_addr $ name_arg $ offset_arg $ length_arg)
216216+ const (read env#net)
217217+ $ setup_log $ connect_addr $ name_arg $ offset_arg $ length_arg)
218218+219219+let write_cmd env =
220220+ let doc = "Write some contents to a file" in
221221+ let info = Cmd.info "write" ~doc in
222222+ Cmd.v info
223223+ Term.(
224224+ const (write env#net)
225225+ $ setup_log $ connect_addr $ name_arg $ offset_arg $ length_arg $ data_arg)
177226178227let main_cmd env =
179228 let doc = "Bellairs Storage Client" in
···186235 delete_cmd env;
187236 size_cmd env;
188237 read_cmd env;
238238+ write_cmd env;
189239 ]
190240191241let () = exit @@ Eio_main.run @@ fun env -> Cmd.eval (main_cmd env)
···1111 let open Directory.Create in
1212 let name = Params.name_get params in
1313 release_param_caps ();
1414- let response, results = Service.Response.create Results.init_pointer in
1514 let file = Impl.create dir name in
1615 let file_cap = File.local file in
1717- (* TODO: add persistence *)
1616+ let response, results = Service.Response.create Results.init_pointer in
1817 Results.file_set results (Some file_cap);
1818+ Capability.dec_ref file_cap;
1919 Service.return response
20202121 method list_impl _ release_param_caps =
···2929 List.iteri
3030 (fun i e ->
3131 let entry = Capnp.Array.get entries_array i in
3232+ let file = File.local e.Impl.file in
3233 API.Builder.Directory.Entry.name_set entry e.Impl.name;
3333- API.Builder.Directory.Entry.file_set entry
3434- (Some (File.local e.Impl.file)))
3434+ API.Builder.Directory.Entry.file_set entry (Some file))
3535 entries;
3636 Service.return response
37373838- method open_impl params release_param_caps =
3838+ method open_impl params _release_param_caps =
3939 let open Directory.Open in
4040 let name = Params.name_get params in
4141- release_param_caps ();
4241 let response, results = Service.Response.create Results.init_pointer in
4342 try
4443 let file = Impl.open_ dir name in
4545- Results.file_set results (Some (File.local file));
4444+ let file_cap = File.local file in
4545+ Results.file_set results (Some file_cap);
4646 Service.return response
4747 with Not_found -> Service.fail "File '%s' not found" name
4848
···11open Capnp_rpc.Std
2233+let int64_of_uint64 n =
44+ match Stdint.Int64.of_uint64 n with -1L -> None | i -> Some i
55+36let local file =
47 let module File = API.Service.File in
58 File.local
···811912 method read_impl params release_param_caps =
1013 let open File.Read in
1111- let off = Stdint.Int64.of_uint64 (Params.off_get params) in
1212- let len = Stdint.Int64.of_uint64 (Params.len_get params) in
1414+ let off = int64_of_uint64 (Params.off_get params) in
1515+ let len = int64_of_uint64 (Params.len_get params) in
1316 release_param_caps ();
1417 let response, results = Service.Response.create Results.init_pointer in
1515- let data = Impl.read file ~off ~len in
1818+ let data = Impl.read file ?off ?len in
1619 Results.data_set results data;
2020+ Service.return response
2121+2222+ method write_impl params release_param_caps =
2323+ let open File.Write in
2424+ let off = int64_of_uint64 (Params.off_get params) in
2525+ let len = int64_of_uint64 (Params.len_get params) in
2626+ let data = Params.data_get params in
2727+ release_param_caps ();
2828+ let response = Service.Response.create_empty () in
2929+ Impl.write file ?off ?len data;
1730 Service.return response
18311932 method size_impl _ release_param_caps =
+23-6
mvp/ocaml/server/impl.ml
···11(* TODO: put the real implementation here -- for now it's just an
22 in-memory database *)
3344-type file = { content : string; size : int64 }
44+type file = { mutable content : string }
55type dir = (string, file) Hashtbl.t
66type entry = { name : string; file : file }
7788let create files name =
99- let file = { content = ""; size = 0L } in
99+ let file = { content = "" } in
1010 Hashtbl.add files name file;
1111 file
1212···1919let open_ (files : dir) name = Hashtbl.find files name
2020let delete files name = Hashtbl.remove files name
21212222-let read ?(off = 0L) ?(len = Int64.max_int) file =
2222+let read ?(off = 0L) ?len file =
2323 let content_len = String.length file.content in
2424 let off = Int64.to_int off in
2525- let len = Int64.to_int len in
2626- let off = max 0 (min off content_len) in
2525+ let len =
2626+ match len with None -> content_len | Some len -> Int64.to_int len
2727+ in
2728 let max_len = content_len - off in
2829 let len = if len >= max_len then max_len else len in
2930 String.sub file.content off len
30313131-let size file = file.size
3232+let write ?(off = 0L) ?len file data =
3333+ let data_len = String.length data in
3434+ let off = Int64.to_int off in
3535+ let len = match len with None -> data_len | Some len -> Int64.to_int len in
3636+ let required_len = off + len in
3737+ let file_content =
3838+ if required_len > String.length file.content then (
3939+ let new_content = Bytes.make required_len '\000' in
4040+ String.blit file.content 0 new_content 0 (String.length file.content);
4141+ let new_content = Bytes.unsafe_to_string new_content in
4242+ file.content <- new_content;
4343+ new_content)
4444+ else file.content
4545+ in
4646+ String.blit data 0 (Bytes.unsafe_of_string file_content) off len
4747+4848+let size file = Int64.of_int (String.length file.content)
32493350let list files =
3451 Hashtbl.fold (fun name file acc -> { name; file } :: acc) files []
+12-6
mvp/ocaml/server/server.ml
···3344let cap_file = "storage.cap"
5566-let serve config =
66+let serve () config =
77 Switch.run @@ fun sw ->
88 let root_id = Capnp_rpc_unix.Vat_config.derived_id config "root" in
99- let restore = Restorer.single root_id (Directory.local (Impl.root ())) in
99+ let root = Impl.root () in
1010+ let restore = Restorer.single root_id (Directory.local root) in
1011 let vat = Capnp_rpc_unix.serve ~sw ~restore config in
1112 match Capnp_rpc_unix.Cap_file.save_service vat root_id cap_file with
1213 | Error (`Msg m) -> failwith m
···16171718open Cmdliner
18191919-let () =
2020- Logs.set_level (Some Logs.Warning);
2121- Logs.set_reporter (Logs_fmt.reporter ())
2020+let setup_log style_renderer level =
2121+ Fmt_tty.setup_std_outputs ?style_renderer ();
2222+ Logs.set_level level;
2323+ Logs.set_reporter (Logs_fmt.reporter ());
2424+ ()
2525+2626+let setup_log =
2727+ Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ())
22282329let serve_cmd env =
2430 let doc = "run the server" in
2531 let info = Cmd.info "serve" ~doc in
2626- Cmd.v info Term.(const serve $ Capnp_rpc_unix.Vat_config.cmd env)
3232+ Cmd.v info Term.(const serve $ setup_log $ Capnp_rpc_unix.Vat_config.cmd env)
27332834let () = exit @@ Eio_main.run @@ fun env -> Cmd.eval (serve_cmd env)
+6-3
mvp/schema/storage.capnp
···2233interface Directory {
44 # Represents a directory in the filesystem
55-55+66 list @0 () -> (entries :List(Entry));
77 # Lists all entries in the directory
88···23232424interface File {
2525 # Represents a file in the filesystem
2626-2626+2727 size @0 () -> (size :UInt64);
2828 # Returns the size of the file in bytes
29293030 read @1 (off :UInt64 = 0, len :UInt64 = 0xffffffffffffffff) -> (data :Data);
3131 # Reads data from the file, optionally starting at offset and reading up to len bytes
3232 # Default is to read the entire file
3333+3434+ write @2 (off :UInt64 = 0, len :UInt64 = 0xffffffffffffffff, data :Data) -> ();
3535+ # Write data to the file, optionally starting at offset and reading up to len bytes
3636+ # Default is to write the entire file
3337}
3434-