ocaml http/1, http/2 and websocket client and server library
1type event = {
2 event_type : string option;
3 data : string;
4 id : string option;
5 retry : int option;
6}
7
8let event data = { event_type = None; data; id = None; retry = None }
9
10let event_typed ~event_type data =
11 { event_type = Some event_type; data; id = None; retry = None }
12
13let make ?event_type ?id ?retry data = { event_type; data; id; retry }
14
15let format ev =
16 let buf = Buffer.create 64 in
17 let add_kv k v =
18 Buffer.add_string buf k;
19 Buffer.add_string buf ": ";
20 Buffer.add_string buf v;
21 Buffer.add_char buf '\n'
22 in
23 Option.iter (fun t -> add_kv "event" t) ev.event_type;
24 Option.iter (fun i -> add_kv "id" i) ev.id;
25 Option.iter
26 (fun r ->
27 Buffer.add_string buf "retry: ";
28 Buf.int buf r;
29 Buffer.add_char buf '\n')
30 ev.retry;
31 String.split_on_char '\n' ev.data
32 |> List.iter (fun line ->
33 Buffer.add_string buf "data: ";
34 Buffer.add_string buf line;
35 Buffer.add_char buf '\n');
36 Buffer.add_char buf '\n';
37 Buffer.contents buf
38
39let headers =
40 [
41 ("content-type", "text/event-stream");
42 ("cache-control", "no-cache");
43 ("connection", "keep-alive");
44 ("x-accel-buffering", "no");
45 ]
46
47let respond generator =
48 let next () =
49 match generator () with
50 | None -> None
51 | Some ev -> Some (Cstruct.of_string (format ev))
52 in
53 Response.stream ~headers next
54
55let respond_with_stream (events : event Eio.Stream.t) =
56 let next () =
57 try
58 let ev = Eio.Stream.take events in
59 Some (Cstruct.of_string (format ev))
60 with _ -> None
61 in
62 Response.stream ~headers next
63
64let respond_raw generator =
65 let next () =
66 match generator () with
67 | None -> None
68 | Some s -> Some (Cstruct.of_string s)
69 in
70 Response.stream ~headers next
71
72let respond_raw_stream (strings : string Eio.Stream.t) =
73 let next () =
74 try
75 let s = Eio.Stream.take strings in
76 Some (Cstruct.of_string s)
77 with _ -> None
78 in
79 Response.stream ~headers next