Skip to content

Commit a120008

Browse files
committed
Merge branch 'Adesin-fr-master'
2 parents f5e65ed + 9d623ef commit a120008

File tree

6 files changed

+5374
-5339
lines changed

6 files changed

+5374
-5339
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ advised to only use this package for non-critical / non-production projects.
2121
In order to use this package, your project needs to meet the following criteria:
2222

2323
- PHP 7.4 or 8.x
24-
- Laravel 6, 7 or 8
24+
- Laravel 6 to 11
2525
- Uses either [bref](https://bref.sh) or [Laravel Vapor](https://vapor.laravel.com) to deploy to AWS
2626
- Has a working queue
2727
- Uses Laravel Mix or any other tool to bundle your assets
@@ -120,6 +120,7 @@ provider:
120120
121121
environment:
122122
# Add these variables
123+
# Please note : in Laravel 11, this setting is now BROADCAST_CONNECTION
123124
BROADCAST_DRIVER: laravel-echo-api-gateway
124125
LARAVEL_ECHO_API_GATEWAY_DYNAMODB_TABLE: !Ref ConnectionsTable
125126
LARAVEL_ECHO_API_GATEWAY_API_ID: !Ref WebsocketsApi
@@ -201,4 +202,19 @@ window.Echo = new Echo({
201202
});
202203
```
203204

205+
You can also enable console output by passing a `debug: true` otpion to your window.Echo intializer :
206+
```js
207+
import Echo from 'laravel-echo';
208+
import {broadcaster} from 'laravel-echo-api-gateway';
209+
210+
window.Echo = new Echo({
211+
broadcaster,
212+
// replace the placeholders
213+
host: 'wss://{api-ip}.execute-api.{region}.amazonaws.com/{stage}',
214+
debug: true
215+
});
216+
```
217+
218+
219+
204220
Lastly, you have to generate your assets by running Laravel Mix. After this step, you should be up and running.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"php": "^8.0|^8.1|^8.2",
2323
"ext-json": "*",
2424
"aws/aws-sdk-php": "^3.308",
25-
"bref/bref": "^1.1",
25+
"bref/bref": "^1.1|^2.0",
2626
"guzzlehttp/guzzle": "^6.3|^7.0",
2727
"laravel/framework": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0"
2828
},

js-src/Websocket.ts

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {Channel} from "./Channel";
2-
import {AxiosResponse} from "axios";
1+
import { AxiosResponse } from "axios";
2+
import axios from 'axios';
3+
import { Channel } from "./Channel";
4+
5+
export type Options = { authEndpoint: string, host: string, bearerToken: string, auth: any, debug: boolean };
36

4-
export type Options = { authEndpoint: string, host: string, bearerToken: string, auth: any };
57
export type MessageBody = { event: string, channel?: string, data: object };
68

79
export class Websocket {
@@ -19,14 +21,20 @@ export class Websocket {
1921

2022
private socketId: string;
2123

24+
private closing = false;
25+
2226
private pingInterval: NodeJS.Timeout;
2327

24-
constructor(options: Options) {
25-
this.options = options;
28+
private connect(host: string): void {
29+
this.options.debug && console.log('Connecting');
2630

27-
this.websocket = new WebSocket(options.host)
31+
this.websocket = new WebSocket(host)
2832

2933
this.websocket.onopen = () => {
34+
this.send({
35+
event: 'whoami',
36+
})
37+
3038
while (this.buffer.length) {
3139
const message = this.buffer[0]
3240

@@ -44,7 +52,7 @@ export class Websocket {
4452
}
4553

4654
if (message.channel) {
47-
console.log(`Received event ${message.event} on channel ${message.channel}`)
55+
this.options.debug && console.log(`Received event ${message.event} on channel ${message.channel}`)
4856

4957
if (this.listeners[message.channel] && this.listeners[message.channel][message.event]) {
5058
this.listeners[message.channel][message.event](message.data)
@@ -56,12 +64,24 @@ export class Websocket {
5664
if (this.internalListeners[message.event]) {
5765
this.internalListeners[message.event](message.data)
5866
}
67+
5968
}
6069

70+
71+
this.websocket.onclose = () => {
72+
if (this.socketId && !this.closing || !this.socketId) {
73+
this.options.debug && console.info('Connection lost, reconnecting...');
74+
setTimeout(() => {
75+
this.socketId = undefined
76+
this.connect(host)
77+
}, 1000);
78+
}
79+
};
80+
6181
this.on('whoami', ({ socket_id: socketId }) => {
6282
this.socketId = socketId
6383

64-
console.log(`just set socketId to ${socketId}`)
84+
this.options.debug && console.log(`just set socketId to ${socketId}`)
6585

6686
while (this.channelBacklog.length) {
6787
const channel = this.channelBacklog[0]
@@ -72,27 +92,32 @@ export class Websocket {
7292
}
7393
})
7494

75-
this.send({
76-
event: 'whoami',
77-
})
7895

7996
// send ping every 60 seconds to keep connection alive
8097
this.pingInterval = setInterval(() => {
81-
console.log('Sending ping')
82-
83-
this.send({
84-
event: 'ping',
85-
})
98+
if (this.websocket.readyState === this.websocket.OPEN) {
99+
this.options.debug && console.log('Sending ping')
100+
this.send({
101+
event: 'ping',
102+
})
103+
}
86104
}, 60 * 1000)
87105

106+
}
107+
108+
constructor(options: Options) {
109+
this.options = options;
110+
111+
this.connect(this.options.host);
112+
88113
return this
89114
}
90115

91116
protected parseMessage(body: string): MessageBody {
92117
try {
93118
return JSON.parse(body)
94119
} catch (error) {
95-
console.error(error)
120+
this.options.debug && console.error(error)
96121

97122
return undefined
98123
}
@@ -115,7 +140,8 @@ export class Websocket {
115140
this.buffer.push(message)
116141
}
117142

118-
close (): void {
143+
close(): void {
144+
this.closing = true
119145
this.internalListeners = {}
120146

121147
clearInterval(this.pingInterval)
@@ -134,7 +160,7 @@ export class Websocket {
134160

135161
private actuallySubscribe(channel: Channel): void {
136162
if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
137-
console.log(`Sending auth request for channel ${channel.name}`)
163+
this.options.debug && console.log(`Sending auth request for channel ${channel.name}`)
138164

139165
if (this.options.bearerToken) {
140166
this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
@@ -146,21 +172,21 @@ export class Websocket {
146172
}, {
147173
headers: this.options.auth.headers || {}
148174
}).then((response: AxiosResponse) => {
149-
console.log(`Subscribing to channels ${channel.name}`)
175+
this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
150176

151177
this.send({
152178
event: 'subscribe',
153179
data: {
154180
channel: channel.name,
155-
... response.data
181+
...response.data
156182
},
157183
})
158184
}).catch((error) => {
159-
console.log(`Auth request for channel ${channel.name} failed`)
160-
console.error(error)
185+
this.options.debug && console.log(`Auth request for channel ${channel.name} failed`)
186+
this.options.debug && console.error(error)
161187
})
162188
} else {
163-
console.log(`Subscribing to channels ${channel.name}`)
189+
this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
164190

165191
this.send({
166192
event: 'subscribe',

js-tests/Connector.test.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import WS from "jest-websocket-mock";
22
import { Connector } from "../js-src/Connector";
33
import { Channel } from "../js-src/Channel";
44

5+
const mockedHost = 'ws://localhost:1234';
6+
57
describe('Connector', () => {
68
let server: WS;
79

810
beforeEach(() => {
9-
server = new WS("ws://localhost:1234");
11+
jest.useRealTimers();
12+
server = new WS(mockedHost);
1013
});
1114

1215
afterEach(() => {
@@ -15,7 +18,7 @@ describe('Connector', () => {
1518

1619
test('socket id is correctly set', async () => {
1720
const connector = new Connector({
18-
host: "ws://localhost:1234",
21+
host: mockedHost,
1922
})
2023

2124
await server.connected;
@@ -26,9 +29,29 @@ describe('Connector', () => {
2629
expect(connector.socketId()).toBe('test-socket-id')
2730
})
2831

32+
test('we reconnect to the server on error', async () => {
33+
const connector = new Connector({
34+
host: mockedHost,
35+
})
36+
37+
await server.connected;
38+
await expect(server).toReceiveMessage('{"event":"whoami"}');
39+
server.send('{"event":"whoami","data":{"socket_id":"test-socket-id"}}')
40+
41+
server.close();
42+
await server.closed;
43+
server.server.stop(() => (server = new WS(mockedHost)));
44+
45+
await server.connected;
46+
await expect(server).toReceiveMessage('{"event":"whoami"}');
47+
server.send('{"event":"whoami","data":{"socket_id":"test-socket-id2"}}')
48+
49+
expect(connector.socketId()).toBe('test-socket-id2')
50+
})
51+
2952
test('we can subscribe to a channel and listen to events', async () => {
3053
const connector = new Connector({
31-
host: "ws://localhost:1234",
54+
host: mockedHost,
3255
})
3356

3457
await server.connected;
@@ -57,7 +80,7 @@ describe('Connector', () => {
5780

5881
test('we can send a whisper event', async () => {
5982
const connector = new Connector({
60-
host: "ws://localhost:1234",
83+
host: mockedHost,
6184
})
6285

6386
await server.connected;

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
"jest": "^24.9.0",
5050
"jest-websocket-mock": "^2.2.0",
5151
"laravel-echo": "^1.10.0",
52-
"mock-socket": "^9.0.3",
5352
"rollup": "^2.10.2",
5453
"rollup-plugin-typescript2": "^0.27.1",
5554
"standard-version": "^8.0.1",

0 commit comments

Comments
 (0)