PHPackages                             hermod/laravel-wamp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. hermod/laravel-wamp

ActiveLibrary[HTTP &amp; Networking](/categories/http)

hermod/laravel-wamp
===================

A modern WAMP client for Laravel 12+

v1.0.2(1mo ago)111↓100%MITPHPPHP ^8.2

Since Apr 18Pushed 1mo agoCompare

[ Source](https://github.com/sparrinellodev/hermod)[ Packagist](https://packagist.org/packages/hermod/laravel-wamp)[ RSS](/packages/hermod-laravel-wamp/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (9)Versions (10)Used By (0)

Hermod — WAMP Client for Laravel
================================

[](#hermod--wamp-client-for-laravel)

[![Latest Version](https://camo.githubusercontent.com/cabedd1a01874074f1ace5e1160c64489255efe1652afeca5e45dc3ce892a0fb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6865726d6f642f6c61726176656c2d77616d702e737667)](https://packagist.org/packages/hermod/laravel-wamp)[![PHP Version](https://camo.githubusercontent.com/1f50a15cf6d3235669fea56b3be954a43721e9606eb8ce019b19ab14c60f558e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6865726d6f642f6c61726176656c2d77616d702e737667)](https://packagist.org/packages/hermod/laravel-wamp)[![License](https://camo.githubusercontent.com/2f2e57c653ec15953c51771561448ce38d666e2af5765778de05292a04c853da/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6865726d6f642f6c61726176656c2d77616d702e737667)](LICENSE.md)

Hermod is a modern WAMP v2 client for Laravel 12+, built on AMPHP v3 and PHP Fibers. Born as an actively maintained alternative to Thruway, it supports RPC (Caller/Callee) and PubSub with JSON serialization, MessagePack, and CBOR.

> **In Norse mythology, Hermod is the messenger of the gods — the one who carries messages between realms.**

---

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 12.x+
- A WAMP v2 router (e.g., [Crossbar.io](https://crossbar.io))

---

Installation
------------

[](#installation)

```
composer require hermod/laravel-wamp
```

Publish the configuration:

```
php artisan vendor:publish --tag=hermod-config
```

---

Configuration
-------------

[](#configuration)

Add the variables to your `.env`:

```
# Connection
WAMP_URL=ws://localhost:8080/ws
WAMP_REALM=realm1
WAMP_SERIALIZER=json

# Authentication (anonymous by default)
WAMP_AUTH_METHOD=anonymous

# Automatic reconnect
WAMP_RECONNECT=true
WAMP_RECONNECT_MAX=5
WAMP_RECONNECT_DELAY=1
WAMP_RECONNECT_MAX_DELAY=30
WAMP_RECONNECT_MULTIPLIER=2

# Heartbeat
WAMP_HEARTBEAT=true
WAMP_HEARTBEAT_INTERVAL=30
```

### Ticket Authentication

[](#ticket-authentication)

```
WAMP_AUTH_METHOD=ticket
WAMP_AUTH_ID=myuser
WAMP_AUTH_TICKET=my-secret-token
```

### Authentication with WAMP-CRA

[](#authentication-with-wamp-cra)

```
WAMP_AUTH_METHOD=wampcra
WAMP_AUTH_ID=myuser
WAMP_AUTH_SECRET=my-secret
```

### Multiple connections in `config/hermod.php`

[](#multiple-connections-in-confighermodphp)

```
'connections' => [

    'default' => [
        'transport'  => 'websocket',
        'url'        => env('WAMP_URL', 'ws://localhost:8080/ws'),
        'realm'      => 'realm1',
        'serializer' => 'json',
        'auth'       => ['method' => 'anonymous'],
        'reconnect'  => ['enabled' => true, 'max_attempts' => 5],
        'heartbeat'  => ['enabled' => true, 'interval' => 30],
    ],

    'local_tcp' => [
        'transport'  => 'rawsocket',
        'url'        => 'tcp://localhost:8081',
        'realm'      => 'realm1',
        'serializer' => 'msgpack',
        'auth'       => ['method' => 'anonymous'],
        'reconnect'  => ['enabled' => true, 'max_attempts' => 5],
        'heartbeat'  => ['enabled' => true, 'interval' => 30],
    ],

    'local_unix' => [
        'transport'  => 'rawsocket',
        'url'        => 'unix:///var/run/crossbar/router.sock',
        'realm'      => 'realm1',
        'serializer' => 'cbor',
        'auth'       => ['method' => 'anonymous'],
        'reconnect'  => ['enabled' => true, 'max_attempts' => 5],
        'heartbeat'  => ['enabled' => true, 'interval' => 30],
    ],

    'secure' => [
        'transport'  => 'websocket',
        'url'        => env('WAMP_SECURE_URL', 'wss://router.example.com/ws'),
        'realm'      => 'secure_realm',
        'serializer' => 'cbor',
        'auth'       => [
            'method' => 'wampcra',
            'authid' => env('WAMP_AUTH_ID'),
            'secret' => env('WAMP_AUTH_SECRET'),
        ],
        'reconnect'  => ['enabled' => true, 'max_attempts' => 10],
        'heartbeat'  => ['enabled' => true, 'interval' => 20],
    ],

],
```

---

Usage Examples
--------------

[](#usage-examples)

### RPC — Procedure Registration (Callee)

[](#rpc--procedure-registration-callee)

#### Without Authentication (Anonymous)

[](#without-authentication-anonymous)

In your `AppServiceProvider`:

```
use Hermod\Laravel\Events\WampServeStarted;
use Illuminate\Support\Facades\Event;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        Event::listen(WampServeStarted::class, function (WampServeStarted $event) {

            // Simple procedure — add two numbers
            $event->client->register('com.myapp.somma', function (array $args): int {
                return $args[0] + $args[1];
            });

            // Procedure with kwargs — personalized greeting
            $event->client->register('com.myapp.saluta', function (array $args, array $kwargs): string {
                $nome  = $kwargs['nome']  ?? 'Utente';
                $titolo = $kwargs['titolo'] ?? '';
                return "Ciao, {$titolo} {$nome}!";
            });

            // Procedure with access to the Laravel DB
            $event->client->register('com.myapp.utente.trova', function (array $args): array {
                $user = \App\Models\User::find($args[0]);
                return $user?->toArray() ?? [];
            });

            // Procedure with error handling
            $event->client->register('com.myapp.divisione', function (array $args): float {
                if ($args[1] === 0) {
                    throw new \InvalidArgumentException('Divisione per zero non consentita.');
                }
                return $args[0] / $args[1];
            });

        });
    }
}
```

Start the worker:

```
php artisan wamp:serve
```

#### With Ticket Authentication

[](#with-ticket-authentication)

```
WAMP_AUTH_METHOD=ticket
WAMP_AUTH_ID=backend-service
WAMP_AUTH_TICKET=supersecrettoken123
```

The `AppServiceProvider` remains identical — authentication is transparent.

```
php artisan wamp:serve
# The client will automatically authenticate with the configured ticket
```

#### With WAMP-CRA authentication

[](#with-wamp-cra-authentication)

```
WAMP_AUTH_METHOD=wampcra
WAMP_AUTH_ID=backend-service
WAMP_AUTH_SECRET=my-hmac-secret
```

```
php artisan wamp:serve
# The client will automatically calculate the HMAC-SHA256 signature
```

#### With specific connection

[](#with-specific-connection)

```
php artisan wamp:serve --connection=secure
```

---

### RPC — Procedure Call (Caller)

[](#rpc--procedure-call-caller)

#### Synchronous call

[](#synchronous-call)

```
use Hermod\Laravel\Facades\Wamp;

// In a controller, job, command, etc.
Wamp::connect();

// Call with positional arguments
$somma = Wamp::call('com.myapp.somma', [3, 5]);
// → 8

// Call with kwargs
$saluto = Wamp::call('com.myapp.saluta', [], ['nome' => 'Mario', 'titolo' => 'Dr.']);
// → "Ciao, Dr. Mario!"

// Call with error handling
try {
    $risultato = Wamp::call('com.myapp.divisione', [10, 0]);
} catch (\Hermod\Exceptions\RpcException $e) {
    Log::error("Errore RPC: {$e->getMessage()}", ['wamp_error' => $e->wampError]);
}

Wamp::disconnect();
```

#### Asynchronous call

[](#asynchronous-call)

```
use Hermod\Laravel\Facades\Wamp;
use function Amp\Future\await;

Wamp::connect();

// Single asynchronous call
$future = Wamp::callAsync('com.myapp.somma', [10, 20]);
$result = $future->await();
// → 30

// Parallel calls — executed simultaneously
$futures = [
    'somma'   => Wamp::callAsync('com.myapp.somma',    [1, 2]),
    'saluto'  => Wamp::callAsync('com.myapp.saluta',   [], ['nome' => 'Mario']),
    'utente'  => Wamp::callAsync('com.myapp.utente.trova', [42]),
];

$risultati = await($futures);
// $risultati['somma']  → 3
// $risultati['saluto'] → "Ciao, Mario!"
// $risultati['utente'] → ['id' => 42, 'name' => '...']

Wamp::disconnect();
```

#### In a Laravel Route

[](#in-a-laravel-route)

```
use Hermod\Laravel\Facades\Wamp;
use Illuminate\Support\Facades\Route;

Route::get('/calcola/{a}/{b}', function (int $a, int $b) {
    Wamp::connect();
    $result = Wamp::call('com.myapp.somma', [$a, $b]);
    Wamp::disconnect();
    return response()->json(['risultato' => $result]);
});

Route::get('/utente/{id}', function (int $id) {
    Wamp::connect();
    $utente = Wamp::call('com.myapp.utente.trova', [$id]);
    Wamp::disconnect();

    if (empty($utente)) {
        return response()->json(['error' => 'Utente non trovato'], 404);
    }

    return response()->json($utente);
});
```

#### From terminal (debug)

[](#from-terminal-debug)

```
# Call with positional arguments
php artisan wamp:call com.myapp.somma 3 5

# Calling with kwargs in JSON
php artisan wamp:call com.myapp.saluta --kwargs='{"nome":"Mario","titolo":"Dr."}'

# Call on specific connection
php artisan wamp:call com.myapp.somma 10 20 --connection=secure

# Output atteso:
# ✓ Risultato (12.5ms):
# 30
```

---

### PubSub — Publisher

[](#pubsub--publisher)

#### Fire and Forget Publication

[](#fire-and-forget-publication)

```
use Hermod\Laravel\Facades\Wamp;

Wamp::connect();

// Positional array → args
Wamp::publish('com.myapp.notifiche', ['messaggio importante']);

// Associative array → kwargs automatically
Wamp::publish('com.myapp.ordini', ['ordine_id' => 123, 'stato' => 'spedito']);

// Args and kwargs combined
Wamp::publish('com.myapp.eventi', [1, 2, 3], ['extra' => 'info']);

Wamp::disconnect();
```

#### Publication with acknowledgement

[](#publication-with-acknowledgement)

```
use Hermod\Laravel\Facades\Wamp;

Wamp::connect();

// Waiting for PUBLISHED confirmation from the router
$publicationId = Wamp::publishWithAck(
    'com.myapp.notifiche',
    ['messaggio' => 'Ordine confermato!']
)->await();

Log::info("Messaggio pubblicato", ['publication_id' => $publicationId]);

Wamp::disconnect();
```

#### From a Laravel Job

[](#from-a-laravel-job)

```
namespace App\Jobs;

use Hermod\Laravel\Facades\Wamp;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class NotificaOrdineSpe­dito implements ShouldQueue
{
    use Queueable;

    public function __construct(
        private readonly int    $ordineId,
        private readonly string $corriere,
    ) {}

    public function handle(): void
    {
        Wamp::connect();

        Wamp::publish('com.myapp.ordini.spediti', [], [
            'ordine_id' => $this->ordineId,
            'corriere'  => $this->corriere,
            'timestamp' => now()->toISOString(),
        ]);

        Wamp::disconnect();
    }
}
```

#### Da un Observer Eloquent

[](#da-un-observer-eloquent)

```
namespace App\Observers;

use App\Models\Ordine;
use Hermod\Laravel\Facades\Wamp;

class OrdineObserver
{
    public function updated(Ordine $ordine): void
    {
        if ($ordine->isDirty('stato')) {
            Wamp::connect();

            Wamp::publish('com.myapp.ordini.aggiornati', [], [
                'ordine_id'  => $ordine->id,
                'stato_nuovo' => $ordine->stato,
                'stato_vecchio' => $ordine->getOriginal('stato'),
            ]);

            Wamp::disconnect();
        }
    }
}
```

---

### PubSub — Subscriber

[](#pubsub--subscriber)

#### Subscribing to a topic

[](#subscribing-to-a-topic)

In your `AppServiceProvider`:

```
use Hermod\Laravel\Events\WampServeStarted;

Event::listen(WampServeStarted::class, function (WampServeStarted $event) {

    // Simple subscription
    $event->client->subscribe('com.myapp.notifiche', function (array $args, array $kwargs): void {
        Log::info('Notifica ricevuta', [
            'args'   => $args,
            'kwargs' => $kwargs,
        ]);
    });

    // Subscription with business logic
    $event->client->subscribe('com.myapp.ordini.spediti', function (array $args, array $kwargs): void {
        $ordineId = $kwargs['ordine_id'] ?? null;
        $corriere = $kwargs['corriere']  ?? 'sconosciuto';

        if ($ordineId) {
            \App\Models\Ordine::find($ordineId)?->update([
                'notifica_spedizione_inviata' => true,
            ]);

            Log::info("Ordine {$ordineId} spedito con {$corriere}");
        }
    });

    // Dynamic subscription and unsubscription
    $subscription = $event->client->subscribe('com.myapp.temporaneo', function (array $args): void {
        Log::debug('Evento temporaneo ricevuto', $args);
    });

    // You can unsubscribe later
    // $event->client->unsubscribeById($subscription);

});
```

Start the worker subscriber:

```
php artisan wamp:serve
```

#### Automatic Laravel Event

[](#automatic-laravel-event)

Every WAMP `EVENT` received automatically dispatches a Laravel event, without having to register an explicit handler:

```
use Hermod\Laravel\Events\WampEventReceived;

// In EventServiceProvider or AppServiceProvider
Event::listen(WampEventReceived::class, function (WampEventReceived $event): void {

    // Filter by topic
    match ($event->topic) {
        'com.myapp.ordini.spediti' => dispatch(new \App\Jobs\ProcessaSpedizione(
            ordineId: $event->kwargs['ordine_id'],
        )),
        'com.myapp.notifiche' => \App\Models\Notifica::create([
            'contenuto' => $event->args[0] ?? '',
            'ricevuta_at' => now(),
        ]),
        default => Log::debug("Evento WAMP non gestito: {$event->topic}"),
    };

});
```

---

### Combining RPC and PubSub in the same worker

[](#combining-rpc-and-pubsub-in-the-same-worker)

```
use Hermod\Laravel\Events\WampServeStarted;

Event::listen(WampServeStarted::class, function (WampServeStarted $event) {

    // ── RPC Procedures ────────────────────────────────────
    $event->client->register('com.myapp.utente.crea', function (array $args, array $kwargs): array {
        $user = \App\Models\User::create([
            'name'  => $kwargs['nome'],
            'email' => $kwargs['email'],
        ]);

        // Publish event after user creation
        $event->client->publish('com.myapp.utenti.creati', [], [
            'user_id' => $user->id,
            'email'   => $user->email,
        ]);

        return $user->toArray();
    });

    $event->client->register('com.myapp.statistiche', function (): array {
        return [
            'utenti_totali' => \App\Models\User::count(),
            'ordini_attivi' => \App\Models\Ordine::where('stato', 'attivo')->count(),
        ];
    });

    // ── PubSub Subscriptions ──────────────────────────────
    $event->client->subscribe('com.myapp.cache.invalida', function (array $args, array $kwargs): void {
        $chiave = $kwargs['chiave'] ?? '*';
        \Illuminate\Support\Facades\Cache::forget($chiave);
        Log::info("Cache invalidata per chiave: {$chiave}");
    });

    $event->client->subscribe('com.myapp.broadcast', function (array $args, array $kwargs): void {
        // Forward the WAMP event as a Laravel broadcast event
        \Illuminate\Support\Facades\Broadcast::on('general')
            ->event(new \App\Events\WampBroadcast($kwargs))
            ->sendNow();
    });

});
```

---

### Automatic Reconnect

[](#automatic-reconnect)

Reconnect is configured in `config/hermod.php` and works transparently during `listen()`. When the connection drops, Hermod:

1. Detects the disconnection in the listening loop
2. Waits for the initial delay (default: 1 second)
3. Attempts to reconnect
4. If it fails, it applies exponential backoff (1s → 2s → 4s → 8s → 16s → max 30s)
5. After a successful reconnect, it automatically re-registers all procedures and subscriptions

```
// Custom configuration for critical environment
// config/hermod.php
'reconnect' => [
    'enabled'      => true,
    'max_attempts' => 10,      // maximum 10 attempts
    'base_delay'   => 0.5,     // starts from 0.5 seconds
    'max_delay'    => 60.0,    // 60-second cap
    'multiplier'   => 2.0,     // doubles with every failure
],
```

---

Artisan Commands
----------------

[](#artisan-commands)

```
# Start a WAMP worker (Callee + Subscriber)
php artisan wamp:serve
php artisan wamp:serve --connection=secure
php artisan wamp:serve --realm=myrealm
php artisan wamp:serve --serializer=cbor

# Make an RPC call from the terminal
php artisan wamp:call com.myapp.somma 3 5
php artisan wamp:call com.myapp.saluta --kwargs='{"nome":"Mario"}'
php artisan wamp:call com.myapp.somma 10 20 --connection=secure
```

---

Serializers
-----------

[](#serializers)

DriverSubprotocolStatoNote.env`json``wamp.2.json`✅ StabileDefault, nessuna dipendenza extraWAMP\_SERIALIZER=json`cbor``wamp.2.cbor`✅ StabileRichiede `spomky-labs/cbor-php`WAMP\_SERIALIZER=cbor`msgpack``wamp.2.msgpack`✅ StabileRichiede `rybakit/msgpack`WAMP\_SERIALIZER=msgpack---

Authentication
--------------

[](#authentication)

MethodUse caseRequired configuration`anonymous`Local development, closed networksnone`ticket`API key, static JWT`authid`, `ticket``wampcra`Secure authentication with HMAC`authid`, `secret`---

Roadmap
-------

[](#roadmap)

VersionContent**v0.1**RPC Core — Caller, Callee, JSON, CBOR ✅**v0.2**PubSub — Publisher, Subscriber ✅**v0.3**Auth — WAMP-CRA, Ticket, Reconnect ✅**v1.0**MessagePack, RawSocket, Complete documentation ✅---

Testing
-------

[](#testing)

```
# All tests
./vendor/bin/pest

# With coverage
./vendor/bin/pest --coverage --min=80

# For specific suite
./vendor/bin/pest --filter=Auth
./vendor/bin/pest --filter=Reconnect
./vendor/bin/pest --filter=PubSub
./vendor/bin/pest --filter=Rpc
./vendor/bin/pest --filter=RawSocket
./vendor/bin/pest --filter=Msgpack
```

---

Contribute
----------

[](#contribute)

Read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

---

License
-------

[](#license)

Hermod is open source software released under the \[MIT\] License (LICENSE.md).

```

```

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

9

Last Release

44d ago

Major Versions

v0.3.0 → v1.0.02026-04-26

### Community

Maintainers

![](https://www.gravatar.com/avatar/3be9422e7e8774eb37eb7c1632d1fb94b1d41aed6ca9dc875e3e3dc895985422?d=identicon)[sparrinellodev](/maintainers/sparrinellodev)

---

Top Contributors

[![sparrinellodev](https://avatars.githubusercontent.com/u/275711846?v=4)](https://github.com/sparrinellodev "sparrinellodev (12 commits)")

---

Tags

laravelrpcwebsocketamphpWAMPpubsub

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/hermod-laravel-wamp/health.svg)

```
[![Health](https://phpackages.com/badges/hermod-laravel-wamp/health.svg)](https://phpackages.com/packages/hermod-laravel-wamp)
```

###  Alternatives

[amphp/websocket-client

Async WebSocket client for PHP based on Amp.

1624.3M53](/packages/amphp-websocket-client)[amphp/websocket

Shared code for websocket servers and clients.

464.4M10](/packages/amphp-websocket)[vinelab/minion

A Simple WAMP (Web Application Messaging Protocol) server and command line tool

1276.5k](/packages/vinelab-minion)[basement-chat/basement-chat

Add a real-time chat widget to your Laravel application.

4984.0k](/packages/basement-chat-basement-chat)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
