# Live Chat Reference
This document describes the public live chat interface.
Main types:
- `SoopChatOptions`
- `SoopChatConnection`
- `Command`
- `Event`
## Basic Flow
```rust
use std::sync::Arc;
use soup_sdk::{
Result, SoopHttpClient,
chat::{Event, SoopChatConnection, SoopChatOptions},
};
#[tokio::main]
async fn main() -> Result<()> {
let http = Arc::new(SoopHttpClient::new());
let options = SoopChatOptions {
streamer_id: "streamer_id".to_string(),
password: "".to_string(),
diagnostics: false,
};
let connection = SoopChatConnection::new(Arc::clone(&http), options)?;
let mut events = connection.subscribe();
connection.start().await?;
while let Ok(event) = events.recv().await {
if let Event::Chat(chat) = event {
println!("{}: {}", chat.user.label, chat.comment);
}
}
Ok(())
}
```
## `SoopChatOptions`
Configuration for a live chat connection.
Fields:
- `streamer_id: String`: SOOP streamer ID.
- `password: String`: broadcast password. Use an empty string for non-password streams.
- `diagnostics: bool`: when `true`, emits raw frame, decoded frame, unknown-code, and parse-failure diagnostic events.
Current limitation:
- Login/session options and custom base URLs are not currently exposed.
## `SoopChatConnection::new`
Creates a chat connection handle.
```rust
let connection = SoopChatConnection::new(http_client, options)?;
```
Inputs:
- `http_client: Arc<SoopHttpClient>`
- `options: SoopChatOptions`
Returns:
```rust
Result<SoopChatConnection>
```
Behavior:
- Initializes TLS crypto provider if needed.
- Creates an internal command channel.
- Creates a broadcast event channel with capacity `1024`.
- Does not open the network connection yet.
Failure modes:
- TLS crypto provider initialization can return `Error::Protocol` if installation fails.
## `subscribe`
Creates an event receiver.
```rust
let mut events = connection.subscribe();
```
Returns:
```rust
tokio::sync::broadcast::Receiver<Event>
```
Behavior:
- Can be called before `start`.
- Multiple subscribers can receive the same event stream.
- Broadcast receivers can lag. If a receiver falls behind the channel capacity, Tokio broadcast semantics apply and events may be missed.
## `start`
Starts the background live chat connection task.
```rust
connection.start().await?;
```
Returns:
```rust
Result<()>
```
Behavior:
- Calls `SoopHttpClient::get_live_status`.
- Returns `Error::StreamOffline` if the streamer is not live.
- Builds the WebSocket URL from live detail.
- Opens the WebSocket with a 15-second connection timeout.
- Takes ownership of the internal command receiver.
- Spawns the connection loop in a background Tokio task.
Current contract:
- A `SoopChatConnection` is one-shot. Calling `start` more than once returns `Error::AlreadyStarted`.
Failure modes:
- live detail HTTP/API failure.
- stream offline.
- invalid live detail state.
- already-started connection.
## `command`
Sends a command to the background connection loop.
```rust
use soup_sdk::chat::commands::Command;
connection.command(Command::Shutdown)?;
connection.command(Command::RequestParticipantList)?;
```
Returns:
```rust
Result<()>
```
Implemented commands:
- `Command::Shutdown`: stops the active communication loop and leads to `Event::Disconnected`.
- `Command::RequestParticipantList`: sends a participant-list request packet. The SDK aggregates the server response internally and emits one final `Event::ParticipantList`.
Current note:
- Chat sending is not exposed in v0.3.
Failure modes:
- internal command channel is closed or full.
## Connection Lifecycle
Current session lifecycle:
```text
start
-> fetch live detail
-> connect to WebSocket
-> emit Connected
-> send Connect packet
-> receive server CONNECT
-> send JOIN packet
-> process incoming chat frames
-> send participant-list request when commanded
-> send Ping every 60 seconds
-> Shutdown or socket failure
-> emit Disconnected with a reason
```
Reconnect note:
- v0.3 does not automatically reconnect.
- Downstream users should treat disconnect as terminal and create a new session when they want to retry.
TLS note:
- Live chat currently disables TLS certificate verification for compatibility with the upstream chat endpoint. This is a deliberate security tradeoff in v0.3 and should not be treated as a general-purpose secure WebSocket default.
## Incoming Message Handling
Incoming WebSocket binary frames are handled as:
```text
binary frame
-> Event::Diagnostic(RawFrame) when diagnostics is enabled
-> parse raw protocol header/body
-> Event::Diagnostic(DecodedFrame) when diagnostics is enabled
-> match message code
-> parse typed event
-> broadcast typed Event or Event::Diagnostic(ParseFailed) when diagnostics is enabled
```
Raw protocol facts:
- header length: 14 bytes.
- body separator: form feed byte `0x0c`.
- message code constants live in `chat::constants::message_codes`.
## Debugging Workflow
For protocol analysis, set `SoopChatOptions::diagnostics` to `true`, subscribe to events, and inspect:
- `Event::Diagnostic(RawFrame)`: original binary frame.
- `Event::Diagnostic(DecodedFrame)`: decoded message code, ret code, body fields, and raw bytes.
- `Event::Unknown(code)` and `Event::Diagnostic(UnknownCode)`: decoded message code without a typed handler.
- `Event::Diagnostic(ParseFailed)`: message code, body field count, field index, expected type, reason, and raw bytes.
- typed events with surprising field values.
Recommended workflow for adding support for a new message:
1. Capture `Event::Diagnostic(RawFrame)`.
2. Decode the message code and body fields.
3. Record body field indexes and sample values.
4. Add or update a parser.
5. Add replay tests for the raw frame.
6. Update `EVENTS.md`.
## Threading and Runtime Notes
- The SDK expects a Tokio runtime.
- `start` spawns a background task with `tokio::spawn`.
- Events are delivered through `tokio::sync::broadcast`.
- Commands are delivered through `tokio::sync::mpsc`.