123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It 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 Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openPackagemoduleSenv=Server_parametersmoduleJutil=Yojson.Basic.Util(* -------------------------------------------------------------------------- *)(* --- Request Registry --- *)(* -------------------------------------------------------------------------- *)typejson=Data.jsontypekind=[`GET|`SET|`EXEC]moduletypeInput=sigtypetvaljtype:jtypevalof_json:json->tendmoduletypeOutput=sigtypetvaljtype:jtypevalto_json:t->jsonendtype'ainput=(moduleInputwithtypet='a)type'aoutput=(moduleOutputwithtypet='a)(* -------------------------------------------------------------------------- *)(* --- Signals --- *)(* -------------------------------------------------------------------------- *)typesignal=Main.signalletsignal~package~name~descr=letid=Package.declare_id~package~name~descrD_signalinMain.signal(Package.name_of_identid)letemit=Main.emitleton_signal=Main.on_signal(* -------------------------------------------------------------------------- *)(* --- Multiple Fields Requests --- *)(* -------------------------------------------------------------------------- *)moduleFmap=Map.Make(String)typerq={mutableparam:jsonFmap.t;mutableresult:jsonFmap.t;}letfmap_of_jsonrjs=List.fold_left(funr(fd,js)->Fmap.addfdjsr)r(Jutil.to_assocjs)letfmap_to_jsonr=`Assoc(Fmap.fold(funfdjsr->(fd,js)::r)r[])type'aparam=rq->'atype'aresult=rq->'a->unit(* -------------------------------------------------------------------------- *)(* --- Input/Output Request Processing --- *)(* -------------------------------------------------------------------------- *)type_rq_input=|Pnone|Pdata:'ainput->'arq_input|Pfields:fieldInfolist->unitrq_inputtype_rq_output=|Rnone|Rdata:'aoutput->'arq_output|Rfields:fieldInfolist->unitrq_output(* json input syntax *)letrq_input(typea)(input:arq_input):paramInfo=matchinputwith|Pnone->assertfalse|Pdatad->letmoduleD=(vald)inP_valueD.jtype|Pfieldsfds->P_named(List.revfds)(* json output syntax *)letrq_output(typeb)(output:brq_output):paramInfo=matchoutputwith|Rnone->assertfalse|Rdatad->letmoduleD=(vald)inP_valueD.jtype|Rfieldsfds->P_named(List.revfds)(* -------------------------------------------------------------------------- *)(* --- Multi-Parameters Requests --- *)(* -------------------------------------------------------------------------- *)type('a,'b)signature={mutabledefined:bool;mutabledefaults:jsonFmap.t;mutablerequired:stringlist;mutableinput:'arq_input;mutableoutput:'brq_output;}letfailure_missingfmapname=Data.failure~json:(fmap_to_jsonfmap)"Missing parameter '%s'"nameletcheck_requiredfmapfd=ifnot(Fmap.memfdfmap)thenfailure_missingfmapfd(* -------------------------------------------------------------------------- *)(* --- Named Input Parameters Definitions --- *)(* -------------------------------------------------------------------------- *)(* current input fields *)letfds_inputs:fieldInfolist=ifs.definedthenraise(Invalid_argument"Server.Request: already published");matchs.inputwith|Pdata_->raise(Invalid_argument"Server.Request: request has not named input");|Pnone->[]|Pfieldsfds->fdsletparam(typeab)(s:(unit,b)signature)~name~descr?default(input:ainput):aparam=letmoduleD=(valinput)inletftype=ifdefault=NonethenD.jtypeelseJoptionD.jtypeinletfd=Package.{fd_name=name;fd_type=ftype;fd_descr=descr;}ins.input<-Pfields(fd::fds_inputs);funrq->tryD.of_json(Fmap.findnamerq.param)withNot_found->matchdefaultwith|None->failure_missingrq.paramname|Somev->vletparam_opt(typeab)(s:(unit,b)signature)~name~descr(input:ainput):aoptionparam=letmoduleD=(valinput)inletfd=Package.{fd_name=name;fd_type=JoptionD.jtype;fd_descr=descr;}ins.input<-Pfields(fd::fds_inputs);funrq->trySome(D.of_json(Fmap.findnamerq.param))withNot_found->None(* -------------------------------------------------------------------------- *)(* --- Named Output Parameters Definitions --- *)(* -------------------------------------------------------------------------- *)(* current output fields *)letfds_outputs:fieldInfolist=ifs.definedthenraise(Invalid_argument"Server.Request: already published");matchs.outputwith|Rdata_->raise(Invalid_argument"Server.Request: request has not named input");|Rnone->[]|Rfieldsfds->fdsletresult(typeab)(s:(a,unit)signature)~name~descr?default(output:boutput):bresult=letmoduleD=(valoutput)inletfd=Package.{fd_name=name;fd_type=D.jtype;fd_descr=descr;}ins.output<-Rfields(fd::fds_outputs);beginmatchdefaultwith|None->s.required<-name::s.required|Somev->s.defaults<-Fmap.addname(D.to_jsonv)s.defaultsend;funrqv->rq.result<-Fmap.addname(D.to_jsonv)rq.resultletresult_opt(typeab)(s:(a,unit)signature)~name~descr(output:boutput):boptionresult=letmoduleD=(valoutput)inletfd=Package.{fd_name=name;fd_type=JoptionD.jtype;fd_descr=descr;}ins.output<-Rfields(fd::fds_outputs);funrqopt->matchoptwithNone->()|Somev->rq.result<-Fmap.addname(D.to_jsonv)rq.result(* -------------------------------------------------------------------------- *)(* --- Opened Signature Definition --- *)(* -------------------------------------------------------------------------- *)letsignature?input?output()=letinput=matchinputwithNone->Pnone|Somed->Pdatadinletoutput=matchoutputwithNone->Rnone|Somed->Rdatadin{defaults=Fmap.empty;required=[];input;output;defined=false;}(* -------------------------------------------------------------------------- *)(* --- Opened Signature Process --- *)(* -------------------------------------------------------------------------- *)(* json input processing *)letmk_input(typea)namedefaults(input:arq_input):(rq->json->a)=matchinputwith|Pnone->Senv.fatal"No input defined for request '%s'"name|Pdatad->letmoduleD=(vald)inbeginfunrqjs->rq.result<-defaults;tryD.of_jsonjswithJutil.Type_error(msg,js)->Data.failure_from_type_errormsgjsend|Pfields_->beginfunrqjs->tryrq.param<-fmap_of_jsonrq.paramjswithJutil.Type_error(msg,js)->Data.failure_from_type_errormsgjsend(* json output processing *)letmk_output(typeb)namerequired(output:brq_output):(rq->b->json)=matchoutputwith|Rnone->Senv.fatal"No output defined for request '%s'"name|Rdatad->letmoduleD=(vald)in(fun_rqv->D.to_jsonv)|Rfields_->(funrq()->List.iter(check_requiredrq.result)required;fmap_to_jsonrq.result)letregister_sig(typeab)~package~kind~name~descr?(signals=[])(s:(a,b)signature)(process:rq->a->b)=ifs.definedthenSenv.fatal"Request '%s' is defined twice"name;letinput=mk_inputnames.defaultss.inputinletoutput=mk_outputnames.requireds.outputinletprocessorjs=letrq={param=Fmap.empty;result=Fmap.empty}injs|>inputrq|>processrq|>outputrqinletrequest=D_request{rq_kind=kind;rq_input=rq_inputs.input;rq_output=rq_outputs.output;rq_signals=List.mapMain.signal_namesignals;}inletid=declare_id~package~name~descrrequestinMain.registerkind(name_of_identid)processor;s.defined<-true(* -------------------------------------------------------------------------- *)(* --- Request Registration --- *)(* -------------------------------------------------------------------------- *)letregister~package~kind~name~descr?signals~input~outputprocess=register_sig~package~kind~name~descr?signals(signature~input~output())(fun_rqv->processv)letdictionary(typea)~package~name~descr(d:aData.Enum.dictionary)=letopenDatainletdata=Enum.publish~package~name~descrdinletdescr=Markdown.plain"Registered tags for the above type."inletname=name^"Tags"inregister~kind:`GET~package~name~descr~input:(moduleJunit)~output:(moduleJlist(Tag))(fun()->Enum.tagsd);data(* -------------------------------------------------------------------------- *)