123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285# 1 "src/lib/eliom_reference.server.ml"(* Ocsigen
* http://www.ocsigen.org
* Copyright (C) 2010 Vincent Balat
*
* This program is free software; 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, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*)(*****************************************************************************)(** {2 Eliom references} *)openEliom_statelet(>>=)=Lwt.bindmoduleOcsipersist=structincludeEliom_common.Ocsipersist.StoreincludeEliom_common.Ocsipersist.Polymorphicendletpers_ref_store=Ocsipersist.open_store"eliom__persistent_refs"type'aeref_kind=|Reqof'aPolytables.key|Sitof'aPolytables.key|Refof'alazy_tref(* Ocaml reference *)|Volof'avolatile_tableLazy.t(* Vol. table (group, session, process) *)|Ocsiperof'aoptionOcsipersist.tLwt.t(* Global persist. table *)|Ocsiper_sitof'aOcsipersist.tableLwt.t(* Persist. table for site *)|Perof'apersistent_tableLwt.t(* Persist. table for group session or process *)typevolatile=[`Volatile]typepersistent=[`Persistent]type('a,'storage)eref'=(unit->'a)*bool*'aeref_kind(* * The function to get the value
* a boolean true means "it is safe to execute the function from an
external context" (for example if it is a constant function - eref created
from a value)
* the kind of reference (scope, persistence)
*)type'aeref=('a,[volatile|persistent])eref'exceptionEref_not_initializedmoduleVolatile=structtype'aeref=('a,volatile)eref'(* TODO With GADTs, drop the [assert false] and [failwith] statements below! *)leteref_from_fun_~ext~scope?securef:'aeref=(f,ext,matchscopewith|`Request->Req(Polytables.make_key())|`Global->Ref(ref(Lazy.from_funf))|`Site->Sit(Polytables.make_key())|#Eliom_common.user_scopeasscope->Vol(lazy(create_volatile_table~scope?secure())))leteref_from_fun~scope?securef:'aeref=eref_from_fun_~ext:false~scope?securefleteref~scope?securev=eref_from_fun_~ext:true~scope?secure(fun()->v)letget((f,_,table):_eref)=matchtablewith|Reqkey->(lettable=Eliom_request_info.get_request_cache()intryPolytables.get~table~keywithNot_found->letvalue=f()inPolytables.set~table~key~value;value)|Sitkey->(lettable=Eliom_common.((get_site_data()).site_value_table)intryPolytables.get~table~keywithNot_found->letvalue=f()inPolytables.set~table~key~value;value)|Volt->(matchget_volatile_data~table:(Lazy.forcet)()with|Datad->d|_->letvalue=f()inset_volatile_data~table:(Lazy.forcet)value;value)|Refr->Lazy.force!r|_->assertfalseletset((_,_,table):_eref)value=matchtablewith|Reqkey->lettable=Eliom_request_info.get_request_cache()inPolytables.set~table~key~value|Sitkey->lettable=Eliom_common.((get_site_data()).site_value_table)inPolytables.set~table~key~value|Volt->set_volatile_data~table:(Lazy.forcet)value|Refr->r:=Lazy.from_valvalue|_->assertfalseletmodifyereff=seteref(f(geteref))letunset((f,_,table):_eref)=matchtablewith|Reqkey->lettable=Eliom_request_info.get_request_cache()inPolytables.remove~table~key|Sitkey->lettable=Eliom_common.((get_site_data()).site_value_table)inPolytables.remove~table~key|Volt->remove_volatile_data~table:(Lazy.forcet)()|Refr->r:=Lazy.from_funf|_->assertfalsemoduleExt=structletgetstate(f,ext,table)=matchtablewith|Volt->(tryEliom_state.Ext.Low_level.get_volatile_data~state~table:(Lazy.forcet)withNot_found->ifextthen(letvalue=f()inEliom_state.Ext.Low_level.set_volatile_data~state~table:(Lazy.forcet)value;value)else(* I don't want to run f in the wrong context -> I fail *)raiseEref_not_initialized)|_->failwith"wrong eref for this function"letsetstate(_,_,table)value=matchtablewith|Volt->Eliom_state.Ext.Low_level.set_volatile_data~state~table:(Lazy.forcet)value|_->failwith"wrong eref for this function"letmodifystateereff=setstateeref(f(getstateeref))letunsetstate((_,_,table):_eref)=matchtablewith|Volt->Eliom_state.Ext.Low_level.remove_volatile_data~state~table:(Lazy.forcet)|_->failwith"wrong eref for this function"endendleteref_from_fun_~ext~scope?secure?persistentf:'aeref=match(scope:[<Eliom_common.all_scope])with|`Request->(Volatile.eref_from_fun_~ext~scope?securef:>_eref)|`Global->(matchpersistentwith|None->(Volatile.eref_from_fun_~ext~scope?securef:>_eref)|Somename->(f,ext,Ocsiper(pers_ref_store>>=funstore->Ocsipersist.make_persistent~store~name~default:None)))|`Site->(matchpersistentwith|None->(Volatile.eref_from_fun_~ext~scope?securef:>_eref)|Somename->(*VVV!!! ??? CHECK! *)f,ext,Ocsiper_sit(Ocsipersist.open_tablename))|#Eliom_common.user_scopeasscope->(matchpersistentwith|None->(Volatile.eref_from_fun_~ext~scope?securef:>_eref)|Somename->f,ext,Per(create_persistent_table~scope?securename))leteref_from_fun~scope?secure?persistentf:'aeref=eref_from_fun_~ext:false~scope?secure?persistentfleteref~scope?secure?persistentv=eref_from_fun_~ext:true~scope?secure?persistent(fun()->v)letget_site_id()=letsd=Eliom_common.get_site_data()in(Eliom_common.get_config_infosd).Ocsigen_extensions.default_hostname^":"^Eliom_common.get_site_dir_stringsdletget((f,_,table)aseref)=matchtablewith|Pert->(t>>=funt->get_persistent_data~table:t()>>=function|Datad->Lwt.returnd|_->letvalue=f()inset_persistent_data~table:tvalue>>=fun()->Lwt.returnvalue)|Ocsiperr->(r>>=funr->Ocsipersist.getr>>=function|Somev->Lwt.returnv|None->letvalue=f()inOcsipersist.setr(Somevalue)>>=fun()->Lwt.returnvalue)|Ocsiper_sitt->(t>>=funt->letsite_id=get_site_id()intry%lwtOcsipersist.findtsite_idwithNot_found->letvalue=f()inOcsipersist.addtsite_idvalue>>=fun()->Lwt.returnvalue)|_->Lwt.return(Volatile.geteref)letset((_,_,table)aseref)value=matchtablewith|Pert->t>>=funt->set_persistent_data~table:tvalue|Ocsiperr->r>>=funr->Ocsipersist.setr(Somevalue)|Ocsiper_sitt->t>>=funt->Ocsipersist.addt(get_site_id())value|_->Lwt.return(Volatile.seterefvalue)letmodifyereff=geteref>>=funx->seteref(fx)letunset((_,_,table)aseref)=matchtablewith|Pert->t>>=funt->remove_persistent_data~table:t()|Ocsiperr->r>>=funr->Ocsipersist.setrNone|Ocsiper_sitt->t>>=funt->Ocsipersist.removet(get_site_id())|_->Lwt.return(Volatile.unseteref)moduleExt=structletgetstate((f,ext,table)asr)=letstate=Eliom_state.Ext.untype_statestateinmatchtablewith|Vol_->Lwt.return(Volatile.Ext.getstater)|Pert->t>>=funt->Lwt.catch(fun()->Eliom_state.Ext.Low_level.get_persistent_data~state~table:t)(function|Not_found->ifext(* We can run the function from another state *)thenletvalue=f()inEliom_state.Ext.Low_level.set_persistent_data~state~table:tvalue>>=fun()->Lwt.returnvalueelseLwt.failEref_not_initialized|e->Lwt.faile)|_->failwith"wrong eref for this function"letsetstate((_,_,table)asr)value=letstate=Eliom_state.Ext.untype_statestateinmatchtablewith|Vol_->Lwt.return(Volatile.Ext.setstatervalue)|Pert->t>>=funt->Eliom_state.Ext.Low_level.set_persistent_data~state~table:tvalue|_->Lwt.fail(Failure"wrong eref for this function")letmodifystateereff=getstateeref>>=funv->setstateeref(fv)letunsetstate((_,_,table)asr)=letstate=Eliom_state.Ext.untype_statestateinmatchtablewith|Vol_->Lwt.return(Volatile.Ext.unsetstater)|Pert->t>>=funt->Eliom_state.Ext.Low_level.remove_persistent_data~state~table:t|_->failwith"wrong eref for this function"end