# Interpreting TCP Streams

Contribute a "Follow TCP Stream" view for your protocol by conforming your analyzer to ``CPAStreamInterpreting``.

## Overview

When a user runs **Follow TCP Stream** on a TCP conversation, CocoaPacketAnalyzer reassembles the whole bidirectional byte stream and hands it to any plugin that knows how to interpret it. Your plugin opts in by conforming its registered analyzer class to ``CPAStreamInterpreting`` — a small, stateless, type-level protocol. There is **no extra registration call**: the host discovers conformers automatically via `CPAPlugInsController.streamInterpreterTypes()`.

The result is a structured, message-by-message rendering of the conversation — and, because every message body flows through the shared view, any image/text/binary body the user can **drag straight out to Finder**.

> Important: Stream interpretation is **TCP only**. The Follow-TCP-Stream window opens for TCP packets, so a UDP-only analyzer cannot use this protocol.

## Conform your analyzer

`CPAStreamInterpreting` has three `static` requirements — no instance state, so interpretation runs off the main actor safely:

```swift
import CPAPluginSDK

extension MyProtocolAnalyzer: CPAStreamInterpreting {

    /// The user-facing tab label (e.g. "HTTP", "SMTP").
    public static var streamDisplayName: String { "MyProto" }

    /// Cheap check: does this stream look like your protocol?
    public static func canInterpret(stream: TCPStream) -> Bool {
        looksLikeMyProto(stream.clientToServerData)
            || looksLikeMyProto(stream.serverToClientData)
    }

    /// Parse the reassembled bytes into ordered messages.
    public static func interpret(stream: TCPStream) -> StreamInterpretation {
        var messages: [StreamMessage] = []
        messages += parse(stream.clientToServerData, direction: .clientToServer)
        messages += parse(stream.serverToClientData, direction: .serverToClient)
        return StreamInterpretation(messages: messages, pairings: nil)
    }
}
```

## The stream and the messages

``TCPStream`` gives you the fully reassembled payload for each direction plus the ordered segments:

- `clientToServerData` / `serverToClientData` — the reassembled `Data` for each side (sequence-ordered, retransmissions resolved).
- `segments` — the `TCPSegment`s, if you need per-segment timing.
- `locate(byteRange:in:)` — maps a direction-relative byte range back to the carrying packet ids and capture timestamp, so you can populate ``StreamMessage`` `packetIds`/`timestamp` for wall-clock ordering and jump-to-packet.

Each ``StreamMessage`` you emit carries a `direction`, a `kind` (`.request` / `.reply` / `.data` / `.handshake` / `.push`), a one-line `summary`, optional `detail` name/value rows, an optional `body` with a ``StreamBodyHint`` (`.text` / `.json` / `.html` / `.xml` / `.image` / `.binary`), and an optional `filename` (used as the drag-to-save name). Bodies render — and become droppable assets — for free.

Return them in a ``StreamInterpretation``. Set `pairings` to correlate requests with replies (drawn as a connector rail beside the list), or `nil` if your protocol has no natural pairing.

## Keep `interpret` pure

`interpret(stream:)` must be **pure and off-main-safe**: depend only on its `TCPStream` argument, touch no shared mutable state, and never assume the main actor. A `static` method on an `NSObject` analyzer satisfies this by construction.

## Worked references

The first-party analyzers ship complete conformers you can read as templates:

- **HTTP** — request/response with headers, body content-type detection, and `Content-Encoding` decompression.
- **Hotline** — a binary transaction protocol, with `taskNumber`-based request↔reply pairing.
- **SMTP / POP3 / IMAP** — line protocols that extract each email's MIME parts (attachments) as individually droppable messages via the shared `MIMEParser`.

## See Also

- ``CPAStreamInterpreting``
- ``StreamMessage``
- ``StreamInterpretation``
- ``TCPStream``
