Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Almost complete port to Eio #254

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6f608d0
Disable openssl for now
talex5 Jan 19, 2022
ef7d7be
Get rid of stuff that doesn't build
talex5 Jan 18, 2022
6c4ed2d
Initial port to Eio
Willenbrink Apr 3, 2023
5c276c5
Use Eio to accept network connections
Willenbrink Apr 3, 2023
5a6cac0
Remove ssl dependency
talex5 Feb 3, 2022
703db62
Update to Eio 0.1
talex5 Feb 3, 2022
88d0b24
Update to Eio 0.2
Willenbrink Apr 3, 2023
942dbfc
Use Eio_unix.sleep in examples
Willenbrink Apr 3, 2023
189929e
Fix most remaining errors
Willenbrink Mar 13, 2023
72896f8
Remove lwt from pure
Willenbrink Apr 2, 2023
9a1cada
Remove Lwt from server/ as far as possible
Willenbrink Apr 2, 2023
c1021d6
Remove lwt from graphql/
Willenbrink Apr 2, 2023
59af592
Remove Lwt from mirage/
Willenbrink Apr 2, 2023
a46bb20
Remove lwt from sql/ as far as possible
Willenbrink Apr 2, 2023
c1e5e91
Remove lwt from http/ as far as possible
Willenbrink Apr 2, 2023
b600bc1
Update dream.mli
Willenbrink Apr 2, 2023
02208cd
Fix examples
Willenbrink Apr 2, 2023
a9cca15
Update dependencies to master
Willenbrink Apr 8, 2023
b30594e
Revert "Disable openssl for now"
Willenbrink Apr 8, 2023
c44b79c
Remove promises from dream.mli
Willenbrink Apr 8, 2023
47a4617
Replace gluten and httpaf lwt variants with eio
Willenbrink Apr 8, 2023
fc7ed99
Expose backlog, remove more lwt from http/
Willenbrink Apr 8, 2023
ceedc70
Disable SSL for the time being
Willenbrink Apr 8, 2023
f9f68d7
Move static files to eio
Willenbrink Apr 8, 2023
64bef1b
Remove lwt async_exception_hook
Willenbrink Apr 9, 2023
d923711
Remove lwt id handling for logging
Willenbrink Apr 9, 2023
8bd26a8
Switch to multipart_form-eio
Willenbrink Apr 9, 2023
531bb37
Switch to mirage_crypto_rng_eio
Willenbrink Apr 9, 2023
b528ea4
Add Random.run to replace Random.initialize
Willenbrink Apr 10, 2023
1f7f9b9
Add mock for g-upload
Willenbrink Apr 10, 2023
334311e
Mock upload gets stuck
Willenbrink Apr 10, 2023
0b53d91
Remove superfluous switch
Willenbrink Apr 12, 2023
4c3c387
Replace await_lwt with run_lwt where applicable
Willenbrink Apr 19, 2023
b98ab65
Incorporate other feedback
Willenbrink Apr 19, 2023
306a49a
Remove loader from static
Willenbrink Apr 19, 2023
83a6137
Fix forgotten example
Willenbrink Apr 19, 2023
b625e72
Revert whitespace changes
Willenbrink Apr 20, 2023
0951517
Merge branch 'master' into eio
aantron Apr 21, 2023
3bb33d7
Remove unnecessary make default target
aantron Apr 19, 2023
8757a12
Sync src/vendor/dune with gluten-eio dune
aantron Apr 21, 2023
df07d35
Merge branch 'master' into eio
aantron Apr 21, 2023
42f54bb
Make message body a promise again
Willenbrink Apr 21, 2023
ad54366
Fix mirage and echo example
Willenbrink Apr 21, 2023
a9634bc
Ignore unused vars
Willenbrink Apr 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions dream-httpaf.opam
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ depends: [
"dune" {>= "2.7.0"} # --instrument-with.
"lwt"
"lwt_ppx" {>= "1.2.2"}
"lwt_ssl"
"ocaml" {>= "4.08.0"}
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.

# Currently vendored.
# "gluten"
Expand Down
1 change: 1 addition & 0 deletions dream-pure.opam
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ depends: [
"ocaml" {>= "4.08.0"}
"ptime" {>= "0.8.1"} # Ptime.weekday.
"uri" {>= "4.2.0"}
"eio" {>= "0.2"}

# Testing, development.
"alcotest" {with-test}
Expand Down
4 changes: 2 additions & 2 deletions dream.opam
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ depends: [
"graphql-lwt"
"lwt"
"lwt_ppx" {>= "1.2.2"}
"lwt_ssl"
"logs" {>= "0.5.0"}
"magic-mime"
"mirage-clock" {>= "3.0.0"} # now_d_ps : unit -> int * int64.
Expand All @@ -73,9 +72,10 @@ depends: [
"multipart_form-lwt"
"ocaml" {>= "4.08.0"}
"ptime" {>= "0.8.1"} # Ptime.v.
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.
"uri" {>= "4.2.0"}
"yojson" # ...
"eio_main" {>= "0.2"}
"lwt_eio" {>= "0.1"}

# Testing, development.
"alcotest" {with-test}
Expand Down
11 changes: 9 additions & 2 deletions example/1-hello/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ This project is so simple that it doesn't even log requests!

```ocaml
let () =
Dream.run (fun _ ->
Dream.html "Good morning, world!")
Eio_main.run (fun env ->
Dream.run env (fun _ ->
Dream.html "Good morning, world!")
)
```

<br>
Expand Down Expand Up @@ -39,6 +41,11 @@ name of the `.ml` file, but with `.ml` changed to `.exe`.

<br>

A Dream server runs in an [Eio](https://github.com/ocaml-multicore/eio) event loop,
which is created by `Eio_main.run`.

<br>

**Next steps:**

- The next example, [**`2-middleware`**](../2-middleware#files), adds a logger
Expand Down
6 changes: 4 additions & 2 deletions example/1-hello/hello.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
let () =
Dream.run (fun _ ->
Dream.html "Good morning, world!")
Eio_main.run (fun env ->
Dream.run env (fun _ ->
Dream.html "Good morning, world!")
)
10 changes: 6 additions & 4 deletions example/2-middleware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ middlewares, the [*logger*](https://aantron.github.io/dream/#val-logger):

```ocaml
let () =
Dream.run
(Dream.logger (fun _ ->
Dream.html "Good morning, world!"))
Eio_main.run (fun env ->
Dream.run env
(Dream.logger (fun _ ->
Dream.html "Good morning, world!")))
```

<br>
Expand All @@ -25,7 +26,8 @@ in this example looks like this:

```ocaml
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ fun _ -> Dream.html "Good morning, world!"
```
Expand Down
3 changes: 2 additions & 1 deletion example/2-middleware/middleware.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ fun _ -> Dream.html "Good morning, world!"
3 changes: 2 additions & 1 deletion example/3-router/router.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.router [

Expand Down
3 changes: 2 additions & 1 deletion example/4-counter/counter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ let count_requests inner_handler request =
inner_handler request

let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ count_requests
@@ Dream.router [
Expand Down
57 changes: 11 additions & 46 deletions example/5-promise/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
# `5-promise`

(note this example is now badly named, as it doesn't use any promises)

<br>

[**`4-counter`**](../4-counter#files) was limited to counting requests *before*
passing them on to the rest of the app. With the promise library
[Lwt](https://github.com/ocsigen/lwt), we can await responses, and do something
*after*. In this example, we separately count requests that were handled
successfully, and those that caused an exception:
passing them on to the rest of the app. We can also await responses, and do
something *after*. In this example, we separately count requests that were
handled successfully, and those that caused an exception:

```ocaml
let successful = ref 0
let failed = ref 0

let count_requests inner_handler request =
try%lwt
let%lwt response = inner_handler request in
try
let response = inner_handler request in
successful := !successful + 1;
Lwt.return response

response
with exn ->
failed := !failed + 1;
raise exn

let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ count_requests
@@ Dream.router [
Expand All @@ -48,49 +49,13 @@ Try it in the [playground](http://dream.as/5-promise).

<br>

As you can see, the
[core constructs](https://ocsigen.org/lwt/latest/api/Ppx_lwt) of Lwt are:

- `let%lwt` to await the result of a promise.
- `try%lwt` to catch both exceptions and rejections. Lwt promises can only be
rejected with exceptions, of OCaml type `exn`.
- `Lwt.return` to resolve a promise.

Besides these, Lwt has a lot of [convenience
functions](https://ocsigen.org/lwt/latest/api/Lwt), and an [asychronous
I/O library](https://ocsigen.org/lwt/latest/api/Lwt_unix).
As you can see, we use `try` to catch both exceptions and rejections.

<!-- TODO Link to read_file and write_file helpers. -->
<!-- TODO Link to Lwt_unix, Lwt_io, Lwt. -->

<br>

To use `let%lwt`, we need to modify our
[`dune`](https://github.com/aantron/dream/blob/master/example/5-promise/dune)
file a bit to include `lwt_ppx`:

<pre><code>(executable
(name promise)
(libraries dream)
<b>(preprocess (pps lwt_ppx)))</b>
</code></pre>

There are other ways to write *await* and *catch* in Lwt that don't require
`lwt_ppx`, but `lwt_ppx` is presently the best for preserving nice stack traces.
For example, `let%lwt` is equivalent to...

- [`Lwt.bind`](https://github.com/ocsigen/lwt/blob/c5f895e35a38df2d06f19fd23bf553129b9e95b3/src/core/lwt.mli#L475),
which is almost never used directly.
- [`>>=`](https://github.com/ocsigen/lwt/blob/c5f895e35a38df2d06f19fd23bf553129b9e95b3/src/core/lwt.mli#L1395)
from module `Lwt.Infix`.
- [`let*`](https://github.com/ocsigen/lwt/blob/c5f895e35a38df2d06f19fd23bf553129b9e95b3/src/core/lwt.mli#L1511)
from module `Lwt.Syntax`, which is showcased in Lwt's
[README](https://github.com/ocsigen/lwt#readme).

We will stick to `let%lwt` in the examples and keep things tidy.

<br>

**Next steps:**

- [**`6-echo`**](../6-echo#files) uses Dream and Lwt to read a request body.
Expand Down
3 changes: 1 addition & 2 deletions example/5-promise/dune
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(executable
(name promise)
(libraries dream)
(preprocess (pps lwt_ppx)))
(libraries dream))

(data_only_dirs _esy esy.lock lib node_modules)
10 changes: 5 additions & 5 deletions example/5-promise/promise.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ let successful = ref 0
let failed = ref 0

let count_requests inner_handler request =
try%lwt
let%lwt response = inner_handler request in
try
let response = inner_handler request in
successful := !successful + 1;
Lwt.return response

response
with exn ->
failed := !failed + 1;
raise exn

let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ count_requests
@@ Dream.router [
Expand Down
3 changes: 1 addition & 2 deletions example/6-echo/dune
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(executable
(name echo)
(libraries dream)
(preprocess (pps lwt_ppx)))
(libraries dream))

(data_only_dirs _esy esy.lock lib node_modules)
7 changes: 4 additions & 3 deletions example/6-echo/echo.ml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.router [

Dream.post "/echo" (fun request ->
let%lwt body = Dream.body request in
let body = Dream.body request in
Dream.respond
~headers:["Content-Type", "application/octet-stream"]
body);
(Eio.Promise.await_exn body));

]
3 changes: 1 addition & 2 deletions example/7-template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ file to run the template preprocessor:

<pre><code>(executable
(name template)
(libraries dream)
(preprocess (pps lwt_ppx)))
(libraries dream))

<b>(rule
(targets template.ml)
Expand Down
3 changes: 2 additions & 1 deletion example/7-template/template.eml.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ let render param =
</html>

let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.router [

Expand Down
3 changes: 2 additions & 1 deletion example/8-debug/debug.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
let () =
Dream.run ~error_handler:Dream.debug_error_handler
Eio_main.run @@ fun env ->
Dream.run ~error_handler:Dream.debug_error_handler env
@@ Dream.logger
@@ Dream.router [

Expand Down
5 changes: 3 additions & 2 deletions example/9-error/error.eml.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ let my_error_template _error debug_info suggested_response =
</body>
</html>
end;
Lwt.return suggested_response
suggested_response

let () =
Dream.run ~error_handler:(Dream.error_template my_error_template)
Eio_main.run @@ fun env ->
Dream.run ~error_handler:(Dream.error_template my_error_template) env
@@ Dream.logger
@@ Dream.not_found
3 changes: 2 additions & 1 deletion example/a-log/log.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.router [

Expand Down
3 changes: 1 addition & 2 deletions example/b-session/dune
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(executable
(name session)
(libraries dream)
(preprocess (pps lwt_ppx)))
(libraries dream))

(data_only_dirs _esy esy.lock lib node_modules)
7 changes: 4 additions & 3 deletions example/b-session/session.ml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.memory_sessions
@@ fun request ->

match Dream.session_field request "user" with
| None ->
let%lwt () = Dream.invalidate_session request in
let%lwt () = Dream.set_session_field request "user" "alice" in
Dream.invalidate_session request;
Dream.set_session_field request "user" "alice";
Dream.html "You weren't logged in; but now you are!"

| Some username ->
Expand Down
5 changes: 3 additions & 2 deletions example/c-cookie/cookie.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.set_secret "foo"
@@ Dream.logger
@@ fun request ->
Expand All @@ -13,4 +14,4 @@ let () =
let response = Dream.response "Set language preference; come again!" in
Dream.add_header response "Content-Type" Dream.text_html;
Dream.set_cookie response request "ui.language" "ut-OP";
Lwt.return response
response
3 changes: 1 addition & 2 deletions example/d-form/dune
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(executable
(name form)
(libraries dream)
(preprocess (pps lwt_ppx)))
(libraries dream))

(rule
(targets form.ml)
Expand Down
5 changes: 3 additions & 2 deletions example/d-form/form.eml.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ let show_form ?message request =
</html>

let () =
Dream.run
Eio_main.run @@ fun env ->
Dream.run env
@@ Dream.logger
@@ Dream.memory_sessions
@@ Dream.router [
Expand All @@ -28,7 +29,7 @@ let () =

Dream.post "/"
(fun request ->
match%lwt Dream.form request with
match Dream.form request with
| `Ok ["message", message] ->
Dream.html (show_form ~message request)
| _ ->
Expand Down
2 changes: 1 addition & 1 deletion example/e-json/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ To get this working, we have to add `ppx_yojson_conv` to our
<pre><code>(executable
(name json)
(libraries dream)
<b>(preprocess (pps lwt_ppx ppx_yojson_conv)))</b>
<b>(preprocess (pps ppx_yojson_conv)))</b>
</code></pre>

and to
Expand Down
Loading