Document example/w-server-sent-events

This commit is contained in:
Anton Bachin 2021-04-08 18:25:08 +03:00
parent f997718427
commit 12b7ba714b
3 changed files with 75 additions and 26 deletions

View File

@ -77,8 +77,8 @@ if something is missing!
- [**`w-query`**](w-query#files)  —  reading URL query
parameters.
- [**`w-server-sent-events`**](w-server-sent-events#files)  — 
the server side of JavaScript
[`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
[`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource),
an older alternative to WebSockets.
- [**`w-site-prefix`**](w-site-prefix#files)  —  a Web app
running not at `/`.
- [**`w-template-stream`**](w-template-stream#files)  —  writing

View File

@ -2,11 +2,55 @@
<br>
**Next steps:**
In [server-sent
events](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), a client
sends a request to a server, to which the server responds with header
`Content-Type: text/event-stream`, and gradually streams events.
This example sets up a message-generating loop, `message_loop`, to simulate
messages sent by other clients:
```ocaml
let rec message_loop () =
let%lwt () = Lwt_unix.sleep (Random.float 2.) in
incr last_message;
let message = string_of_int !last_message in
Dream.log "Generated message %s" message;
server_state := message::!server_state;
!notify ();
message_loop ()
```
<br>
[Up to the example index](../#readme)
When a client connects to the example's server-sent events endpoint at
[http://localhost:8080/push](http://localhost:8080/push), the server first sends
any messages that have already accumulated, and then gradually
[streams](https://aantron.github.io/dream/#streaming) more messages as they are
created.
You can see this in action either by visiting the endpoint directly, or as
interpreted by the page at [http://localhost:8080](http://localhost:8080), which
uses the browser
[`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
interface to server-sent events.
<br>
**See also:**
- [**`k-websocket`**](../k-websocket#files) for WebSockets, which largely
supersede server-sent events.
- [**`w-template-stream`**](../w-template-stream#files) for another example of
“real-time” streaming with
[`Dream.flush`](https://aantron.github.io/dream/#val-flush).
<br>
[Up to the example index](../#examples)
<!-- TODO OWASP link; injection general link. -->
<!-- TODO Link to template syntax reference. -->

View File

@ -28,13 +28,40 @@ let last_message =
let rec message_loop () =
let%lwt () = Lwt_unix.sleep (Random.float 2.) in
incr last_message;
let message = string_of_int !last_message in
Dream.log "Generated message %s" message;
server_state := message::!server_state;
!notify ();
message_loop ()
let rec forward_messages response =
let%lwt messages =
match !server_state with
| [] ->
let on_message, notify_message = Lwt.wait () in
notify := Lwt.wakeup_later notify_message;
let%lwt () = on_message in
notify := ignore;
Lwt.return !server_state
| messages ->
Lwt.return messages
in
server_state := [];
messages
|> List.rev
|> List.map (Printf.sprintf "data: %s\n\n")
|> String.concat ""
|> fun text ->
let%lwt () = Dream.write text response in
let%lwt () = Dream.flush response in
forward_messages response
let () =
Lwt.async message_loop;
@ -45,28 +72,6 @@ let () =
Dream.get "/" (fun _ -> Dream.respond home);
Dream.get "/push" (fun _ ->
let rec forward_messages response =
let%lwt messages =
match !server_state with
| [] ->
let on_message, notify_message = Lwt.wait () in
notify := Lwt.wakeup_later notify_message;
let%lwt () = on_message in
notify := ignore;
Lwt.return !server_state
| messages ->
Lwt.return messages
in
server_state := [];
messages
|> List.rev
|> List.map (Printf.sprintf "data: %s\n\n")
|> String.concat ""
|> fun text ->
let%lwt () = Dream.write text response in
let%lwt () = Dream.flush response in
forward_messages response
in
Dream.stream
~headers:["Content-Type", "text/event-stream"]
forward_messages);