Source file eliom_reference.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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# 1 "src/lib/eliom_reference.server.ml"
(** {2 Eliom references} *)
open Eliom_state
let ( >>= ) = Lwt.bind
module Ocsipersist = struct
include Eliom_common.Ocsipersist.Store
include Eliom_common.Ocsipersist.Polymorphic
end
let pers_ref_store = Ocsipersist.open_store "eliom__persistent_refs"
type 'a eref_kind =
| Req of 'a Polytables.key
| Sit of 'a Polytables.key
| Ref of 'a lazy_t ref
| Vol of 'a volatile_table Lazy.t
| Ocsiper of 'a option Ocsipersist.t Lwt.t
| Ocsiper_sit of 'a Ocsipersist.table Lwt.t
| Per of 'a persistent_table Lwt.t
type volatile = [`Volatile]
type persistent = [`Persistent]
type ('a, 'storage) eref' = (unit -> 'a) * bool * 'a eref_kind
type 'a eref = ('a, [volatile | persistent]) eref'
exception Eref_not_initialized
module Volatile = struct
type 'a eref = ('a, volatile) eref'
let eref_from_fun_ ~ext ~scope ?secure f : 'a eref =
( f
, ext
, match scope with
| `Request -> Req (Polytables.make_key ())
| `Global -> Ref (ref (Lazy.from_fun f))
| `Site -> Sit (Polytables.make_key ())
| #Eliom_common.user_scope as scope ->
Vol (lazy (create_volatile_table ~scope ?secure ())) )
let eref_from_fun ~scope ?secure f : 'a eref =
eref_from_fun_ ~ext:false ~scope ?secure f
let eref ~scope ?secure v =
eref_from_fun_ ~ext:true ~scope ?secure (fun () -> v)
let get ((f, _, table) : _ eref) =
match table with
| Req key -> (
let table = Eliom_request_info.get_request_cache () in
try Polytables.get ~table ~key
with Not_found ->
let value = f () in
Polytables.set ~table ~key ~value;
value)
| Sit key -> (
let table = Eliom_common.((get_site_data ()).site_value_table) in
try Polytables.get ~table ~key
with Not_found ->
let value = f () in
Polytables.set ~table ~key ~value;
value)
| Vol t -> (
match get_volatile_data ~table:(Lazy.force t) () with
| Data d -> d
| _ ->
let value = f () in
set_volatile_data ~table:(Lazy.force t) value;
value)
| Ref r -> Lazy.force !r
| _ -> assert false
let set ((_, _, table) : _ eref) value =
match table with
| Req key ->
let table = Eliom_request_info.get_request_cache () in
Polytables.set ~table ~key ~value
| Sit key ->
let table = Eliom_common.((get_site_data ()).site_value_table) in
Polytables.set ~table ~key ~value
| Vol t -> set_volatile_data ~table:(Lazy.force t) value
| Ref r -> r := Lazy.from_val value
| _ -> assert false
let modify eref f = set eref (f (get eref))
let unset ((f, _, table) : _ eref) =
match table with
| Req key ->
let table = Eliom_request_info.get_request_cache () in
Polytables.remove ~table ~key
| Sit key ->
let table = Eliom_common.((get_site_data ()).site_value_table) in
Polytables.remove ~table ~key
| Vol t -> remove_volatile_data ~table:(Lazy.force t) ()
| Ref r -> r := Lazy.from_fun f
| _ -> assert false
module Ext = struct
let get state (f, ext, table) =
match table with
| Vol t -> (
try
Eliom_state.Ext.Low_level.get_volatile_data ~state
~table:(Lazy.force t)
with Not_found ->
if ext
then (
let value = f () in
Eliom_state.Ext.Low_level.set_volatile_data ~state
~table:(Lazy.force t) value;
value)
else
raise Eref_not_initialized)
| _ -> failwith "wrong eref for this function"
let set state (_, _, table) value =
match table with
| Vol t ->
Eliom_state.Ext.Low_level.set_volatile_data ~state
~table:(Lazy.force t) value
| _ -> failwith "wrong eref for this function"
let modify state eref f = set state eref (f (get state eref))
let unset state ((_, _, table) : _ eref) =
match table with
| Vol t ->
Eliom_state.Ext.Low_level.remove_volatile_data ~state
~table:(Lazy.force t)
| _ -> failwith "wrong eref for this function"
end
end
let eref_from_fun_ ~ext ~scope ?secure ?persistent f : 'a eref =
match (scope : [< Eliom_common.all_scope]) with
| `Request -> (Volatile.eref_from_fun_ ~ext ~scope ?secure f :> _ eref)
| `Global -> (
match persistent with
| None -> (Volatile.eref_from_fun_ ~ext ~scope ?secure f :> _ eref)
| Some name ->
( f
, ext
, Ocsiper
( pers_ref_store >>= fun store ->
Ocsipersist.make_persistent ~store ~name ~default:None ) ))
| `Site -> (
match persistent with
| None -> (Volatile.eref_from_fun_ ~ext ~scope ?secure f :> _ eref)
| Some name ->
f, ext, Ocsiper_sit (Ocsipersist.open_table name))
| #Eliom_common.user_scope as scope -> (
match persistent with
| None -> (Volatile.eref_from_fun_ ~ext ~scope ?secure f :> _ eref)
| Some name -> f, ext, Per (create_persistent_table ~scope ?secure name))
let eref_from_fun ~scope ?secure ?persistent f : 'a eref =
eref_from_fun_ ~ext:false ~scope ?secure ?persistent f
let eref ~scope ?secure ?persistent v =
eref_from_fun_ ~ext:true ~scope ?secure ?persistent (fun () -> v)
let get_site_id () =
let sd = Eliom_common.get_site_data () in
sd.Eliom_common.config_info.Ocsigen_extensions.default_hostname ^ ":"
^ sd.Eliom_common.site_dir_string
let get ((f, _, table) as eref) =
match table with
| Per t -> (
t >>= fun t ->
get_persistent_data ~table:t () >>= function
| Data d -> Lwt.return d
| _ ->
let value = f () in
set_persistent_data ~table:t value >>= fun () -> Lwt.return value)
| Ocsiper r -> (
r >>= fun r ->
Ocsipersist.get r >>= function
| Some v -> Lwt.return v
| None ->
let value = f () in
Ocsipersist.set r (Some value) >>= fun () -> Lwt.return value)
| Ocsiper_sit t -> (
t >>= fun t ->
let site_id = get_site_id () in
try%lwt Ocsipersist.find t site_id
with Not_found ->
let value = f () in
Ocsipersist.add t site_id value >>= fun () -> Lwt.return value)
| _ -> Lwt.return (Volatile.get eref)
let set ((_, _, table) as eref) value =
match table with
| Per t -> t >>= fun t -> set_persistent_data ~table:t value
| Ocsiper r -> r >>= fun r -> Ocsipersist.set r (Some value)
| Ocsiper_sit t -> t >>= fun t -> Ocsipersist.add t (get_site_id ()) value
| _ -> Lwt.return (Volatile.set eref value)
let modify eref f = get eref >>= fun x -> set eref (f x)
let unset ((_, _, table) as eref) =
match table with
| Per t -> t >>= fun t -> remove_persistent_data ~table:t ()
| Ocsiper r -> r >>= fun r -> Ocsipersist.set r None
| Ocsiper_sit t -> t >>= fun t -> Ocsipersist.remove t (get_site_id ())
| _ -> Lwt.return (Volatile.unset eref)
module Ext = struct
let get state ((f, ext, table) as r) =
let state = Eliom_state.Ext.untype_state state in
match table with
| Vol _ -> Lwt.return (Volatile.Ext.get state r)
| Per t ->
t >>= fun t ->
Lwt.catch
(fun () ->
Eliom_state.Ext.Low_level.get_persistent_data ~state ~table:t)
(function
| Not_found ->
if ext
then
let value = f () in
Eliom_state.Ext.Low_level.set_persistent_data ~state ~table:t
value
>>= fun () -> Lwt.return value
else Lwt.fail Eref_not_initialized
| e -> Lwt.fail e)
| _ -> failwith "wrong eref for this function"
let set state ((_, _, table) as r) value =
let state = Eliom_state.Ext.untype_state state in
match table with
| Vol _ -> Lwt.return (Volatile.Ext.set state r value)
| Per t ->
t >>= fun t ->
Eliom_state.Ext.Low_level.set_persistent_data ~state ~table:t value
| _ -> Lwt.fail (Failure "wrong eref for this function")
let modify state eref f = get state eref >>= fun v -> set state eref (f v)
let unset state ((_, _, table) as r) =
let state = Eliom_state.Ext.untype_state state in
match table with
| Vol _ -> Lwt.return (Volatile.Ext.unset state r)
| Per t ->
t >>= fun t ->
Eliom_state.Ext.Low_level.remove_persistent_data ~state ~table:t
| _ -> failwith "wrong eref for this function"
end