StompClient (Elixir STOMP Client v0.0.2)

View Source

Custom STOMP protocol client implementation for Elixir.

This module provides a GenServer-based STOMP client with precise control over message formatting, especially content-length headers. It features automatic reconnection, heartbeat support, and callback-based message handling.

Features

  • Custom Message Formatting: Control over content-length headers (can omit content-length for SEND frames)
  • 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

Usage

The basic workflow involves:

  1. Start a callback handler process
  2. Connect to the STOMP server
  3. Subscribe to destinations
  4. Send/receive messages
  5. Disconnect when done

Example

# Define a callback handler
defmodule MyHandler do
  use GenServer

  def start_link(_), do: GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  def init(_), do: {:ok, %{}}

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

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

  def handle_info(_, state), do: {:noreply, state}
end

# Start handler and connect  
{:ok, _} = MyHandler.start_link(nil)
{:ok, client} = StompClient.connect([
  host: "localhost",
  port: 61613,
  username: "guest",
  password: "guest"
], callback_handler: MyHandler)

# Use the client
StompClient.subscribe(client, "/queue/test")
StompClient.send(client, "/queue/test", "Hello World!")
StompClient.disconnect(client)

Callback Messages

Your callback handler will receive these message types:

  • {: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)

Summary

Functions

Returns a specification to start this module under a supervisor.

Connects to a STOMP server with callback handler.

Disconnects from the STOMP server and stops the client.

Sends a message to a STOMP destination.

Starts a STOMP client process.

Subscribes to a STOMP destination.

Unsubscribes from a STOMP destination.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

connect(opts, list)

@spec connect(keyword() | map(), [{:callback_handler, pid() | atom()}]) ::
  GenServer.on_start()

Connects to a STOMP server with callback handler.

This is a convenience function that combines start_link/1 with callback handler setup.

Parameters

  • opts - Connection options (keyword list or map)
  • callback_handler - Process to receive callback messages

Examples

{:ok, client} = StompClient.connect([
  host: "localhost",
  port: 61613,
  username: "guest", 
  password: "guest"
], callback_handler: MyHandler)

disconnect(pid)

@spec disconnect(pid()) :: :ok

Disconnects from the STOMP server and stops the client.

Parameters

  • pid - The STOMP client process

Returns

  • :ok always

Examples

StompClient.disconnect(client)

send(pid, destination, body, headers \\ [])

@spec send(pid(), String.t(), String.t(), [{String.t(), String.t()}]) ::
  :ok | {:error, :not_connected | term()}

Sends a message to a STOMP destination.

Parameters

  • pid - The STOMP client process
  • destination - STOMP destination (e.g., "/queue/test" or "/topic/news")
  • body - Message body as string
  • headers - Optional list of additional headers as tuples

Returns

  • :ok on success
  • {:error, :not_connected} if client is not connected
  • {:error, reason} on other errors

Examples

# Simple message
StompClient.send(client, "/queue/test", "Hello World!")

# Message with custom headers  
StompClient.send(client, "/queue/test", "Hello", [
  {"priority", "5"},
  {"custom-header", "value"}
])

start_link(opts)

@spec start_link(keyword() | map()) :: GenServer.on_start()

Starts a STOMP client process.

Parameters

  • opts - Connection options as keyword list or map

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)

Examples

{:ok, client} = StompClient.start_link([
  host: "localhost",
  port: 61613,
  username: "guest",
  password: "guest",
  callback_handler: MyHandler
])

subscribe(pid, destination, opts \\ [])

@spec subscribe(pid(), String.t(), keyword()) ::
  :ok | {:error, :not_connected | term()}

Subscribes to a STOMP destination.

Parameters

  • pid - The STOMP client process
  • destination - STOMP destination to subscribe to
  • opts - Optional subscription options

Options

  • :id - Custom subscription ID (auto-generated if not provided)
  • :selector - Message selector for filtering

Returns

  • :ok on success
  • {:error, :not_connected} if client is not connected
  • {:error, reason} on other errors

Examples

# Simple subscription
StompClient.subscribe(client, "/queue/test")

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

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

unsubscribe(pid, destination)

@spec unsubscribe(pid(), String.t()) ::
  :ok | {:error, :not_connected | :not_subscribed | term()}

Unsubscribes from a STOMP destination.

Parameters

  • pid - The STOMP client process
  • destination - STOMP destination to unsubscribe from

Returns

  • :ok on success
  • {:error, :not_connected} if client is not connected
  • {:error, :not_subscribed} if not subscribed to destination
  • {:error, reason} on other errors

Examples

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