Skip to content

Commit aa69c4f

Browse files
committed
* broadcaster: refactor from Pusher to AnyCable mode
1 parent 63be3f2 commit aa69c4f

File tree

5 files changed

+42
-67
lines changed

5 files changed

+42
-67
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master
44

5+
## 0.2.0
6+
7+
- Refactor broadcaster to work with AnyCable Echo adapter (Reverb-compatible Echo adapters don't require a custom broadcaster anymore).
8+
59
## 0.1.2
610

711
- Use Reverb env vars as defaults in `anycable:server`.

README.md

Lines changed: 11 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@
22

33
# AnyCable Laravel Broadcaster
44

5-
A Laravel broadcaster implementation to use [AnyCable](https://anycable.io/) as a WebSocket server.
6-
7-
The broadcaster allows you to use AnyCable as a drop-in replacement for Reverb, or Pusher, or whatever is supported by Laravel Echo. By "drop-in", we mean that no client-side changes required to use AnyCable, all you need is to update the server configuration (and, well, launch an AnyCable server).
5+
A Laravel broadcaster implementation to use [AnyCable](https://anycable.io/) as a WebSocket server with Laravel Echo clients. For client-side integration, see [@anycable/echo][] package.
86

97
> [!TIP]
108
> The quickest way to get started with AnyCable server is to use our free managed offering: [plus.anycable.io](https://plus.anycable.io)
119
12-
> [!NOTE]
13-
> AnyCable Laravel support is still in its early days. Please, let us know if anything goes wrong. See also the [limitations](#limitations) section below.
14-
1510
## Requirements
1611

1712
- PHP 8.2+
@@ -57,51 +52,22 @@ That's a minimal configuration, all AnyCable related parameters would be inferre
5752
]
5853
```
5954

60-
Your client-side Echo configuration can stay almost unchanged (in case you used Reverb):
55+
On the client-side, configure Echo to use AnyCable adapter:
6156

6257
```js
6358
import Echo from "laravel-echo";
59+
import { EchoCable } from "@anycable/echo";
6460

65-
// We use Pusher protocol for now
66-
import Pusher from "pusher-js";
67-
window.Pusher = Pusher;
6861

6962
window.Echo = new Echo({
70-
broadcaster: "reverb", // reverb or pusher would work
71-
key: import.meta.env.VITE_REVERB_APP_KEY,
72-
wsHost: import.meta.env.VITE_REVERB_HOST,
73-
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
74-
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
75-
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? "https") === "https",
76-
enabledTransports: ["ws", "wss"],
63+
broadcaster: EchoCable,
64+
cableOptions: {
65+
url: url: import.meta.env.VITE_WEBSOCKET_URL || 'ws://localhost:8080/cable',
66+
},
67+
// other configuration options such as auth, etc
7768
});
7869
```
7970

80-
Just make sure you point to to the AnyCable server (locally it runs on the same host and port as Reverb). You must also **configure AnyCable to use the same app key** as `VITE_REVERB_APP_KEY`:
81-
82-
```sh
83-
anycable-go --pusher-app-key=my-app-key
84-
85-
# or
86-
ANYCABLE_PUSHER_APP_KEY=my-app-key anycable-go
87-
```
88-
89-
To use public channels, make sure you have enabled them in AnyCable:
90-
91-
92-
```sh
93-
anycable-go --public_streams
94-
95-
# or full public mode
96-
anycable-go --public
97-
98-
# or
99-
ANYCABLE_PUBLIC_STREAMS=true anycable-go
100-
101-
# or
102-
ANYCABLE_PUBLIC=true anycable-go
103-
```
104-
10571
## Usage
10672

10773
You can use Laravel's broadcasting features as you normally would:
@@ -143,7 +109,7 @@ php artisan anycable:server -- --public_streams --pusher_app_key=my-app-key
143109

144110
### Private Channels
145111

146-
AnyCable supports private channels. To use them, you need to set the `ANYCABLE_SECRET` environment variable.
112+
AnyCable supports private and presence channels. To use them, you need to set the `ANYCABLE_SECRET` environment variable.
147113

148114
Then, don't forget to add authorization callbacks like this:
149115

@@ -153,14 +119,6 @@ Broadcast::channel('private-channel', function ($user) {
153119
});
154120
```
155121

156-
## Limitations
157-
158-
- Presence channels are not supported yet.
159-
160-
- Only HTTP broadcasting adapter for AnyCable is supported for now.
161-
162-
- Pusher's signing functionality is not supported by AnyCable yet (is it used by Laravel at all?).
163-
164122
## Contributing
165123

166124
Contributions are welcomed! All you need to start developing the project locally is PHP 8.2+, Composer and:
@@ -179,3 +137,5 @@ composer lint
179137
## License
180138

181139
The MIT License (MIT). Please see [License File](LICENSE) for more information.
140+
141+
[@anycable/echo]: https://github.com/anycable/anycable-client/tree/master/packages/echo

src/Broadcasting/AnyCableBroadcaster.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,20 @@ public function __construct(Client $httpClient, array $config)
3838
*/
3939
public function validAuthenticationResponse($request, $result)
4040
{
41-
if (str_starts_with($request->channel_name, 'private') && isset($this->config['secret']) && $this->config['secret']) {
41+
if ((str_starts_with($request->channel_name, 'private-') || str_starts_with($request->channel_name, 'presence-')) && isset($this->config['secret']) && $this->config['secret']) {
4242
$signed_stream_name = $this->client->signStream($request->channel_name);
4343

44-
return ['auth' => $signed_stream_name];
44+
if (str_starts_with($request->channel_name, 'presence-')) {
45+
$user = $this->retrieveUser($request, $request->channel_name);
46+
47+
$broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting')
48+
? $user->getAuthIdentifierForBroadcasting()
49+
: $user->getAuthIdentifier();
50+
51+
return ['signed_stream_name' => $signed_stream_name, 'presence' => array_merge(['id' => $broadcastIdentifier], $result)];
52+
}
53+
54+
return ['signed_stream_name' => $signed_stream_name];
4555
}
4656

4757
return [];
@@ -56,7 +66,7 @@ public function broadcast(array $channels, $event, array $payload = [])
5666
foreach ($channels as $channel) {
5767
$result = $this->client->broadcastEvent($channel, $event, $payload);
5868

59-
if (! $result['success']) {
69+
if ($result['status'] != 201) {
6070
Log::error('AnyCable broadcast failed', [
6171
'channel' => $channel,
6272
'event' => $event,

src/Commands/AnyCableServerCommand.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,30 +212,35 @@ protected function runBinary($binaryPath)
212212
$env = $_ENV;
213213

214214
// Set ANYCABLE_BROADCAST_ADAPTER=http if not set
215-
if (!isset($env['ANYCABLE_BROADCAST_ADAPTER'])) {
215+
if (! isset($env['ANYCABLE_BROADCAST_ADAPTER'])) {
216216
$env['ANYCABLE_BROADCAST_ADAPTER'] = 'http';
217217
}
218218

219219
// Set ANYCABLE_PUSHER_APP_ID to REVERB_APP_ID if not set and the latter exists
220-
if (!isset($env['ANYCABLE_PUSHER_APP_ID']) && isset($env['REVERB_APP_ID'])) {
220+
if (! isset($env['ANYCABLE_PUSHER_APP_ID']) && isset($env['REVERB_APP_ID'])) {
221221
$env['ANYCABLE_PUSHER_APP_ID'] = $env['REVERB_APP_ID'];
222222
}
223223

224224
// Set ANYCABLE_PUSHER_APP_KEY to REVERB_APP_KEY if not set and the latter exists
225-
if (!isset($env['ANYCABLE_PUSHER_APP_KEY']) && isset($env['REVERB_APP_KEY'])) {
225+
if (! isset($env['ANYCABLE_PUSHER_APP_KEY']) && isset($env['REVERB_APP_KEY'])) {
226226
$env['ANYCABLE_PUSHER_APP_KEY'] = $env['REVERB_APP_KEY'];
227227
}
228228

229229
// Set ANYCABLE_PUSHER_SECRET to REVERB_APP_SECRET if not set and the latter exists
230-
if (!isset($env['ANYCABLE_PUSHER_SECRET']) && isset($env['REVERB_APP_SECRET'])) {
230+
if (! isset($env['ANYCABLE_PUSHER_SECRET']) && isset($env['REVERB_APP_SECRET'])) {
231231
$env['ANYCABLE_PUSHER_SECRET'] = $env['REVERB_APP_SECRET'];
232232
}
233233

234234
// Set ANYCABLE_PRESETS to broker if not set
235-
if (!isset($env['ANYCABLE_PRESETS'])) {
235+
if (! isset($env['ANYCABLE_PRESETS'])) {
236236
$env['ANYCABLE_PRESETS'] = 'broker';
237237
}
238238

239+
// Enable whispering by default
240+
if (! isset($env['ANYCABLE_STREAMS_WHISPER'])) {
241+
$env['ANYCABLE_STREAMS_WHISPER'] = 'true';
242+
}
243+
239244
$process = new Process($args, null, $env);
240245
$process->setTimeout(null);
241246
$process->setTty(Process::isTtySupported());

tests/Unit/AnyCableBroadcasterTest.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,16 @@ public function test_valid_authentication_response_for_private_channel()
5959
$result = $broadcaster->validAuthenticationResponse($request, 'user-auth-data');
6060

6161
$this->assertIsArray($result);
62-
$this->assertArrayHasKey('auth', $result);
62+
$this->assertArrayHasKey('signed_stream_name', $result);
6363

64-
// Verify the auth signature is correctly formatted
65-
$auth = $result['auth'];
66-
$this->assertStringContainsString('--', $auth);
64+
$signedName = $result['signed_stream_name'];
65+
$this->assertStringContainsString('--', $signedName);
6766

68-
// Split and verify the signature
69-
[$encoded, $digest] = explode('--', $auth);
67+
[$encoded, $digest] = explode('--', $signedName);
7068

71-
// Verify encoded is valid base64
7269
$decoded = base64_decode($encoded, true);
7370
$this->assertNotFalse($decoded);
7471

75-
// Verify decoded is the original channel name
7672
$this->assertEquals('private-channel', json_decode($decoded));
7773
}
7874

0 commit comments

Comments
 (0)