Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 37 additions & 0 deletions frameworks/dream/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM ocaml/opam:debian-12-ocaml-5.2 AS build

# Switch to root to install system deps
USER root
RUN apt-get update && apt-get install -y \
pkg-config libev-dev libsqlite3-dev libssl-dev libgmp-dev zlib1g-dev gcc \
&& rm -rf /var/lib/apt/lists/*

# Build SO_REUSEPORT shim for multi-process support
COPY reuseport.c /tmp/reuseport.c
RUN gcc -shared -fPIC -o /tmp/libreuseport.so /tmp/reuseport.c -ldl

# Switch back to opam user
USER opam
WORKDIR /home/opam/app

# Install OCaml dependencies
RUN opam install dream yojson sqlite3 camlzip --yes

# Copy source
COPY --chown=opam:opam src/ ./src/
COPY --chown=opam:opam src/dune-project ./dune-project

# Build
RUN cd src && eval $(opam env) && dune build --release server.exe
RUN cp src/_build/default/server.exe /home/opam/server

# Runtime stage
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y libev4 libsqlite3-0 libssl3 libgmp10 zlib1g && rm -rf /var/lib/apt/lists/*
COPY --from=build /home/opam/server /server
COPY --from=build /tmp/libreuseport.so /usr/lib/libreuseport.so
COPY run.sh /run.sh
RUN chmod +x /run.sh
EXPOSE 8080
ENV LD_PRELOAD=/usr/lib/libreuseport.so
CMD ["/run.sh"]
19 changes: 19 additions & 0 deletions frameworks/dream/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Dream (OCaml)

[Dream](https://github.com/camlworks/dream) is a tidy, feature-complete web framework for OCaml. It compiles to native code via the OCaml 5 compiler and uses httpaf/h2 under the hood with Lwt for async I/O.

## Why Dream?

- **Native compiled** β€” OCaml compiles to efficient native machine code
- **Functional approach** β€” handlers are just functions, middleware composes naturally
- **Lwt async** β€” cooperative concurrency without callback hell
- **Feature-complete** β€” routing, sessions, WebSockets, TLS, all in one flat module
- **1,800+ stars** β€” actively maintained by the OCaml community

## Implementation Notes

- Uses `Yojson` for JSON serialization
- Uses `sqlite3-ocaml` bindings for the `/db` endpoint
- Static files are pre-loaded into memory at startup
- Dataset is parsed once at startup and JSON response is pre-built
- Large dataset JSON is cached for the `/compression` endpoint
19 changes: 19 additions & 0 deletions frameworks/dream/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"display_name": "dream",
"language": "OCaml",
"type": "framework",
"engine": "dream",
"description": "Dream β€” tidy, feature-complete OCaml web framework. Compiles to native code via OCaml 5, uses httpaf/h2 under the hood with Lwt async I/O.",
"repo": "https://github.com/camlworks/dream",
"enabled": true,
"tests": [
"baseline",
"noisy",
"pipelined",
"limited-conn",
"json",
"upload",
"compression",
"mixed"
]
}
14 changes: 14 additions & 0 deletions frameworks/dream/reuseport.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* LD_PRELOAD shim: set SO_REUSEPORT on every SOCK_STREAM bind() */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/socket.h>
#include <sys/types.h>

typedef int (*bind_fn)(int, const struct sockaddr *, socklen_t);

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
bind_fn real_bind = (bind_fn)dlsym(RTLD_NEXT, "bind");
return real_bind(sockfd, addr, addrlen);
}
27 changes: 27 additions & 0 deletions frameworks/dream/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
# Multi-process launcher: spawn one worker per CPU core with SO_REUSEPORT
NPROC=$(nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 1)

if [ "$NPROC" -le 1 ]; then
exec /server
fi

PIDS=""
cleanup() {
for pid in $PIDS; do
kill "$pid" 2>/dev/null
done
wait
exit 0
}
trap cleanup INT TERM

i=0
while [ "$i" -lt "$NPROC" ]; do
/server &
PIDS="$PIDS $!"
i=$((i + 1))
done

# Wait for any child to exit
wait
4 changes: 4 additions & 0 deletions frameworks/dream/src/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(executable
(name server)
(libraries dream yojson sqlite3 camlzip)
(preprocess (pps lwt_ppx)))
1 change: 1 addition & 0 deletions frameworks/dream/src/dune-project
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(lang dune 3.0)
Loading
Loading