package eliom
Advanced client/server Web and mobile framework
Install
Dune Dependency
Authors
Maintainers
Sources
11.0.1.tar.gz
md5=3aeeca5f734f8e932b5a00fbfd43bd26
sha512=d92948949c81fe5b84f7d262b72653175d4f69574cbb4f85433f3a40df436e9e78b3f024ebcd98cb0e1c8ec45af0e3f9cd1153187549883f4ddfd32feeee3176
doc/src/eliom.server/eliom_notif.ml.html
Source file eliom_notif.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
# 1 "src/lib/eliom_notif.server.ml" open Lwt (* We use a hashtable associating resourceid to a weak set of (userid option, notif_ev) corresponding to each tab that want to get updates of this box. We keep a strong reference on these data in process state. *) module type S = sig type identity type key type server_notif type client_notif val init : unit -> unit Lwt.t val deinit : unit -> unit val listen : key -> unit val unlisten : key -> unit module Ext : sig val unlisten : ?sitedata:Eliom_common.sitedata -> ([< `Client_process], [< `Data]) Eliom_state.Ext.state -> key -> unit end val notify : ?notfor:[`Me | `Id of identity] -> key -> server_notif -> unit val client_ev : unit -> (key * client_notif) Eliom_react.Down.t val clean : unit -> unit end module type ARG = sig type identity type key type server_notif type client_notif val prepare : identity -> server_notif -> client_notif option Lwt.t val equal_key : key -> key -> bool val equal_identity : identity -> identity -> bool val get_identity : unit -> identity Lwt.t val max_resource : int val max_identity_per_resource : int end module Make (A : ARG) : S with type identity = A.identity and type key = A.key and type server_notif = A.server_notif and type client_notif = A.client_notif = struct type key = A.key type identity = A.identity type server_notif = A.server_notif type client_notif = A.client_notif type notification_data = A.key * A.client_notif type notification_react = notification_data Eliom_react.Down.t * (?step:React.step -> notification_data -> unit) module Notif_hashtbl = Hashtbl.Make (struct type t = A.key let equal = A.equal_key let hash = Hashtbl.hash end) module Weak_tbl = Weak.Make (struct type t = (A.identity * notification_react) option let equal a b = match a, b with | None, None -> true | Some (a, b), Some (c, d) -> A.equal_identity a c && b == d | _ -> false let hash = Hashtbl.hash end) module I = struct let tbl = Notif_hashtbl.create A.max_resource let remove_if_empty wt key = if Weak_tbl.count wt = 0 then Notif_hashtbl.remove tbl key let remove v key = try let wt = Notif_hashtbl.find tbl key in Weak_tbl.remove wt v; remove_if_empty wt key with Not_found -> () let add v key = let wt = try Notif_hashtbl.find tbl key with Not_found -> let wt = Weak_tbl.create A.max_identity_per_resource in Notif_hashtbl.add tbl key wt; wt in if not (Weak_tbl.mem wt v) then Weak_tbl.add wt v let iter = let iter (f : Weak_tbl.data -> unit Lwt.t) wt : unit = Weak_tbl.iter (fun data -> Lwt.async (fun () -> f data)) wt in fun f key -> try let wt = Notif_hashtbl.find tbl key in let g data = match data with | None -> Weak_tbl.remove wt data; remove_if_empty wt key; Lwt.return_unit | Some v -> f v in iter g wt with Not_found -> () end let identity_r : (A.identity * notification_react) option Eliom_reference.Volatile.eref = Eliom_reference.Volatile.eref ~scope:Eliom_common.default_process_scope None (* notif_e consists in a server side react event, its client side counterpart, and the server side function to trigger it. *) let notif_e : notification_react Eliom_reference.Volatile.eref = Eliom_reference.Volatile.eref_from_fun ~scope:Eliom_common.default_process_scope (fun () -> let e, send_e = React.E.create () in let client_ev = Eliom_react.Down.of_react (*VVV If we add throttling, some events may be lost even if buffer size is not 1 :O *) ~size:100 (*VVV ? *) ~scope:Eliom_common.default_process_scope e in client_ev, send_e) let set_identity identity = (* For each tab connected to the app, we keep a pointer to (identity, notif_ev) option in process state, because the table resourceid -> (identity, notif_ev) option is weak. *) let notif_e = Eliom_reference.Volatile.get notif_e in Eliom_reference.Volatile.set identity_r (Some (identity, notif_e)) let set_current_identity () = A.get_identity () >>= fun identity -> set_identity identity; Lwt.return_unit let init : unit -> unit Lwt.t = fun () -> set_current_identity () let deinit () = Eliom_reference.Volatile.set identity_r None let listen (key : A.key) = let identity = Eliom_reference.Volatile.get identity_r in I.add identity key let unlisten (id : A.key) = let identity = Eliom_reference.Volatile.get identity_r in I.remove identity id module Ext = struct let unlisten ?sitedata:_ state (key : A.key) = let uc = Eliom_reference.Volatile.Ext.get state identity_r in I.remove uc key end let notify ?notfor key content = let f (identity, ((_, send_e) as notif)) = let blocked = match notfor with | Some `Me -> (*TODO: fails outside of a request*) let notif_e = Eliom_reference.Volatile.get notif_e in notif == notif_e | Some (`Id id) -> identity = id | None -> false in if blocked then Lwt.return_unit else A.prepare identity content >>= fun content -> match content with | Some content -> send_e (key, content); Lwt.return_unit | None -> Lwt.return_unit in (* on all tabs listening on this resource *) I.iter f key let client_ev () = let ev, _ = Eliom_reference.Volatile.get notif_e in ev let clean () = let f key weak_tbl = if Weak_tbl.count weak_tbl = 0 then Notif_hashtbl.remove I.tbl key in Notif_hashtbl.iter f I.tbl end module type ARG_SIMPLE = sig type identity type key type notification val get_identity : unit -> identity Lwt.t end module Make_Simple (A : ARG_SIMPLE) = Make (struct type identity = A.identity type key = A.key type server_notif = A.notification type client_notif = A.notification let prepare _ n = Lwt.return_some n let equal_key = ( = ) let equal_identity = ( = ) let get_identity = A.get_identity let max_resource = 1000 let max_identity_per_resource = 10 end)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>