Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Crossbar Http Publisher Bundle Laravel Package

facile-it/crossbar-http-publisher-bundle

Symfony bundle for publishing WAMP events to a Crossbar router over HTTP, letting PHP apps push real-time messages without maintaining a persistent WebSocket connection. Configure the publisher through Symfony services and start broadcasting quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Know what you're actually buying. Crossbar is a WAMP router; its HTTP Publisher is a plain POST endpoint that accepts a JSON body (topic, args, kwargs) plus an HMAC-SHA256 signature of the raw body keyed with a shared secret. Subscribers get the event over their WAMP session. The bundle's entire job is: build that body, sign it, POST it, tell you if it worked. There is no socket, no handshake, no subscription management.
  • This is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no auto-discovery, no config publishing, and it depends on Symfony DI/Config components. In a Laravel app you should almost never install the bundle itself — install the underlying client (facile-it/crossbar-http-publisher, PSR-18/PSR-7 based) or vendor the ~20 lines of request-building logic. Read the bundle's DependencyInjection/Configuration.php first: it is the authoritative list of knobs (endpoint URL, key, secret, and likely HTTP client/timeout options). Then read the publisher class — that is the whole implementation.
  • Check your Guzzle major before you start. As of 2.1.0 the client supports Guzzle 7 and deprecates Guzzle 5 & 6. Laravel 7+ ships Guzzle 7 by default, so a modern app is fine; Laravel 5.x/6 apps (or anything with guzzlehttp/guzzle: ^6.0 pinned by another dependency) will resolve to the deprecated path — pin ^2.1 and plan the bump, or skip the package entirely and use the vendored snippet below. Note Guzzle 7 also raises the PHP floor (7.2.5+).
  • Provision the router side first. In your Crossbar config.json, add a web transport with a paths entry of type: publisher, a key, and a secret. Until that exists, every publish attempt is a 404/403 and you'll waste an hour debugging client code.
  • First use case. Publish a domain event from a Laravel event listener to browser/webview clients already connected via WAMP — e.g. App\Events\OrderShipped → publish to com.example.orders.shipped with the order id. Configure via env (CROSSBAR_PUBLISH_URL, CROSSBAR_KEY, CROSSBAR_SECRET), bind a small CrossbarPublisher wrapper in a service provider, and publish from a queued listener.
$body = json_encode(['topic' => $topic, 'args' => [$payload]], JSON_UNESCAPED_SLASHES);
Http::withHeaders(['X-Crossbar-Signature' => hash_hmac('sha256', $body, $secret)])
    ->withBody($body, 'application/json')
    ->post($endpoint);

Implementation Patterns

  • Wrap it, don't sprinkle it. One CrossbarPublisher class with publish(string $topic, array $args = [], array $kwargs = []). Inject it; never call Http:: from controllers or models. This is also your seam for tests.
  • Always publish from a queued listener/job. The publish is a synchronous outbound HTTP call; doing it in the request cycle adds the router's latency (and failure modes) to your user's response. implements ShouldQueue on the listener is the standard pattern.
  • Pick a topic taxonomy early and treat it as public API: {org}.{domain}.{entity}.{event} (acme.billing.invoice.paid). Subscribers hard-code these; renaming later is a breaking change.
  • Prefer kwargs for named data, args for positional. Most PHP-side consumers want kwargs (associative) because it survives serialization better and reads well in JS: payload.items[0].sku.
  • Keep payloads small and JSON-safe. No Eloquent models, no resources, no Carbon objects — pass a plain array / DTO you've explicitly ->toArray()'d. Publish identifiers, and let subscribers re-fetch if they need the full record.
  • Fan-out to multiple topics by looping the publisher; it's cheap. There's no batch endpoint on the Crossbar side.
  • Retries with a cap. Wrap in retry(3, 200) or a queued job's $tries/backoff. The publish is idempotent-ish for subscribers but not deduplicated by the router — a retry means subscribers may see the event twice. Design consumers tolerantly (event id in the payload, idempotent handlers).
  • Give it a configured Guzzle 7 client, not the defaults. On 2.1.0 you can hand the publisher a GuzzleHttp\Client (or any PSR-18 client). Build one in your container binding with timeout, connect_timeout, and http_errors => false, and pass that — it keeps retry/timeout policy in one place instead of scattered across call sites.
  • Testing. Fake your wrapper ($this->mock(CrossbarPublisher::class)), or if you inlined Http::, use Http::fake() and assert on the signature header and raw body — that's the part that actually breaks in production.
  • Observability. Log topic, payload size, status code, and latency. Never log the secret or the full signature.

Gotchas and Tips

  • Sign the exact bytes you send. The HMAC is over the raw request body. If you compute the signature on one json_encode() output and then let a client re-serialize (or you json_encode with different flags/ordering — JSON_UNESCAPED_SLASHES, JSON_PRESERVE_ZERO_FRACTION matter), the signature won't match and Crossbar returns a 403 with a body you'll misread as an auth problem. Build the string once, sign it, send that same string.
  • Check the response body, not just the status. Crossbar's HTTP publisher returns structured JSON; a 200 is not a universal success signal across versions/configs. Parse and assert on the expected field, and log the body on unexpected responses.
  • It's fire-and-forget pub/sub. No subscriber = silently dropped. No ack, no ordering guarantee across concurrent publishes, no persistence. If you need delivery guarantees, this is the wrong transport — you want a queue (Redis/SQS) plus a WAMP bridge, or a WAMP client with proper session handling.
  • Secrets in env, not in a cached config file. Anything resembling Symfony's config dump or Laravel's config:cache will bake the secret into a file; read it via env() at the boundary only.
  • Timeouts will bite you. Guzzle's default has no read timeout, which can hang a queue worker indefinitely if the router is unreachable. Set explicit connect_timeout and timeout (2–5s) on the client you inject. Guzzle 7 also defaults http_errors to true, so a 4xx/5xx throws RequestException rather than returning the response — flip it off if you want to inspect Crossbar's error body.
  • Watch for the impending v3. 2.1.0 deprecates Guzzle 5 & 6 — it doesn't remove them, but the next major will. If anything in your lockfile transitively pins Guzzle 6, you're on a branch that dies at the next release. Verify with composer why guzzlehttp/guzzle before adopting, and pin ^2.1.
  • Don't extend the publisher — decorate it. The bundle's publisher is a thin, likely-final class. If you need custom headers, a different PSR-18 client, or payload shaping, wrap it.
  • Debug with curl, not with your app. Capture the raw body + signature from a failing call, then replay: curl -X POST $URL -H "X-Crossbar-Signature: $SIG" -H 'Content-Type: application/json' --data-binary @body.json. That isolates client bugs from config bugs instantly.
  • Small userbase (10 stars, 0 dependents) — pin the version and read the source. Treat it as a reference implementation: the protocol is stable and documented, the wrapper is trivial, and you'll be better served by owning ~30 lines than by depending on a Symfony-shaped abstraction you have to fight into Laravel. The 2.1.0 Guzzle 7 bump is the main reason to reach for the package at all right now; the deprecation notice is the main reason to keep your wrapper thin enough to swap out.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource