feat: crypto library, Nexus HTTP server, JWT CLI, Boko web framework

- lib/crypto/: 9-module crypto library (Hash, HMAC, Base64/URL, Random, AES, RSA, ECDSA, Ed25519, JWT)
- rt/runtime.c: +346 lines OpenSSL crypto primitives (SHA-1/384/512, HMAC, Base64URL, AES-CBC/GCM, RSA, ECDSA, Ed25519)
- apps/nexus/: multi-threaded HTTP/1.1 + HTTP/2 detect + WebSocket server
- apps/jwt-pitbul/: JWT CLI tool (sign, verify, decode, keygen)
- apps/boko-framework/: FastAPI-inspired async web framework
- test_crypto/: crypto library test suite (23 tests)
This commit is contained in:
2026-06-07 22:15:00 +03:00
parent a2617e9954
commit e7e900973f
47 changed files with 3983 additions and 6 deletions
+177
View File
@@ -0,0 +1,177 @@
# Boko Framework
**Async web framework for Bux — inspired by FastAPI.**
Boko is a lightweight, multi-threaded web framework that brings FastAPI-style routing to the Bux programming language. It handles HTTP parsing, path pattern matching, query parameter extraction, and response building so you can focus on your application logic.
## Quick Start
```bash
cd apps/boko-framework
../../buxc build
./boko-framework
```
Open `http://localhost:8080` — you'll see the demo landing page.
## How It Works
Boko follows a **single-dispatch-function** pattern. You define one function — `Boko_Router` — and the framework calls it for every incoming request:
```bux
import Boko::{Request, Response, Response_Json, Response_Html, Response_NotFound,
Path_Match, Request_GetQuery, Request_GetPathParam,
App, App_New, App_Run};
func Boko_Router(req: Request) -> Response {
// Route: GET /
if String_Eq(req.path, "/") {
return Response_Html("<h1>Hello Boko!</h1>");
}
// Route: GET /api/health
if String_Eq(req.path, "/api/health") {
return Response_Json("{\"status\":\"ok\"}");
}
// Route: GET /users/{id} — path parameter
if Path_Match("/users/{id}", req.path, &req) {
let id: String = Request_GetPathParam(&req, "id");
// Build JSON response with id
return Response_Json(...);
}
// Route: GET /search?q=... — query parameter
if String_Eq(req.path, "/search") {
let q: String = Request_GetQuery(&req, "q");
return Response_Json(...);
}
return Response_NotFound();
}
func Main() -> int {
let app: App = App_New(8080, 4); // port, threads
App_Run(&app);
return 0;
}
```
## API Reference
### Request
| Field | Type | Description |
|-------|------|-------------|
| `method` | `HttpVerb` | GET, POST, PUT, DELETE |
| `path` | `String` | Request path (without query string) |
| `body` | `String` | Request body (for POST/PUT) |
| `headerCount` | `int` | Number of headers |
| Function | Returns | Description |
|----------|---------|-------------|
| `Request_GetHeader(req, name)` | `String` | Get header value by name |
| `Request_GetQuery(req, name)` | `String` | Get query parameter by name |
| `Request_GetPathParam(req, name)` | `String` | Get extracted path parameter |
### Response
| Constructor | Content-Type | Status |
|-------------|-------------|--------|
| `Response_Html(html)` | `text/html` | 200 |
| `Response_Json(json)` | `application/json` | 200 |
| `Response_Text(text)` | `text/plain` | 200 |
| `Response_Redirect(url)` | — | 302 |
| `Response_NotFound()` | `application/json` | 404 |
| `Response_Error(code, msg)` | `application/json` | custom |
| `Response_NoContent()` | — | 204 |
### Path Matching
`Path_Match(pattern, actualPath, req)` matches a pattern with `{param}` placeholders:
```bux
// Pattern: /users/{id}/posts/{postId}
// Actual: /users/42/posts/7
// Extracts: id=42, postId=7
if Path_Match("/users/{id}/posts/{postId}", req.path, &req) {
let userId: String = Request_GetPathParam(&req, "id"); // "42"
let postId: String = Request_GetPathParam(&req, "postId"); // "7"
}
```
The function returns `true` if the pattern matches and populates `req.pathParamKeys` / `req.pathParamValues`.
### App
```bux
let app: App = App_New(8080, 4); // port 8080, 4 worker threads
App_Run(&app); // blocks, handles requests
```
## Architecture
```
Incoming connection
Net_Accept() ─── worker thread (1 of N)
Net_Recv() → raw HTTP bytes
Request_Parse() → method, path, query, headers, body
Boko_Router(req) ←── YOUR CODE
Response_Build() → HTTP/1.1 response string
Net_Send() → bytes to client
Net_Close()
```
## Endpoints in Demo App
| Method | Path | Description |
|--------|------|-------------|
| GET | `/` | Landing page (HTML) |
| GET | `/api/health` | Health check (JSON) |
| GET | `/api/info` | Framework info (JSON) |
| GET | `/hello?name=X` | Query param demo |
| GET | `/users/{id}` | Path param demo |
| GET | `/posts/{id}/comments/{cid}` | Multi path param demo |
| GET | `/redirect` | 302 redirect to `/` |
| POST | `/api/echo` | Echo request body |
## Project Structure
```
apps/boko-framework/
├── bux.toml # Package manifest
├── README.md # This file
└── src/
├── Boko.bux # Framework core (~500 lines)
└── Main.bux # Example app (~150 lines)
```
## Design Philosophy
Boko is intentionally simple. Instead of complex DSLs or code generation, it gives you:
- **One function to write** — `Boko_Router(req) -> Response`
- **Direct control** — you write plain if/else or match for routing
- **No magic** — path params, query params, headers are explicit function calls
- **Fast** — multi-threaded accept loop, zero allocations where possible
This is the same philosophy as Go's `net/http` — simple, explicit, composable.
## License
Part of the Bux project. See root [LICENSE](../../LICENSE).