README.md

# Elixir STOMP Client

A custom STOMP protocol client implementation for Elixir that provides precise control over message formatting, especially content-length headers. Features automatic reconnection, heartbeat support, and callback-based message handling.

## Features

- **Custom Message Formatting**: Control over content-length headers (can omit content-length like Go's NoContentLength)
- **Automatic Reconnection**: Automatic reconnection with configurable retry intervals
- **Heartbeat Support**: Built-in heartbeat mechanism to keep connections alive
- **Callback-based Handling**: Process-based callback system for handling connection events and messages
- **STOMP 1.2 Compatible**: Full support for STOMP 1.2 protocol
- **Subscription Management**: Easy subscription and unsubscription management

## Installation

Add `elixir_stomp_client` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:elixir_stomp_client, "~> 0.1.0"}
  ]
end
```

## Usage

### Basic Connection

```elixir
# Define a callback handler process
defmodule MyStompHandler do
  use GenServer

  def start_link(_) do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end

  def init(_) do
    {:ok, %{}}
  end

  def handle_info({:stomp_client, :on_connect, frame}, state) do
    IO.puts("Connected to STOMP server!")
    {:noreply, state}
  end

  def handle_info({:stomp_client, :on_message, message}, state) do
    IO.puts("Received message: #{inspect(message)}")
    {:noreply, state}
  end

  def handle_info({:stomp_client, :on_disconnect, _}, state) do
    IO.puts("Disconnected from STOMP server")
    {:noreply, state}
  end

  def handle_info({:stomp_client, :on_connect_error, error}, state) do
    IO.puts("Connection error: #{inspect(error)}")
    {:noreply, state}
  end
end

# Start the handler
{:ok, _} = MyStompHandler.start_link(nil)

# Connect to STOMP server
{:ok, client} = StompClient.connect([
  host: "localhost",
  port: 61613,
  username: "guest",
  password: "guest"
], callback_handler: MyStompHandler)
```

### Sending Messages

```elixir
# Send a simple message
StompClient.send(client, "/queue/test", "Hello World!")

# Send a message with custom headers
StompClient.send(client, "/queue/test", "Hello World!", [
  {"custom-header", "custom-value"}
])
```

### Subscribing to Destinations

```elixir
# Subscribe to a queue
StompClient.subscribe(client, "/queue/test")

# Subscribe with a selector
StompClient.subscribe(client, "/queue/test", selector: "priority > 5")

# Subscribe with custom ID
StompClient.subscribe(client, "/queue/test", id: "my-subscription")
```

### Unsubscribing

```elixir
StompClient.unsubscribe(client, "/queue/test")
```

### Disconnecting

```elixir
StompClient.disconnect(client)
```

## Configuration Options

When connecting, you can provide the following options:

- `host` - STOMP server hostname (required)
- `port` - STOMP server port (default: 61613)
- `username` or `login` - Authentication username
- `password` or `passcode` - Authentication password
- `callback_handler` - Process to receive callback messages (required)

## Callback Messages

Your callback handler will receive the following messages:

- `{:stomp_client, :on_connect, frame}` - When successfully connected
- `{:stomp_client, :on_message, message}` - When a message is received
- `{:stomp_client, :on_disconnect, nil}` - When disconnected
- `{:stomp_client, :on_connect_error, error}` - When connection fails
- `{:stomp_client, :on_send, frame}` - When a frame is sent (optional)

## Message Structure

Received messages have the following structure:

```elixir
%{
  "destination" => "/queue/test",
  "body" => "message content",
  # ... other STOMP headers
}
```

## Advanced Usage

### Custom Frame Building

The client provides two frame building methods:

1. **Standard frames** (with content-length): Used for CONNECT, SUBSCRIBE, etc.
2. **Frames without content-length**: Used for SEND messages (configurable)

This allows compatibility with different STOMP server implementations that may have different content-length requirements.

### Heartbeat Configuration

The client automatically sends heartbeats every 25 seconds when connected. The server heartbeat timeout is set to 30 seconds.

### Error Handling

The client includes robust error handling with automatic reconnection. Connection failures trigger reconnection attempts every 5 seconds.

## License

MIT License. See LICENSE file for details.

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request