kode-bridge 0.5.1

Modern HTTP Over IPC library for Rust with both client and server support (Unix sockets, Windows named pipes).
Documentation
# kode-bridge Server Guide

This guide covers the server APIs available in kode-bridge 0.5. Enable the
`server` feature for server-only programs or `full` when the same crate also
uses client APIs.

```toml
[dependencies]
kode-bridge = { version = "0.5", features = ["server"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
serde_json = "1"
http = "1"
```

Rust 1.87 or newer is required.

## HTTP server

`IpcHttpServer` parses HTTP-style requests from an IPC connection, routes them
by method and path, and encodes an HTTP-style response on the same connection.

```rust
use http::StatusCode;
use kode_bridge::{HttpResponse, IpcHttpServer, Result, Router};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<()> {
    #[cfg(unix)]
    let endpoint = "/tmp/kode-bridge-server.sock";
    #[cfg(windows)]
    let endpoint = r"\\.\pipe\kode-bridge-server";

    let router = Router::new()
        .get("/health", |_| async {
            HttpResponse::json(&json!({"status": "healthy"}))
        })
        .get("/users/:id", |ctx| async move {
            let id = ctx
                .path_params
                .get("id")
                .cloned()
                .unwrap_or_default();
            HttpResponse::json(&json!({"id": id}))
        })
        .post("/echo", |ctx| async move {
            match ctx.json::<serde_json::Value>() {
                Ok(value) => HttpResponse::json(&value),
                Err(error) => Ok(HttpResponse::error(
                    StatusCode::BAD_REQUEST,
                    &error.to_string(),
                )),
            }
        });

    let mut server = IpcHttpServer::new(endpoint)?.router(router);
    server.serve().await
}
```

The router supports GET, POST, PUT, and DELETE helpers. Use `add_route` with an
`http::Method` for another method. Route parameters use `:name`, for example
`/users/:id`.

The current router does not provide middleware or static-file helpers. Put
cross-cutting behavior in handler functions or an application-owned wrapper.

## Request and response APIs

`RequestContext` exposes:

- `method`, `uri`, `headers`, and raw `body` fields;
- `json::<T>()` and `text()` body parsing;
- `query_params()` for decoded query pairs;
- `path_params` and `path_params()` for route captures;
- connection ID and timing through `client_info` and `timestamp`.

Handlers return `kode_bridge::Result<HttpResponse>`. Responses can be built
with `HttpResponse::json`, `HttpResponse::text`, `HttpResponse::error`, or the
response builder:

```rust
let response = HttpResponse::builder()
    .status(http::StatusCode::CREATED)
    .header("content-type", "application/json")
    .json(&serde_json::json!({"created": true}))?
    .build();
```

## HTTP server configuration

```rust
use kode_bridge::ServerConfig;
use std::time::Duration;

let config = ServerConfig {
    max_connections: 128,
    read_timeout: Duration::from_secs(5),
    write_timeout: Duration::from_secs(5),
    max_request_size: 10 * 1024 * 1024,
    max_header_size: 4096,
    enable_logging: true,
    max_requests_per_connection: 32,
    shutdown_timeout: Duration::from_secs(3),
};
```

Create the server with `IpcHttpServer::with_config(endpoint, config)`.

- `max_connections` bounds concurrently accepted connections.
- `read_timeout` bounds waiting for and parsing the next request.
- Despite its name, `write_timeout` currently bounds the handler future. The
  subsequent `framed.send(response)` is not wrapped in a separate timeout.
- `max_requests_per_connection` bounds keep-alive reuse on one connection.
- Size limits should be set from the largest supported request, with overhead.
- `enable_logging` controls per-request server logging.

`ServerStats` reports connections, requests, responses, errors, and start time.
The server does not currently expose a cloneable runtime stats/control handle;
plan ownership before moving the server into a task.

## Streaming server

`IpcStreamServer` broadcasts raw `StreamMessage` frames. JSON and text messages
are newline-delimited; binary messages are written as provided. A periodic
`JsonDataSource` is the shortest supported setup:

```rust
use kode_bridge::{IpcStreamServer, JsonDataSource, Result, StreamServerConfig};
use serde_json::json;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<()> {
    #[cfg(unix)]
    let endpoint = "/tmp/kode-bridge-stream.sock";
    #[cfg(windows)]
    let endpoint = r"\\.\pipe\kode-bridge-stream";

    let config = StreamServerConfig {
        max_connections: 64,
        buffer_size: 64 * 1024,
        write_timeout: Duration::from_secs(5),
        max_message_size: 1024 * 1024,
        enable_logging: true,
        shutdown_timeout: Duration::from_secs(5),
        broadcast_capacity: 1000,
        keepalive_interval: Duration::from_secs(30),
    };

    let source = JsonDataSource::new(
        || Ok(json!({"status": "running"})),
        Duration::from_secs(1),
    );

    let mut server = IpcStreamServer::with_config(endpoint, config)?;
    server.serve_with_source(source).await
}
```

For application-defined production logic, implement `StreamSource` directly.
It supplies `next_messages`, `has_more`, `initialize`, and `cleanup`; see
[stream_server.rs](./examples/stream_server.rs) and the API documentation for
the exact signatures.

`IpcStreamClient` is not the direct client for `IpcStreamServer` in 0.5. The
former parses an HTTP-style streamed response, while the latter emits raw
newline-delimited frames. Use a raw Tokio `AsyncRead` client for the stream
server protocol, or expose an HTTP-style streaming handler for
`IpcStreamClient`.

The public `broadcast()` method requires the server's broadcast channel to be
initialized, but `serve(&mut self)` holds the mutable server borrow. Version
0.5 does not expose a cloneable broadcast/control handle, so
`serve_with_source` is the practical public API for ongoing broadcasts.

## Listener permissions and cleanup

### Unix

```rust
#[cfg(unix)]
let server = IpcHttpServer::new("/run/my-app/service.sock")?
    .with_listener_mode(0o660);
```

The default listener removes its own socket path when dropped. It does not
overwrite a stale path unless `ListenerOptions::try_overwrite(true)` is set.
Use a trusted parent directory. Custom mode is applied after bind and before
listen on Linux and macOS.

### Windows

```rust
#[cfg(windows)]
let server = IpcHttpServer::new(r"\\.\pipe\my-app")?
    .with_listener_security_descriptor("D:(A;;GA;;;WD)");
```

Windows named pipes reject remote clients. SDDL is applied to every pipe
instance; invalid SDDL panics during builder configuration for 0.4 API
compatibility. Use a least-privilege descriptor for production services.

## Task lifecycle

`serve()` runs until it is cancelled or its internal shutdown channel fires;
accept errors are logged and the accept loop continues. Version 0.5 does not
expose a separate shutdown handle. When the application owns the server task,
cancellation is the usable external shutdown mechanism:

```rust
let task = tokio::spawn(async move { server.serve().await });
tokio::signal::ctrl_c().await?;
task.abort();
let _ = task.await;
```

Await the cancelled task so the listener is dropped before restarting on the
same endpoint. On Unix, that drop performs identity-checked path cleanup.

## Performance guidance

- Reuse pooled client connections instead of increasing server limits first.
- Set `max_connections` and broadcast capacity from measured concurrency and
  per-connection memory.
- Keep request and message limits explicit.
- Do not shorten `write_timeout` below the slowest supported handler. Treat a
  response-write deadline as an open server limitation in version 0.5.
- Run `cargo bench --all-features --bench ipc_transport` for transport changes.
- Treat shared CI runners as functional evidence, not stable performance data.

Complete runnable programs are maintained in
[http_server.rs](./examples/http_server.rs),
[stream_server.rs](./examples/stream_server.rs), and
[server.rs](./examples/server.rs).