# pdk-websockets

Library for decoding and encoding WebSocket frames in Flex Gateway custom policies.

It wraps [`websocket-sans-io`](https://crates.io/crates/websocket-sans-io) to provide ergonomic
frame-level access for policies that operate on WebSocket upgrade connections.

## Types

- **`Frame`** — a single WebSocket frame with payload and metadata
- **`FrameType`** — the kind of frame (`Text`, `Binary`, `Continuation`, `Ping`, `Pong`, `ConnectionClose`, `Reserved`)
- **`Decoder`** — incrementally decodes raw bytes into `Frame`s
- **`Encoder`** — re-encodes a collection of `Frame`s back into bytes
- **`SinkResult`** — outcome of feeding bytes to the `Decoder` (`Complete(frames)` or `MidFrame`)

## Usage

Add the dependency to your policy's `Cargo.toml`:

```toml
pdk_websockets = { workspace = true }
```

Process frames in `on_http_request_body`:

```rust
use pdk_websockets::{Decoder, Encoder, Frame, FrameType, SinkResult};

let mut decoder = Decoder::default();

match decoder.sink(body) {
    SinkResult::MidFrame => {
        // Incomplete frame — pause and collect remaining bytes
        Action::Pause
    }
    SinkResult::Complete(mut frames) => {
        // Inspect frames
        if let Some(frame) = frames.first() {
            if let FrameType::Text = frame.frame_type() {
                let text = String::from_utf8_lossy(frame.data());
            }
        }

        // Modify frames
        if let Some(first) = frames.first_mut() {
            first.update("modified payload");
        }

        // Add new frames
        frames.push(Frame::ping());
        frames.push(Frame::text("injected", true));

        // Re-encode and replace the buffer
        let encoded = Encoder::default().encode(frames);
        self.set_http_request_body(0, usize::MAX, &encoded);
        Action::Continue
    }
}
```
