package ojs_filetree
Using filetrees in ojs_base applications, common part
Install
Dune Dependency
Authors
Maintainers
Sources
ojs-base-0.7.0.tar.bz2
md5=85b8a0746e9be8c20cf082f2573b5895
sha512=ec707820ff69ddbf9c631cf6a1c8748e82346daded1a4f73c5702128d07858f915e62d529e5fec01e99263f33eefb1586067341c058535806e0092b9d040644a
doc/src/ojs_filetree.server/server.ml.html
Source file server.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
(*********************************************************************************) (* Ojs-base *) (* *) (* Copyright (C) 2014-2021 INRIA. All rights reserved. *) (* *) (* This program is free software; you can redistribute it and/or modify *) (* it under the terms of the GNU General Public License as *) (* published by the Free Software Foundation, version 3 of the License. *) (* *) (* This program is distributed in the hope that it will be useful, *) (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) (* GNU Library General Public License for more details. *) (* *) (* You should have received a copy of the GNU General Public *) (* License along with this program; if not, write to the Free Software *) (* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *) (* 02111-1307 USA *) (* *) (* As a special exception, you have permission to link this program *) (* with the OCaml compiler and distribute executables, as long as you *) (* follow the requirements of the GNU GPL in regard to all of the *) (* software in the executable aside from the OCaml compiler. *) (* *) (* Contact: Maxence.Guesdon@inria.fr *) (* *) (*********************************************************************************) (** *) open Ojs_server.Server open Lwt.Infix module type S = sig module P : Ojs_filetree.Types.P val access_forbidden : Ojs_base.Path.t -> P.server_msg val creation_forbidden : Ojs_base.Path.t -> P.server_msg val deletion_forbidden : Ojs_base.Path.t -> P.server_msg val renaming_forbidden : Ojs_base.Path.t -> Ojs_base.Path.t -> P.server_msg class filetree : (P.server_msg -> (P.client_msg -> unit Lwt.t) -> unit Lwt.t) -> (P.server_msg -> unit Lwt.t) -> id:string -> Ojs_base.Path.t -> object val mutable file_filter : Ojs_base.Path.t -> bool method after_add_file : Ojs_base.Path.t -> unit method after_get_tree : Ojs_filetree.Types.file_tree list -> Ojs_filetree.Types.file_tree list method before_add_file : Ojs_base.Path.t -> unit method can_add_dir : string -> bool method can_add_file : string -> bool method can_delete : string -> bool method can_rename : string -> string -> bool method handle_add_dir : (P.server_msg -> unit Lwt.t) -> Ojs_filetree.Types.path -> unit Lwt.t method handle_add_file : (P.server_msg -> unit Lwt.t) -> Ojs_filetree.Types.path -> string -> unit Lwt.t method handle_call : (P.server_msg -> unit Lwt.t) -> P.client_msg -> unit Lwt.t method handle_delete : (P.server_msg -> unit Lwt.t) -> Ojs_filetree.Types.path -> unit Lwt.t method handle_message : (P.server_msg -> unit Lwt.t) -> P.client_msg -> unit Lwt.t method handle_rename : (P.server_msg -> unit Lwt.t) -> Ojs_filetree.Types.path -> Ojs_filetree.Types.path -> unit Lwt.t method id : string method root : Ojs_base.Path.t method set_file_filter : (Ojs_base.Path.t -> bool) -> unit end class filetrees : (P.app_server_msg -> (P.app_client_msg -> unit Lwt.t) -> unit Lwt.t) -> (P.app_server_msg -> unit Lwt.t) -> ((P.server_msg -> (P.client_msg -> unit Lwt.t) -> unit Lwt.t) -> (P.server_msg -> unit Lwt.t) -> id:string -> Ojs_base.Path.t -> filetree) -> object val mutable filetrees : filetree Ojs_server.Server.SMap.t method add_filetree : id:Ojs_server.Server.SMap.key -> Ojs_base.Path.t -> filetree method filetree : Ojs_server.Server.SMap.key -> filetree method handle_call : (P.app_server_msg -> unit Lwt.t) -> P.app_client_msg -> unit Lwt.t method handle_message : (P.app_server_msg -> unit Lwt.t) -> P.app_client_msg -> unit Lwt.t end end module Make(P:Ojs_filetree.Types.P) = struct module P = P let access_forbidden path = P.SError (Printf.sprintf "Forbidden access to %S" (Ojs_base.Path.to_string path)) let creation_forbidden path = P.SError (Printf.sprintf "Forbidden creation of %S" (Ojs_base.Path.to_string path)) let deletion_forbidden path = P.SError (Printf.sprintf "Forbidden deletion of %S " (Ojs_base.Path.to_string path)) let renaming_forbidden path1 path2 = P.SError (Printf.sprintf "Forbidden renaming of %S to %S" (Ojs_base.Path.to_string path1) (Ojs_base.Path.to_string path2)) (*c==v=[File.file_of_string]=1.1====*) let file_of_string ~file s = let oc = open_out file in output_string oc s; close_out oc (*/c==v=[File.file_of_string]=1.1====*) class filetree (broadcall : P.server_msg -> (P.client_msg -> unit Lwt.t) -> unit Lwt.t) (broadcast : P.server_msg -> unit Lwt.t) ~id root = object(self) val mutable file_filter = (fun (_:Ojs_base.Path.t) -> true) method set_file_filter f = file_filter <- f method id : string = id method root : Ojs_base.Path.t = root method can_add_file file = true method can_add_dir dir = true method can_delete file = true method can_rename file1 file2 = true method before_add_file (filename : Ojs_base.Path.t) = () method after_add_file (filename : Ojs_base.Path.t) = () method handle_add_file reply_msg path contents = let norm = Ojs_base.Path.normalize path in let file = Ojs_base.Path.to_string (Ojs_base.Path.append_path root norm) in match self#can_add_file file with false -> reply_msg (creation_forbidden path) | true -> let contents = match Base64.decode contents with | Ok c -> c | Error (`Msg msg) -> failwith msg in self#before_add_file norm ; file_of_string ~file contents ; self#after_add_file norm ; let mime = Magic_mime.lookup file in reply_msg P.SOk >>= fun () -> broadcast (P.SAdd_file (path, mime)) method handle_add_dir reply_msg path = let norm = Ojs_base.Path.normalize path in let dir = Ojs_base.Path.to_string (Ojs_base.Path.append_path root norm) in match self#can_add_dir dir with | false -> reply_msg (creation_forbidden path) | true -> try Unix.mkdir dir 0o755 ; reply_msg P.SOk >>= fun () -> broadcast (P.SAdd_dir path) with Unix.Unix_error (e, s1, s2) -> let msg = Printf.sprintf "Could not create %s: %s" (Ojs_base.Path.to_string path) (Unix.error_message e) in reply_msg (P.SError msg) method handle_delete reply_msg path = let norm = Ojs_base.Path.normalize path in let file = Ojs_base.Path.to_string (Ojs_base.Path.append_path root norm) in prerr_endline ("handle_delete, file="^file); match self#can_delete file with | false -> reply_msg (deletion_forbidden path) | true -> if not (Sys.is_directory file) then try Sys.remove file; reply_msg P.SOk >>= fun () -> broadcast (P.SDelete path) with Sys_error msg -> failwith msg else match Sys.command (Printf.sprintf "rm -fr %s" (Filename.quote file)) with 0 -> reply_msg P.SOk >>= fun () -> broadcast (P.SDelete path) | n -> let msg = Printf.sprintf "Could not delete %s" (Ojs_base.Path.to_string path) in reply_msg (P.SError msg) method handle_rename reply_msg path1 path2 = let norm1 = Ojs_base.Path.normalize path1 in let file1 = Ojs_base.Path.to_string (Ojs_base.Path.append_path root norm1) in let norm2 = Ojs_base.Path.normalize path2 in let file2 = Ojs_base.Path.to_string (Ojs_base.Path.append_path root norm2) in match self#can_rename file1 file2 with false -> reply_msg (renaming_forbidden path1 path2) | true -> try Sys.rename file1 file2; reply_msg P.SOk >>= fun () -> broadcast (P.SDelete path1) >>= fun () -> if Sys.is_directory file2 then broadcast (P.SAdd_dir path2) else ( let mime = Magic_mime.lookup file2 in broadcast (P.SAdd_file (path2, mime)) ) with Sys_error msg -> let msg = Printf.sprintf "Could not rename %S to %S: %s" (Ojs_base.Path.to_string path1) (Ojs_base.Path.to_string path2) msg in reply_msg (P.SError msg) method after_get_tree files = files method handle_message (send_msg : 'srv -> unit Lwt.t) (msg : 'clt) = self#handle_call send_msg msg method handle_call (reply_msg : 'srv -> unit Lwt.t) (msg : 'clt) = match msg with P.Get_tree -> let files = Files.file_trees_of_dir ~filepred: file_filter root in let files = self#after_get_tree files in reply_msg (P.STree files) | P.Add_file (path, contents) -> self#handle_add_file reply_msg path contents | P.Add_dir path -> self#handle_add_dir reply_msg path | P.Delete path -> self#handle_delete reply_msg path | P.Rename (path1, path2) -> self#handle_rename reply_msg path1 path2 | _ -> reply_msg (P.SError "Unhandled message") end class filetrees (broadcall : P.app_server_msg -> (P.app_client_msg -> unit Lwt.t) -> unit Lwt.t) (broadcast : P.app_server_msg -> unit Lwt.t) (spawn : (P.server_msg -> (P.client_msg -> unit Lwt.t) -> unit Lwt.t) -> (P.server_msg -> unit Lwt.t) -> id: string -> Ojs_base.Path.t -> filetree ) = object(self) val mutable filetrees = (SMap.empty : filetree SMap.t) method filetree id = try SMap.find id filetrees with Not_found -> failwith (Printf.sprintf "No filetree with id %S" id) method add_filetree ~id root = let broadcall msg cb = let cb msg = match P.unpack_client_msg msg with | Some (_, msg) -> cb msg | _ -> Lwt.return_unit in broadcall (P.pack_server_msg id msg) cb in let broadcast msg = broadcast (P.pack_server_msg id msg) in let ft = spawn broadcall broadcast ~id root in filetrees <- SMap.add id ft filetrees; ft method handle_message (send_msg : P.app_server_msg -> unit Lwt.t) (msg : P.app_client_msg) = match P.unpack_client_msg msg with | Some (id, msg) -> let send_msg msg = send_msg (P.pack_server_msg id msg) in (self#filetree id)#handle_message send_msg msg | None -> Lwt.return_unit method handle_call (return : P.app_server_msg -> unit Lwt.t) (msg : P.app_client_msg) = match P.unpack_client_msg msg with | Some (id, msg) -> let reply_msg msg = return (P.pack_server_msg id msg) in (self#filetree id)#handle_call reply_msg msg | None -> Lwt.return_unit end end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>