123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)moduleParameters=structtypepersistent_state={runner:Runner.toption;base_dir:string;node:Node.t;mutablepending_ready:unitoptionLwt.ulist;preserved_levels:intoption;}typesession_state={mutableready:bool}letbase_default_name="accuser"letdefault_colors=Log.Color.[|BG.yellow++FG.black;BG.yellow++FG.gray;BG.yellow++FG.blue|]endopenParametersincludeDaemon.Make(Parameters)letnode_rpc_portaccuser=Node.rpc_portaccuser.persistent_state.nodelettrigger_readyaccuservalue=letpending=accuser.persistent_state.pending_readyinaccuser.persistent_state.pending_ready<-[];List.iter(funpending->Lwt.wakeup_laterpendingvalue)pendingletset_readyaccuser=(matchaccuser.statuswith|Not_running->()|Runningstatus->status.session_state.ready<-true);trigger_readyaccuser(Some())lethandle_raw_stdoutaccuserline=ifline=~rex"^Waiting for protocol .+ to start...$"thenset_readyaccuserletcreate~protocol?name?color?event_pipe?base_dir?runner?preserved_levelsnode=letname=matchnamewithNone->fresh_name()|Somename->nameinletbase_dir=matchbase_dirwithNone->Temp.dirname|Somedir->dirinletaccuser=create~path:(Protocol.accuserprotocol)?name:(Somename)?color?event_pipe?runner{runner;base_dir;node;pending_ready=[];preserved_levels}inon_stdoutaccuser(handle_raw_stdoutaccuser);accuserletrun?event_levelaccuser=(matchaccuser.statuswith|Not_running->()|Running_->Test.fail"accuser %s is already running"accuser.name);letrunner=accuser.persistent_state.runnerinletnode_runner=Node.runneraccuser.persistent_state.nodeinletnode_rpc_port=node_rpc_portaccuserinletaddress="http://"^Runner.address?from:runnernode_runner^":"inletpreserved_levels=Cli_arg.optional_arg"preserved-levels"string_of_intaccuser.persistent_state.preserved_levelsinletarguments=["-E";address^string_of_intnode_rpc_port;"--base-dir";accuser.persistent_state.base_dir;"run";]@preserved_levelsinleton_terminate_=(* Cancel all [Ready] event listeners. *)trigger_readyaccuserNone;unitinrun?event_levelaccuser{ready=false}arguments~on_terminate?runnerletcheck_event?whereaccusernamepromise=let*result=promiseinmatchresultwith|None->raise(Terminated_before_event{daemon=accuser.name;event=name;where})|Somex->returnxletwait_for_readyaccuser=matchaccuser.statuswith|Running{session_state={ready=true;_};_}->unit|Not_running|Running{session_state={ready=false;_};_}->letpromise,resolver=Lwt.task()inaccuser.persistent_state.pending_ready<-resolver::accuser.persistent_state.pending_ready;check_eventaccuser"Accuser started."promiseletinit~protocol?name?color?event_pipe?event_level?base_dir?runner?preserved_levelsnode=let*()=Node.wait_for_readynodeinletaccuser=create~protocol?name?color?event_pipe?base_dir?runner?preserved_levelsnodeinlet*()=run?event_levelaccuserinlet*()=wait_for_readyaccuserinreturnaccuserletrestartaccuser=let*()=terminateaccuserinlet*()=runaccuserinwait_for_readyaccuser