123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173(*********************************************************************************)(* 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 *)(* *)(*********************************************************************************)(** *)openOjs_server.ServermoduletypeS=sigmoduleP:Ojs_ed.Types.Pvalaccess_forbidden:Ojs_base.Path.t->P.server_msgclasseditor:(P.server_msg->(P.client_msg->unitLwt.t)->unitLwt.t)->(P.server_msg->unitLwt.t)->id:string->Ojs_base.Path.t->objectmethodcan_read_file:string->boolmethodcan_write_file:string->boolmethodhandle_call:(P.server_msg->unitLwt.t)->P.client_msg->unitLwt.tmethodhandle_get_file_contents:(P.server_msg->unitLwt.t)->Ojs_ed.Types.path->unitLwt.tmethodhandle_message:(P.server_msg->unitLwt.t)->P.client_msg->unitLwt.tmethodhandle_save_file:(P.server_msg->unitLwt.t)->Ojs_ed.Types.path->string->unitLwt.tmethodid:stringmethodroot:Ojs_base.Path.tendclasseditors:(P.app_server_msg->(P.app_client_msg->unitLwt.t)->unitLwt.t)->(P.app_server_msg->unitLwt.t)->((P.server_msg->(P.client_msg->unitLwt.t)->unitLwt.t)->(P.server_msg->unitLwt.t)->id:string->Ojs_base.Path.t->editor)->objectvalmutableeditors:editorOjs_server.Server.SMap.tmethodadd_editor:id:Ojs_server.Server.SMap.key->Ojs_base.Path.t->editormethodeditor:Ojs_server.Server.SMap.key->editormethodhandle_call:(P.app_server_msg->unitLwt.t)->P.app_client_msg->unitLwt.tmethodhandle_message:(P.app_server_msg->unitLwt.t)->P.app_client_msg->unitLwt.tendendmoduleMake(P:Ojs_ed.Types.P)=structmoduleP=Pletaccess_forbiddenpath=P.SError("Forbidden access to "^(Ojs_base.Path.to_stringpath))classeditor(broadcall:P.server_msg->(P.client_msg->unitLwt.t)->unitLwt.t)(broadcast:P.server_msg->unitLwt.t)~idroot=object(self)methodid=(id:string)methodroot=(root:Ojs_base.Path.t)methodcan_read_filefile=truemethodcan_write_filefile=truemethodhandle_get_file_contentsreply_msgpath=letnorm=letpath=Ojs_base.Path.append_pathrootpathinOjs_base.Path.normalizepathinletfile=Ojs_base.Path.to_stringnorminmatchself#can_read_filefilewith|false->reply_msg(access_forbiddenpath)|true->letcontents=Files.string_of_filefileinreply_msg(P.SFile_contents(path,contents))methodhandle_save_filereply_msgpathcontents=letnorm=letpath=Ojs_base.Path.append_pathrootpathinOjs_base.Path.normalizepathinletfile=Ojs_base.Path.to_stringnorminmatchself#can_write_filefilewith|false->reply_msg(access_forbiddenpath)|true->Files.file_of_string~filecontents;reply_msg(P.SOk(Printf.sprintf"File %S saved"(Ojs_base.Path.to_stringpath)))methodhandle_message(send_msg:P.server_msg->unitLwt.t)(msg:P.client_msg)=self#handle_callsend_msgmsgmethodhandle_call(reply_msg:P.server_msg->unitLwt.t)(msg:P.client_msg)=matchmsgwith|P.Get_file_contentspath->self#handle_get_file_contentsreply_msgpath|P.Save_file(path,contents)->self#handle_save_filereply_msgpathcontents|_->reply_msg(P.SError"Unhandled message")endclasseditors(broadcall:P.app_server_msg->(P.app_client_msg->unitLwt.t)->unitLwt.t)(broadcast:P.app_server_msg->unitLwt.t)(spawn:(P.server_msg->(P.client_msg->unitLwt.t)->unitLwt.t)->(P.server_msg->unitLwt.t)->id:string->Ojs_base.Path.t->editor)=object(self)valmutableeditors=(SMap.empty:editorSMap.t)methodeditorid=trySMap.findideditorswithNot_found->failwith(Printf.sprintf"No editor with id %S"id)methodadd_editor~idroot=letbroadcallmsgcb=letcbmsg=matchP.unpack_client_msgmsgwith|Some(_,msg)->cbmsg|None->Lwt.return_unitinbroadcall(P.pack_server_msgidmsg)cbinletbroadcastmsg=broadcast(P.pack_server_msgidmsg)inleted=spawnbroadcallbroadcast~idrootineditors<-SMap.addidededitors;edmethodhandle_message(send_msg:P.app_server_msg->unitLwt.t)(msg:P.app_client_msg)=matchP.unpack_client_msgmsgwith|Some(id,msg)->letsend_msgmsg=send_msg(P.pack_server_msgidmsg)in(self#editorid)#handle_messagesend_msgmsg|None->Lwt.return_unitmethodhandle_call(return:P.app_server_msg->unitLwt.t)(msg:P.app_client_msg)=matchP.unpack_client_msgmsgwith|Some(id,msg)->letreply_msgmsg=return(P.pack_server_msgidmsg)in(self#editorid)#handle_callreply_msgmsg|None->Lwt.return_unitendend