Files
bux-lang/apps/nexus/README.md
T
dimgigov a785747c37
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
feat: Linux/cloud platform stack (TLS, registry, static/cross, selfhost PM)
Ship the QUALITY_PLAN platform focus: thin/minimal runtime, --static/--target,
Nexus HTTPS/mTLS with graceful stop, lock checksums + install --locked,
selfhost registry (search/add/HTTP), containers, and CI smokes for cloud path.
2026-07-23 23:00:55 +03:00

219 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nexus
**High-performance, multi-threaded HTTP/1.1, HTTP/2 & WebSocket server — built with the [Bux](https://github.com/bux-lang/bux) programming language.**
Nexus is a from-scratch web server that demonstrates Bux's systems-programming capabilities: raw TCP sockets, pthread-based concurrency, manual memory management, and zero-dependency C ABI interop — all from a clean, modern syntax.
---
## Features
| Area | What's Implemented |
|------|-------------------|
| **HTTP/1.1** | Full request parsing, **keep-alive** (reuse TCP), status codes, content negotiation |
| **Multi-threaded** | Worker pool + channel task queue; configurable via `NEXUS_WORKERS` |
| **HTTP/2** | Connection preface detection (`PRI * HTTP/2.0`), upgrade-aware routing |
| **WebSocket** | RFC 6455 upgrade handshake detection, `Sec-WebSocket-Key` extraction |
| **Static files** | Serves from `public/` with MIME-type detection for 20+ file types, directory-traversal protection |
| **JSON API** | Built-in `/api/health` and `/api/info` endpoints |
| **Logging** | Access log: `METHOD path status duration_ms` (`NEXUS_ACCESS_LOG=0` to disable) |
| **Limits** | `NEXUS_MAX_BODY` (default 1 MiB) → HTTP 413 when exceeded |
| **Graceful stop** | SIGINT/SIGTERM: close listen fd, poison workers, exit 0 |
| **TLS / HTTPS** | OpenSSL server mode via `NEXUS_TLS=1` + PEM cert/key |
| **mTLS** | `NEXUS_TLS_CLIENT_CA` PEM → require client certificates |
## Quick Start
```bash
# From the project root
cd apps/nexus
# Build with the bootstrap compiler (Nim)
../../buxc build
# Or with the self-hosted compiler
../../buxc_lir build
# Run
./nexus
# Optional env (also used by `make bench-nexus`)
# NEXUS_PORT=18080 NEXUS_BIND=127.0.0.1 NEXUS_WORKERS=4 \
# NEXUS_MAX_BODY=1048576 NEXUS_ACCESS_LOG=1 ./build/nexus
# HTTPS (self-signed example)
# openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 -subj /CN=localhost
# NEXUS_TLS=1 NEXUS_TLS_CERT=cert.pem NEXUS_TLS_KEY=key.pem NEXUS_PORT=8443 ./build/nexus
# curl -k https://127.0.0.1:8443/api/health
# mTLS (require client cert signed by CA)
# NEXUS_TLS_CLIENT_CA=ca.pem NEXUS_TLS=1 NEXUS_TLS_CERT=server.pem NEXUS_TLS_KEY=server.key …
# curl --cert client.pem --key client.key --cacert ca.pem https://…
```
Server starts on `http://0.0.0.0:8080` (or `https://` when TLS is enabled).
Stop with **Ctrl+C** or `kill -TERM` (graceful: workers drained via poison pills).
Smoke: `make test-nexus-tls` (self-signed cert + curl -k).
### Docker
```bash
# Full Nexus (needs libssl3)
../../buxc --release build # from apps/nexus
docker build -f ../../examples/docker/Dockerfile.nexus -t bux-nexus ../..
docker run --rm -p 8080:8080 bux-nexus
```
```
╔══════════════════════════════════════════════╗
║ Nexus HTTP Server v0.1.0 ║
║ High-performance multi-threaded HTTP/1.1 ║
║ HTTP/2 & WebSocket detection included ║
║ Built with Bux ║
╚══════════════════════════════════════════════╝
✓ Server listening on http://0.0.0.0:8080
✓ Worker threads: 4
✓ Static files: ./public/
Endpoints:
GET / — Static files (public/)
GET /api/health — Health check (JSON)
GET /api/info — Server info (JSON)
GET /ws — WebSocket upgrade
ANY /* — Static file serving
```
## Testing It
```bash
# Home page (HTML)
curl http://localhost:8080/
# Health check
curl http://localhost:8080/api/health
# → {"status":"ok","server":"Nexus","version":"0.1.0"}
# Server info
curl http://localhost:8080/api/info
# → {"name":"Nexus","language":"Bux","features":[...]}
# Static file (404 page)
curl http://localhost:8080/404.html
# Nonexistent file
curl http://localhost:8080/nope
# → 404 Not Found
# WebSocket upgrade attempt
curl -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
http://localhost:8080/ws
# → 101 Switching Protocols
```
## Architecture
### Thread Model — Multi-Accept
Nexus uses the **multi-accept** pattern rather than a traditional thread pool with a work queue:
```
Main Thread Worker 1 Worker 2 Worker 3
│ │ │ │
├─ socket()/bind()/listen() │ │ │
├─ spawn Worker() ──────────► │ │
├─ spawn Worker() ─────────────────────────► │
├─ spawn Worker() ────────────────────────────────────────►
│ │ │ │
▼ Worker() ▼ accept() ▼ accept() ▼ accept()
accept() loop │ │ │
```
Each worker thread calls `accept()` on the **same** listening socket. The Linux kernel distributes incoming connections across the blocked accept calls — the same mechanism used by nginx and Apache prefork. No mutex, no queue, no context switching between a dispatcher and workers.
### Request Lifecycle
```
Client connects
Net_Accept() → client fd
Net_Recv(fd, 8192) → raw bytes
ParseRequest()
├─ Split headers on \r\n\r\n
├─ Parse request line → method, path, version
└─ Parse header lines → key-value array
Router_Dispatch()
├─ /api/* → JSON handlers
├─ /ws → WebSocket upgrade
├─ Upgrade header → HTTP/2 or WS detection
└─ /* → Static file serving
BuildResponse() → HTTP/1.1 status line + headers + body
Net_Send(fd, response) → bytes to client
Net_Close(fd)
```
### Design Decisions
- **No keep-alive by default.** Each connection is closed after one response. This avoids blocking worker threads on idle clients (Bux doesn't yet expose `SO_RCVTIMEO`).
- **Linear header array instead of hash map.** HTTP requests typically carry 515 headers. A linear scan over a key-value array is faster than hashing for this N, and avoids the complexity of iterating over Bux's generic `StringMap`.
- **Raw extern calls for the string builder.** The stdlib `StringBuilder` wrapper adds a struct indirection. Calling `bux_sb_new` / `bux_sb_append` / `bux_sb_build` directly is simpler and equally safe.
- **WebSocket accept key is a placeholder.** A full implementation needs SHA-1 hashing and Base64 encoding. These aren't in Bux's stdlib yet; they can be added as extern C functions when needed.
## Project Structure
```
apps/nexus/
├── bux.toml # Package manifest
├── README.md # This file
├── src/
│ └── Main.bux # The entire server (~640 lines)
└── public/
├── index.html # Landing page
└── 404.html # Error page
```
Everything lives in one file (`src/Main.bux`) by design — it keeps the module graph flat and the build fast. As the server grows, the HTTP parser, router, and handlers can be split into separate modules.
## Configuration
Edit the constants at the top of `src/Main.bux`:
```bux
const SERVER_PORT: int = 8080; // Listen port
const THREAD_COUNT: int = 4; // Number of worker threads
const RECV_BUF_SIZE: int = 8192; // Receive buffer per request
const SERVER_NAME: String = "Nexus/0.1.0 (Bux)";
const PUBLIC_DIR: String = "public"; // Static files directory
```
## Roadmap
- [ ] Keep-alive with configurable socket timeout
- [ ] Full WebSocket frame read/write (requires SHA-1 + Base64)
- [ ] HTTP/2 binary framing layer (HPACK, stream multiplexing)
- [ ] SSL/TLS via OpenSSL extern bindings
- [ ] Middleware / filter chain
- [ ] Request body parsing (JSON, form-encoded, multipart)
- [ ] Virtual hosts
- [ ] Access logging to file
- [ ] Rate limiting
## License
Nexus is part of the Bux project. See the root [LICENSE](../../LICENSE) for terms.