folk-builder 0.2.0

Custom binary builder for Folk — generates and compiles a Folk server with selected plugins
Documentation
# folk-builder

Generates and compiles a PHP extension (`folk.so`) that runs the Folk application server inside PHP.

Folk replaces Swoole/RoadRunner/FrankenPHP: your PHP process loads `folk.so`, which embeds a high-performance HTTP server (axum/hyper + tokio) with ZTS multi-worker threads.

## Quick Start

### 1. Install folk-builder

```bash
cargo install folk-builder
```

Or build from source:

```bash
git clone https://github.com/Folk-Project/folk-builder
cd folk-builder
cargo build --release
# Binary at target/release/folk-builder
```

### 2. Create build config

Create `folk.build.toml`:

```toml
[build]
output = "folk"                    # Extension name (produces folk.so)

[[plugin]]
crate_name = "folk-plugin-http"    # HTTP server plugin
version = "0.2"
config_key = "http"
```

### 3. Build the extension

```bash
folk-builder build --config folk.build.toml --output-dir .
```

This generates a Cargo project, compiles it, and produces `folk.so`.

Requirements:
- Rust 1.88+
- PHP 8.2+ (NTS or ZTS) with `php-config` in PATH
- For multi-worker: PHP must be compiled with ZTS (`--enable-zts`)

### 4. Load and run

Create `folk.toml` (server config):

```toml
[workers]
script = "server.php"
count = 4           # Number of worker threads (requires ZTS PHP)
max_jobs = 100000

[http]
listen = "0.0.0.0:8080"

[log]
filter = "warn"
```

Create `server.php`:

```php
<?php
require __DIR__ . '/vendor/autoload.php';

// Start the Folk server (non-blocking).
if (!folk_is_worker_thread()) {
    $server = new Folk\Server('folk.toml');
    $server->start();
}

// Create worker loop and register handlers.
$loop = new \Folk\Sdk\Worker\WorkerLoop();
$loop->registerHttpHandler(new MyHttpHandler());
$loop->run();
```

Run:

```bash
php -d extension=./folk.so server.php
```

## Build Config Reference

### `[build]`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `output` | string | yes | Extension name (without `.so`) |
| `folk_ext_path` | string | no | Local path to `folk-ext` crate (for development) |
| `folk_api_path` | string | no | Local path to `folk-api` crate (for development) |

### `[[plugin]]`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `crate_name` | string | yes | Rust crate name |
| `version` | string | no | Version (default: `"0.2"`) |
| `path` | string | no | Local path (overrides version) |
| `git` | string | no | Git URL (overrides version) |
| `config_key` | string | yes | Key in `folk.toml` for plugin config |

### Available plugins

| Plugin | Crate | Description |
|--------|-------|-------------|
| HTTP | `folk-plugin-http` | HTTP/1.1 server (axum/hyper) |
| gRPC | `folk-plugin-grpc` | gRPC server |
| Jobs | `folk-plugin-jobs` | Background job queue |
| Metrics | `folk-plugin-metrics` | Prometheus metrics endpoint |
| Process | `folk-plugin-process` | Process management signals |

## Docker

For production, build `folk.so` in a multi-stage Docker image:

```dockerfile
FROM php:8.3-zts AS builder

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
    | sh -s -- -y --default-toolchain 1.88.0
ENV PATH="/root/.cargo/bin:${PATH}"

RUN apt-get update && apt-get install -y \
    pkg-config libclang-dev clang && rm -rf /var/lib/apt/lists/*

WORKDIR /build
COPY folk-builder/ /build/folk-builder/
RUN cd /build/folk-builder && cargo build --release

RUN cat > /build/folk.build.toml << 'TOML'
[build]
output = "folk"

[[plugin]]
crate_name = "folk-plugin-http"
version = "0.2"
config_key = "http"
TOML

RUN /build/folk-builder/target/release/folk-builder build \
    --config /build/folk.build.toml --output-dir /build/

# --- Runtime ---
FROM php:8.3-zts
COPY --from=builder /build/folk.so /usr/local/lib/php/extensions/folk.so
RUN echo "extension=folk.so" > /usr/local/etc/php/conf.d/folk.ini
```

## Architecture

```
PHP loads folk.so
  |
  +-- Main thread (worker #1)
  |     folk_worker_run() -> Rust dispatch loop
  |       recv Value -> value_to_zval -> call_user_function -> zval_to_value
  |
  +-- folk-tokio thread
  |     axum HTTP server, worker pool, plugin registry
  |
  +-- ZTS workers #2..N (requires ZTS PHP)
        ts_resource -> php_request_startup -> execute worker script
```

Zero JSON serialization. Data passes as direct zval arrays between Rust and PHP.

## Performance

Raw JSON, Docker, 2 CPU:

| Workers | Req/sec |
|---------|---------|
| 1 | ~27,000 |
| 4 | ~55,000 |

Laravel, Docker, 2 CPU, 4 workers: ~3,600 rps

## License

MIT