sondahub / STOMP test server
STOMP test server
STOMP 1.0, 1.1 and 1.2 straight over WebSocket, with RabbitMQ’s destinations and a broker that is already busy: live topics from the hub’s activity, queues that hold the last minute of it, an orders queue that moves what you send, and an rpc queue that answers through a temp-queue. Over TCP too, through the bridge, on the same broker as AMQP.
Free and open: no key, no account. Each WebSocket connection gets a broker of its own.
Connect
- WebSocket
- wss://api.sondahub.com/stomp
- Subprotocol
- v12.stomp, v11.stomp or v10.stomp
- Over TCP
- through the bridge: node bridge.mjs amqp, then localhost:61713
- STOMP
- 1.0, 1.1 and 1.2; heart-beats 10000,10000
- Login
- none (guest), or guest/guest, sonda/sondahub, viewer/viewer
Each WebSocket connection gets a broker of its own, already busy: the hub’s activity on amq.topic, a queue per API holding the last minute of it, an orders queue that takes orders through their life, and an rpc queue that answers. Over TCP the bridge serves STOMP on the same broker as AMQP.
import { Client } from '@stomp/stompjs'
const client = new Client({ brokerURL: 'wss://api.sondahub.com/stomp' })
client.onConnect = () => {
client.subscribe('/topic/fleet.telemetry', (m) => console.log(JSON.parse(m.body)))
client.publish({ destination: '/queue/orders', body: JSON.stringify({ customer_id: 7, total: 42.5 }) })
}
client.activate()
CONNECT
accept-version:1.2
host:sondahub
heart-beat:10000,10000
^@
SUBSCRIBE
id:0
destination:/topic/fleet.telemetry
ack:auto
^@
SEND
destination:/queue/orders
content-type:application/json
receipt:1
{"customer_id":7,"total":42.5}^@
In LockFlare Sonda: a STOMP item pointed at localhost:61713 with the bridge running — or a WebSocket request to wss://api.sondahub.com/stomp, then each frame as a message of its own, CONNECT first.
Destinations
| Destination | What it does |
|---|---|
| /queue/name | SEND to the queue (declared if it is not there); SUBSCRIBE reads it — store, fleet and the other API queues, orders, rpc, yours. |
| /amq/queue/name | The same, but the queue must exist: no declaring. |
| /topic/key | SEND publishes to amq.topic with the key; SUBSCRIBE binds a queue of its own with the key as a pattern — /topic/fleet.telemetry, /topic/store.*, /topic/#. |
| /exchange/name/key | SEND publishes to the exchange with the key; SUBSCRIBE binds a queue of its own to the exchange with the key. |
| /temp-queue/name | In reply-to: a private reply queue, made when first used; the replies arrive with subscription:/temp-queue/name. The reply-to the other side sees is /reply-queue/…. |
What is there from the start: the queues store, fleet, bank, social, helpdesk, flights, identity, orders, orders.dead, rpc, and on /topic/ the routing keys store.orders, store.inventory, fleet.telemetry, fleet.devices, fleet.alerts, bank.fx and the rest — all of them.
Messages
SUBSCRIBE with ack:auto (the default), client (an ACK covers the messages before it on that subscription) or client-individual, and prefetch-count to hold the rest back until you ACK. NACK requeues — the message comes again with redelivered:true — or, with requeue:false, dead-letters it when its queue has a dead-letter exchange. Every frame takes a receipt header; BEGIN, COMMIT and ABORT group SENDs and ACKs; DISCONNECT with a receipt closes cleanly.
| MESSAGE header | What it says |
|---|---|
| subscription, destination, message-id | Which subscription, where the message was published (/topic/store.orders, /queue/name, /exchange/name/key), and its id. |
| ack | On a client or client-individual subscription (STOMP 1.2): the id to ACK or NACK it by. |
| redelivered | true when it was requeued and comes again. |
| content-type, content-length | As published. |
| correlation-id, reply-to, expiration, persistent, priority, amqp-message-id, timestamp, type, user-id, app-id | The AMQP properties, when the message has them. |
| anything else | The message’s own headers. |
A SEND’s own headers travel with the message as headers, and its content-type, correlation-id, reply-to, expiration, persistent and priority as the AMQP properties an AMQP consumer reads.
Orders and RPC
SEND an order to /queue/orders and watch /topic/store.orders: paid two seconds later, shipped at five, delivered at nine. SEND {"method":"store.getProduct","params":{"id":1}} to /queue/rpc with reply-to:/temp-queue/answers, and the answer arrives on the subscription /temp-queue/answers with your correlation-id.
Users
| User | May |
|---|---|
| guest password guest | Everything: declare, bind, publish, consume, delete. The user every client tries first. |
| sonda password sondahub | Everything: declare, bind, publish, consume, delete. |
| viewer password viewer | Reads: consume, get, declare a server-named queue and bind it. Publishing and declaring named queues or exchanges are refused with 403 ACCESS_REFUSED. |
| Anyone else or a wrong password | AMQP: connection.close 403 ACCESS_REFUSED, as RabbitMQ answers. STOMP: an ERROR frame, then the connection closes. |
Questions
Does it need the bridge?
Not over WebSocket: connect to wss://api.sondahub.com/stomp with the subprotocol v12.stomp (or v11.stomp, v10.stomp) and send CONNECT. Over TCP, yes: node bridge.mjs amqp opens localhost:61713, on the same broker as AMQP.
Do my messages reach other people?
No. Over WebSocket each connection has a broker of its own: what you send reaches your own subscriptions. Through the bridge, the clients of one bridge share one broker — STOMP and AMQP alike — and nobody else sees it.
Which clients work?
Any STOMP 1.0, 1.1 or 1.2 client — over WebSocket, or over TCP through the bridge. The destinations are RabbitMQ’s, so code written for RabbitMQ’s STOMP plugin points here unchanged.