123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242# 1 "src/lib/eliom_react.server.ml"(* Ocsigen
* http://www.ocsigen.org
* Copyright (C) 2010
* Raphaël Proust
*
* 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.
*)(* Module for event wrapping and related functions *)openLwt_reactmoduleDown=structtype'astateful={throttling:floatoption;scope:Eliom_common.client_process_scopeoption;react:'aE.t;name:stringoption;size:intoption}type'astateless='aEliom_comet.Channel.ttype'at'=Statefulof'astateful|Statelessof'astatelesstype'at={t:'at';react_down_mark:'atEliom_common.wrapper}[@@warning"-69"]letwrap_stateful{throttling=t;scope;react=e;name;size}=letee=Lwt.with_valueEliom_common.sp_keyNone@@fun()->matchtwith|None->e|Somet->E.limit(fun()->Lwt_unix.sleept)einletchannel=Eliom_comet.Channel.create_from_events?scope?name?sizeeeinchannel,Eliom_common.make_unwrapperEliom_common.react_down_unwrap_idletwrap_statelesschannel=channel,Eliom_common.make_unwrapperEliom_common.react_down_unwrap_idletinternal_wrap=function|{t=Statefulv;_}->wrap_statefulv|{t=Statelessv;_}->wrap_statelessvletreact_down_mark()=Eliom_common.make_wrapperinternal_wrapletstateful?scope?throttling?name?size(e:'aE.t)=Stateful{throttling;scope;react=e;name;size}letstateless?throttling?name?size(e:'aE.t)=letee=matchthrottlingwith|None->e|Somet->E.limit(fun()->Lwt_unix.sleept)einStateless(Eliom_comet.Channel.create_from_events~scope:`Site?name?sizeee)letof_react?scope?throttling?name?size(e:'aE.t)=lett=matchscopewith|Some`Site->stateless?throttling?name?sizee|None->stateful?throttling?name?sizee|Some(`Client_process_asscope)->stateful~scope?throttling?name?sizeein{t;react_down_mark=react_down_mark()}endmoduleUp=structtype'at={event:'aE.t;service:(unit,'a,Eliom_service.post,Eliom_service.non_att,Eliom_service.co,Eliom_service.non_ext,Eliom_service.reg,[`WithoutSuffix],unit,[`Oneof'aEliom_parameter.ocaml]Eliom_parameter.param_name,Eliom_registration.Action.return)Eliom_service.t;wrapper:'atEliom_common.wrapper}[@@warning"-69"]letto_reactt=t.eventletinternal_wrapt=t.service,Eliom_common.make_unwrapperEliom_common.react_up_unwrap_idletup_event_wrapper()=Eliom_common.make_wrapperinternal_wrap(* An event is created along with a service responsible for it's occurrences.
* function takes a param_type *)letcreate?scope?namepost_params=lete,push=E.create()inletsp=Eliom_common.get_sp_option()inletscope=matchsp,scopewith|_,Somel->l|None,_->`Site|_->(Eliom_common.comet_client_process_scope:>Eliom_common.scope)inlete_writer=Eliom_service.create?name~meth:(Eliom_service.Post(Eliom_parameter.unit,post_params))~path:Eliom_service.No_path()inEliom_registration.Action.register~scope~options:`NoReload~service:e_writer(fun()value->pushvalue;Lwt.return_unit);{event=e;service=e_writer;wrapper=up_event_wrapper()}endmoduleS=structmoduleDown=structtype'astateful={throttling:floatoption;scope:Eliom_common.client_process_scopeoption;signal:'aS.t;name:stringoption}[@@warning"-69"]type'astateless={channel:'aEliom_comet.Channel.t;stream:'aLwt_stream.t;(* avoid garbage collection *)sl_signal:'aS.t}[@@warning"-69"]type'at'=Statefulof'astateful|Statelessof'astatelesstype'at={t:'at';signal_down_mark:'atEliom_common.wrapper}[@@warning"-69"]type'astore={s:unitS.tLazy.t;(* to avoid signal GC *)mutablevalue:'a;mutableread:bool;condition:unitLwt_condition.t}letmake_storesignal=letrecstore={s=s';value=S.valuesignal;read=false;condition=Lwt_condition.create()}ands'=lazy(S.map(funv->store.read<-false;store.value<-v;Lwt_condition.broadcaststore.condition();())signal)inignore(Lazy.forcestore.s);storeletread_storestore=letrecaux()=ifstore.readthenlet%lwt()=Lwt_condition.waitstore.conditioninaux()else(store.read<-true;Lwt.return_somestore.value)infun()->Lwt.with_valueEliom_common.sp_keyNone@@auxletwrap_stateful{throttling=t;signal=s;name;_}=lets:'aS.t=matchtwith|None->s|Somet->S.limit(fun()->Lwt_unix.sleept)sinletstore=make_storesinletstream=Lwt_stream.from(read_storestore)inletchannel=Eliom_comet.Channel.create_unlimited?namestreaminletvalue:'a=S.valuesin(channel,value,Eliom_common.make_unwrapperEliom_common.signal_down_unwrap_id)letwrap_stateless{sl_signal=s;channel;_}=letvalue:'a=S.valuesin(channel,value,Eliom_common.make_unwrapperEliom_common.signal_down_unwrap_id)letinternal_wrap=function|{t=Statefulv;_}->wrap_statefulv|{t=Statelessv;_}->wrap_statelessvletsignal_down_mark()=Eliom_common.make_wrapperinternal_wrapletstateful?scope?throttling?name(s:'aS.t)=Stateful{throttling;scope;signal=s;name}letstateless?throttling?name(s:'aS.t)=lets=matchthrottlingwith|None->s|Somet->S.limit(fun()->Lwt_unix.sleept)sinlete=S.changessinletstream=E.to_streameinStateless{channel=Eliom_comet.Channel.create_newest?namestream;stream;sl_signal=s}letof_react?scope?throttling?name(s:'aS.t)=lett=matchscopewith|Some`Site->stateless?throttling?names|None->stateful?throttling?names|Some(`Client_process_asscope)->stateful~scope?throttling?namesin{t;signal_down_mark=signal_down_mark()}endend