#!/usr/bin/env bash set -euo pipefail # --- Config (override via env or flags) --- RMQ_USER="${RMQ_USER:-admin}" RMQ_PASS="${RMQ_PASS:-change_me}" RMQ_HOST="${RMQ_HOST:-localhost}" RMQ_PORT="${RMQ_PORT:-15672}" VHOST="${VHOST:-app}" # Mode A: read from a queue (default) QUEUE="${QUEUE:-queue1}" # Mode B: bind temp queue to an exchange + routing key and consume from it EXCHANGE="${EXCHANGE:-}" # e.g. "amq.topic" or "my-exchange". Leave empty to skip binding mode. ROUTING_KEY="${ROUTING_KEY:-#}" # pattern for topic/direct, default is catch-all "#" # Polling interval when no messages SLEEP_SECS="${SLEEP_SECS:-1}" # Pretty-print with jq if available USE_JQ="${USE_JQ:-auto}" # auto|yes|no USE_COLOR="${USE_COLOR:-yes}" # yes|no -> 'yes' forces color with jq -C # --- Helpers --- api() { local method="$1"; shift local path="$1"; shift local data="${1:-}" if [[ -n "$data" ]]; then curl -sS -u "$RMQ_USER:$RMQ_PASS" -H "content-type:application/json" -X "$method" "http://$RMQ_HOST:$RMQ_PORT$path" -d "$data" else curl -sS -u "$RMQ_USER:$RMQ_PASS" -H "content-type:application/json" -X "$method" "http://$RMQ_HOST:$RMQ_PORT$path" fi } has_jq() { command -v jq >/dev/null 2>&1; } # pretty(): colorized JSON when jq is present. We **force** color with -C so it survives pipes/subshells. pretty() { if [[ "$USE_JQ" == "yes" ]] || { [[ "$USE_JQ" == "auto" ]] && has_jq; }; then if [[ "$USE_COLOR" == "yes" ]]; then jq -C . else jq . fi else cat fi } urlenc() { # vhost is simple ("app"), so we skip full encoding, but keep function for completeness printf '%s' "$1" | sed -e 's, ,%20,g' -e 's,/,%2F,g' } cleanup_queue="" cleanup() { if [[ -n "$cleanup_queue" ]]; then echo "Cleaning up temp queue: $cleanup_queue" api DELETE "/api/queues/$(urlenc "$VHOST")/$cleanup_queue" >/dev/null || true fi } trap cleanup EXIT # --- Setup: decide queue source --- if [[ -n "$EXCHANGE" ]]; then # Create a temp, exclusive, auto-delete queue and bind to exchange cleanup_queue="tmp.$(hostname -s).$$.$(date +%s)" echo "Declaring temp queue: $cleanup_queue (exclusive, auto-delete)" api PUT "/api/queues/$(urlenc "$VHOST")/$cleanup_queue" '{ "auto_delete": true, "durable": false, "arguments": {}, "exclusive": true }' >/dev/null echo "Binding temp queue to exchange '$EXCHANGE' with routing key '$ROUTING_KEY'" api POST "/api/bindings/$(urlenc "$VHOST")/e/$EXCHANGE/q/$cleanup_queue" "{ \"routing_key\": \"$ROUTING_KEY\", \"arguments\": {} }" >/dev/null QUEUE="$cleanup_queue" echo "Consuming from bound temp queue: $QUEUE" else echo "Consuming directly from queue: $QUEUE (vhost: $VHOST)" fi echo "Press Ctrl+C to stop." # --- Consume loop --- while :; do RESP="$(api POST "/api/queues/$(urlenc "$VHOST")/$QUEUE/get" '{ "count": 1, "ackmode": "ack_requeue_false", "encoding": "auto", "truncate": 1000000 }')" # Empty array => no messages if [[ "$RESP" == "[]" ]] || [[ -z "$RESP" ]]; then sleep "$SLEEP_SECS" continue fi # Print one-by-one (the API returns an array) if has_jq && { [[ "$USE_JQ" == "yes" ]] || [[ "$USE_JQ" == "auto" ]]; }; then echo "$RESP" | jq -c '.[]' | while read -r item; do # Extract fields (raw to avoid extra quotes) payload=$(printf '%s' "$item" | jq -r '.payload') rk=$(printf '%s' "$item" | jq -r '.routing_key') ex=$(printf '%s' "$item" | jq -r '.exchange') echo "-----" echo "exchange: ${ex:-\"\"}" echo "routing_key: $rk" echo "payload:" # Smart payload handling: # 1) If payload parses as JSON: # - If it's a JSON string, decode once; if decoded text is JSON, pretty-print it; else print plain text. # - If it's object/array/etc, pretty-print directly. # 2) If payload isn't JSON at all, print as-is. if jq -e . >/dev/null 2>&1 <<<"$payload"; then ptype="$(printf '%s' "$payload" | jq -r 'type')" if [[ "$ptype" == "string" ]]; then decoded="$(printf '%s' "$payload" | jq -r .)" if jq -e . >/dev/null 2>&1 <<<"$decoded"; then printf '%s' "$decoded" | pretty else printf '%s\n' "$decoded" fi else printf '%s' "$payload" | pretty fi else printf '%s\n' "$payload" fi done else # Minimal parsing without jq echo "$RESP" fi done