laravel-echo-api-gateway 0.1.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +14 -7
- package/.github/workflows/release.yml +2 -2
- package/README.md +20 -2
- package/dist/js-src/Websocket.d.ts +5 -0
- package/dist/laravel-echo-api-gateway.common.js +123 -66
- package/dist/laravel-echo-api-gateway.iife.js +123 -66
- package/dist/laravel-echo-api-gateway.js +123 -66
- package/js-src/Channel.ts +8 -5
- package/js-src/Websocket.ts +55 -24
- package/js-tests/Connector.test.ts +57 -5
- package/package.json +1 -1
- package/phpstan.neon.dist +2 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -7,12 +7,16 @@ on:
|
|
|
7
7
|
jobs:
|
|
8
8
|
pest:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
|
-
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: true
|
|
12
|
+
matrix:
|
|
13
|
+
php: ['8.1']
|
|
14
|
+
name: Pest - PHP ${{ matrix.php }}
|
|
11
15
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v4
|
|
13
17
|
- uses: shivammathur/setup-php@v2
|
|
14
18
|
with:
|
|
15
|
-
php-version:
|
|
19
|
+
php-version: ${{ matrix.php }}
|
|
16
20
|
extensions: dom, mbstring, soap, bcmath, pdo_sqlite, intl
|
|
17
21
|
coverage: pcov
|
|
18
22
|
- uses: ramsey/composer-install@v1
|
|
@@ -20,12 +24,16 @@ jobs:
|
|
|
20
24
|
composer-options: "--prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
|
21
25
|
- name: Run PestPHP
|
|
22
26
|
run: vendor/bin/pest --coverage --coverage-clover test-results/pest.xml
|
|
27
|
+
env:
|
|
28
|
+
AWS_ACCESS_KEY_ID: fake
|
|
29
|
+
AWS_SECRET_ACCESS_KEY: fake
|
|
30
|
+
AWS_SESSION_TOKEN: fake
|
|
23
31
|
- name: Upload coverage to Codecov
|
|
24
32
|
if: always()
|
|
25
|
-
uses: codecov/codecov-action@
|
|
33
|
+
uses: codecov/codecov-action@v2
|
|
26
34
|
with:
|
|
27
35
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
28
|
-
flags: pest
|
|
36
|
+
flags: pest-${{ matrix.php }}
|
|
29
37
|
file: test-results/pest.xml
|
|
30
38
|
|
|
31
39
|
larastan:
|
|
@@ -35,7 +43,7 @@ jobs:
|
|
|
35
43
|
- uses: actions/checkout@v2
|
|
36
44
|
- uses: shivammathur/setup-php@v2
|
|
37
45
|
with:
|
|
38
|
-
php-version:
|
|
46
|
+
php-version: ${{ matrix.php }}
|
|
39
47
|
extensions: soap, bcmath, pdo_sqlite, intl
|
|
40
48
|
- uses: ramsey/composer-install@v1
|
|
41
49
|
with:
|
|
@@ -72,7 +80,6 @@ jobs:
|
|
|
72
80
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
73
81
|
flags: jest
|
|
74
82
|
file: test-results/jest/clover.xml
|
|
75
|
-
|
|
76
83
|
# phpcs:
|
|
77
84
|
# runs-on: ubuntu-latest
|
|
78
85
|
# name: PHP Style Fixer
|
|
@@ -10,7 +10,7 @@ jobs:
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
14
|
with:
|
|
15
15
|
ref: ${{ github.event.release.target_commitish }}
|
|
16
16
|
- name: Use Node.js 12
|
|
@@ -24,7 +24,7 @@ jobs:
|
|
|
24
24
|
- run: yarn version --new-version ${{ github.event.release.tag_name }} --no-git-tag-version
|
|
25
25
|
# - run: yarn run build
|
|
26
26
|
# - run: yarn test
|
|
27
|
-
- run: yarn publish --access public --tag latest
|
|
27
|
+
- run: yarn publish --verbose --access public --tag latest
|
|
28
28
|
env:
|
|
29
29
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
30
30
|
- run: git add package.json
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ advised to only use this package for non-critical / non-production projects.
|
|
|
21
21
|
In order to use this package, your project needs to meet the following criteria:
|
|
22
22
|
|
|
23
23
|
- PHP 7.4 or 8.x
|
|
24
|
-
- Laravel 6
|
|
24
|
+
- Laravel 6 to 11
|
|
25
25
|
- Uses either [bref](https://bref.sh) or [Laravel Vapor](https://vapor.laravel.com) to deploy to AWS
|
|
26
26
|
- Has a working queue
|
|
27
27
|
- Uses Laravel Mix or any other tool to bundle your assets
|
|
@@ -37,7 +37,7 @@ composer require georgeboot/laravel-echo-api-gateway
|
|
|
37
37
|
|
|
38
38
|
yarn add laravel-echo-api-gateway
|
|
39
39
|
# or
|
|
40
|
-
|
|
40
|
+
npm install --save-dev laravel-echo-api-gateway
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
### Platform-specific instructions
|
|
@@ -120,6 +120,7 @@ provider:
|
|
|
120
120
|
|
|
121
121
|
environment:
|
|
122
122
|
# Add these variables
|
|
123
|
+
# Please note : in Laravel 11, this setting is now BROADCAST_CONNECTION
|
|
123
124
|
BROADCAST_DRIVER: laravel-echo-api-gateway
|
|
124
125
|
LARAVEL_ECHO_API_GATEWAY_DYNAMODB_TABLE: !Ref ConnectionsTable
|
|
125
126
|
LARAVEL_ECHO_API_GATEWAY_API_ID: !Ref WebsocketsApi
|
|
@@ -196,7 +197,24 @@ window.Echo = new Echo({
|
|
|
196
197
|
broadcaster,
|
|
197
198
|
// replace the placeholders
|
|
198
199
|
host: 'wss://{api-ip}.execute-api.{region}.amazonaws.com/{stage}',
|
|
200
|
+
authEndpoint: '{auth-url}/broadcasting/auth', // Optional: Use if you have a separate authentication endpoint
|
|
201
|
+
bearerToken: '{token}', // Optional: Use if you need a Bearer Token for authentication
|
|
199
202
|
});
|
|
200
203
|
```
|
|
201
204
|
|
|
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
|
+
|
|
202
220
|
Lastly, you have to generate your assets by running Laravel Mix. After this step, you should be up and running.
|
|
@@ -2,6 +2,9 @@ import { Channel } from "./Channel";
|
|
|
2
2
|
export declare type Options = {
|
|
3
3
|
authEndpoint: string;
|
|
4
4
|
host: string;
|
|
5
|
+
bearerToken: string;
|
|
6
|
+
auth: any;
|
|
7
|
+
debug: boolean;
|
|
5
8
|
};
|
|
6
9
|
export declare type MessageBody = {
|
|
7
10
|
event: string;
|
|
@@ -16,7 +19,9 @@ export declare class Websocket {
|
|
|
16
19
|
private internalListeners;
|
|
17
20
|
private channelBacklog;
|
|
18
21
|
private socketId;
|
|
22
|
+
private closing;
|
|
19
23
|
private pingInterval;
|
|
24
|
+
private connect;
|
|
20
25
|
constructor(options: Options);
|
|
21
26
|
protected parseMessage(body: string): MessageBody;
|
|
22
27
|
getSocketId(): string;
|
|
@@ -21,20 +21,44 @@ function _defineProperties(target, props) {
|
|
|
21
21
|
function _createClass(Constructor, protoProps, staticProps) {
|
|
22
22
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
23
23
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
24
|
+
Object.defineProperty(Constructor, "prototype", {
|
|
25
|
+
writable: false
|
|
26
|
+
});
|
|
24
27
|
return Constructor;
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
function _extends() {
|
|
31
|
+
_extends = Object.assign || function (target) {
|
|
32
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
33
|
+
var source = arguments[i];
|
|
34
|
+
|
|
35
|
+
for (var key in source) {
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
37
|
+
target[key] = source[key];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return target;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return _extends.apply(this, arguments);
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
function _inherits(subClass, superClass) {
|
|
28
49
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
29
50
|
throw new TypeError("Super expression must either be null or a function");
|
|
30
51
|
}
|
|
31
52
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
Object.defineProperty(subClass, "prototype", {
|
|
54
|
+
value: Object.create(superClass && superClass.prototype, {
|
|
55
|
+
constructor: {
|
|
56
|
+
value: subClass,
|
|
57
|
+
writable: true,
|
|
58
|
+
configurable: true
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
writable: false
|
|
38
62
|
});
|
|
39
63
|
if (superClass) _setPrototypeOf(subClass, superClass);
|
|
40
64
|
}
|
|
@@ -61,7 +85,7 @@ function _isNativeReflectConstruct() {
|
|
|
61
85
|
if (typeof Proxy === "function") return true;
|
|
62
86
|
|
|
63
87
|
try {
|
|
64
|
-
|
|
88
|
+
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
|
65
89
|
return true;
|
|
66
90
|
} catch (e) {
|
|
67
91
|
return false;
|
|
@@ -79,6 +103,8 @@ function _assertThisInitialized(self) {
|
|
|
79
103
|
function _possibleConstructorReturn(self, call) {
|
|
80
104
|
if (call && (typeof call === "object" || typeof call === "function")) {
|
|
81
105
|
return call;
|
|
106
|
+
} else if (call !== void 0) {
|
|
107
|
+
throw new TypeError("Derived constructors may only return object or undefined");
|
|
82
108
|
}
|
|
83
109
|
|
|
84
110
|
return _assertThisInitialized(self);
|
|
@@ -157,83 +183,104 @@ class Connector {
|
|
|
157
183
|
|
|
158
184
|
var Websocket = /*#__PURE__*/function () {
|
|
159
185
|
function Websocket(options) {
|
|
160
|
-
var _this = this;
|
|
161
|
-
|
|
162
186
|
_classCallCheck(this, Websocket);
|
|
163
187
|
|
|
164
188
|
this.buffer = [];
|
|
165
189
|
this.listeners = {};
|
|
166
190
|
this.internalListeners = {};
|
|
167
191
|
this.channelBacklog = [];
|
|
192
|
+
this.closing = false;
|
|
168
193
|
this.options = options;
|
|
169
|
-
this.
|
|
194
|
+
this.connect(this.options.host);
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
170
197
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
_createClass(Websocket, [{
|
|
199
|
+
key: "connect",
|
|
200
|
+
value: function connect(host) {
|
|
201
|
+
var _this = this;
|
|
174
202
|
|
|
175
|
-
|
|
203
|
+
this.options.debug && console.log('Connecting');
|
|
204
|
+
this.websocket = new WebSocket(host);
|
|
176
205
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
206
|
+
this.websocket.onopen = function () {
|
|
207
|
+
_this.send({
|
|
208
|
+
event: 'whoami'
|
|
209
|
+
});
|
|
180
210
|
|
|
181
|
-
|
|
182
|
-
|
|
211
|
+
while (_this.buffer.length) {
|
|
212
|
+
var message = _this.buffer[0];
|
|
183
213
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
214
|
+
_this.send(message);
|
|
215
|
+
|
|
216
|
+
_this.buffer.splice(0, 1);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
187
219
|
|
|
188
|
-
|
|
189
|
-
|
|
220
|
+
this.websocket.onmessage = function (messageEvent) {
|
|
221
|
+
var message = _this.parseMessage(messageEvent.data);
|
|
190
222
|
|
|
191
|
-
if (
|
|
192
|
-
|
|
223
|
+
if (!message) {
|
|
224
|
+
return;
|
|
193
225
|
}
|
|
194
226
|
|
|
195
|
-
|
|
196
|
-
|
|
227
|
+
if (message.channel) {
|
|
228
|
+
_this.options.debug && console.log("Received event ".concat(message.event, " on channel ").concat(message.channel));
|
|
197
229
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
};
|
|
230
|
+
if (_this.listeners[message.channel] && _this.listeners[message.channel][message.event]) {
|
|
231
|
+
_this.listeners[message.channel][message.event](message.data);
|
|
232
|
+
}
|
|
202
233
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
_this.socketId = socketId;
|
|
206
|
-
console.log("just set socketId to ".concat(socketId));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
207
236
|
|
|
208
|
-
|
|
209
|
-
|
|
237
|
+
if (_this.internalListeners[message.event]) {
|
|
238
|
+
_this.internalListeners[message.event](message.data);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
210
241
|
|
|
211
|
-
|
|
242
|
+
this.websocket.onclose = function () {
|
|
243
|
+
if (_this.socketId && !_this.closing || !_this.socketId) {
|
|
244
|
+
_this.options.debug && console.info('Connection lost, reconnecting...');
|
|
245
|
+
setTimeout(function () {
|
|
246
|
+
_this.socketId = undefined;
|
|
212
247
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
event: 'whoami'
|
|
218
|
-
}); // send ping every 60 seconds to keep connection alive
|
|
248
|
+
_this.connect(host);
|
|
249
|
+
}, 1000);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
219
252
|
|
|
220
|
-
|
|
221
|
-
|
|
253
|
+
this.on('whoami', function (_ref) {
|
|
254
|
+
var socketId = _ref.socket_id;
|
|
255
|
+
_this.socketId = socketId;
|
|
256
|
+
_this.options.debug && console.log("just set socketId to ".concat(socketId));
|
|
222
257
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
});
|
|
226
|
-
}, 60 * 1000);
|
|
227
|
-
return this;
|
|
228
|
-
}
|
|
258
|
+
while (_this.channelBacklog.length) {
|
|
259
|
+
var channel = _this.channelBacklog[0];
|
|
229
260
|
|
|
230
|
-
|
|
261
|
+
_this.actuallySubscribe(channel);
|
|
262
|
+
|
|
263
|
+
_this.channelBacklog.splice(0, 1);
|
|
264
|
+
}
|
|
265
|
+
}); // send ping every 60 seconds to keep connection alive
|
|
266
|
+
|
|
267
|
+
this.pingInterval = setInterval(function () {
|
|
268
|
+
if (_this.websocket.readyState === _this.websocket.OPEN) {
|
|
269
|
+
_this.options.debug && console.log('Sending ping');
|
|
270
|
+
|
|
271
|
+
_this.send({
|
|
272
|
+
event: 'ping'
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}, 60 * 1000);
|
|
276
|
+
}
|
|
277
|
+
}, {
|
|
231
278
|
key: "parseMessage",
|
|
232
279
|
value: function parseMessage(body) {
|
|
233
280
|
try {
|
|
234
281
|
return JSON.parse(body);
|
|
235
282
|
} catch (error) {
|
|
236
|
-
console.error(error);
|
|
283
|
+
this.options.debug && console.error(error);
|
|
237
284
|
return undefined;
|
|
238
285
|
}
|
|
239
286
|
}
|
|
@@ -260,6 +307,7 @@ var Websocket = /*#__PURE__*/function () {
|
|
|
260
307
|
}, {
|
|
261
308
|
key: "close",
|
|
262
309
|
value: function close() {
|
|
310
|
+
this.closing = true;
|
|
263
311
|
this.internalListeners = {};
|
|
264
312
|
clearInterval(this.pingInterval);
|
|
265
313
|
this.pingInterval = undefined;
|
|
@@ -280,26 +328,32 @@ var Websocket = /*#__PURE__*/function () {
|
|
|
280
328
|
var _this2 = this;
|
|
281
329
|
|
|
282
330
|
if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
|
|
283
|
-
console.log("Sending auth request for channel ".concat(channel.name));
|
|
331
|
+
this.options.debug && console.log("Sending auth request for channel ".concat(channel.name));
|
|
332
|
+
|
|
333
|
+
if (this.options.bearerToken) {
|
|
334
|
+
this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
|
|
335
|
+
}
|
|
336
|
+
|
|
284
337
|
axios.post(this.options.authEndpoint, {
|
|
285
338
|
socket_id: this.getSocketId(),
|
|
286
339
|
channel_name: channel.name
|
|
340
|
+
}, {
|
|
341
|
+
headers: this.options.auth.headers || {}
|
|
287
342
|
}).then(function (response) {
|
|
288
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
343
|
+
_this2.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
289
344
|
|
|
290
345
|
_this2.send({
|
|
291
346
|
event: 'subscribe',
|
|
292
|
-
data: {
|
|
293
|
-
channel: channel.name
|
|
294
|
-
|
|
295
|
-
}
|
|
347
|
+
data: _extends({
|
|
348
|
+
channel: channel.name
|
|
349
|
+
}, response.data)
|
|
296
350
|
});
|
|
297
351
|
})["catch"](function (error) {
|
|
298
|
-
console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
299
|
-
console.error(error);
|
|
352
|
+
_this2.options.debug && console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
353
|
+
_this2.options.debug && console.error(error);
|
|
300
354
|
});
|
|
301
355
|
} else {
|
|
302
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
356
|
+
this.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
303
357
|
this.send({
|
|
304
358
|
event: 'subscribe',
|
|
305
359
|
data: {
|
|
@@ -508,9 +562,12 @@ var Channel$1 = /*#__PURE__*/function (_BaseChannel) {
|
|
|
508
562
|
}, {
|
|
509
563
|
key: "whisper",
|
|
510
564
|
value: function whisper(event, data) {
|
|
565
|
+
var channel = this.name;
|
|
566
|
+
var formattedEvent = "client-" + event;
|
|
511
567
|
this.socket.send({
|
|
512
|
-
event:
|
|
513
|
-
data: data
|
|
568
|
+
"event": formattedEvent,
|
|
569
|
+
data: data,
|
|
570
|
+
channel: channel
|
|
514
571
|
});
|
|
515
572
|
return this;
|
|
516
573
|
}
|
|
@@ -20,20 +20,44 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
20
20
|
function _createClass(Constructor, protoProps, staticProps) {
|
|
21
21
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
22
22
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
23
|
+
Object.defineProperty(Constructor, "prototype", {
|
|
24
|
+
writable: false
|
|
25
|
+
});
|
|
23
26
|
return Constructor;
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
function _extends() {
|
|
30
|
+
_extends = Object.assign || function (target) {
|
|
31
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
32
|
+
var source = arguments[i];
|
|
33
|
+
|
|
34
|
+
for (var key in source) {
|
|
35
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
36
|
+
target[key] = source[key];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return target;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return _extends.apply(this, arguments);
|
|
45
|
+
}
|
|
46
|
+
|
|
26
47
|
function _inherits(subClass, superClass) {
|
|
27
48
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
28
49
|
throw new TypeError("Super expression must either be null or a function");
|
|
29
50
|
}
|
|
30
51
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
Object.defineProperty(subClass, "prototype", {
|
|
53
|
+
value: Object.create(superClass && superClass.prototype, {
|
|
54
|
+
constructor: {
|
|
55
|
+
value: subClass,
|
|
56
|
+
writable: true,
|
|
57
|
+
configurable: true
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
60
|
+
writable: false
|
|
37
61
|
});
|
|
38
62
|
if (superClass) _setPrototypeOf(subClass, superClass);
|
|
39
63
|
}
|
|
@@ -60,7 +84,7 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
60
84
|
if (typeof Proxy === "function") return true;
|
|
61
85
|
|
|
62
86
|
try {
|
|
63
|
-
|
|
87
|
+
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
|
64
88
|
return true;
|
|
65
89
|
} catch (e) {
|
|
66
90
|
return false;
|
|
@@ -78,6 +102,8 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
78
102
|
function _possibleConstructorReturn(self, call) {
|
|
79
103
|
if (call && (typeof call === "object" || typeof call === "function")) {
|
|
80
104
|
return call;
|
|
105
|
+
} else if (call !== void 0) {
|
|
106
|
+
throw new TypeError("Derived constructors may only return object or undefined");
|
|
81
107
|
}
|
|
82
108
|
|
|
83
109
|
return _assertThisInitialized(self);
|
|
@@ -156,83 +182,104 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
156
182
|
|
|
157
183
|
var Websocket = /*#__PURE__*/function () {
|
|
158
184
|
function Websocket(options) {
|
|
159
|
-
var _this = this;
|
|
160
|
-
|
|
161
185
|
_classCallCheck(this, Websocket);
|
|
162
186
|
|
|
163
187
|
this.buffer = [];
|
|
164
188
|
this.listeners = {};
|
|
165
189
|
this.internalListeners = {};
|
|
166
190
|
this.channelBacklog = [];
|
|
191
|
+
this.closing = false;
|
|
167
192
|
this.options = options;
|
|
168
|
-
this.
|
|
193
|
+
this.connect(this.options.host);
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
169
196
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
197
|
+
_createClass(Websocket, [{
|
|
198
|
+
key: "connect",
|
|
199
|
+
value: function connect(host) {
|
|
200
|
+
var _this = this;
|
|
173
201
|
|
|
174
|
-
|
|
202
|
+
this.options.debug && console.log('Connecting');
|
|
203
|
+
this.websocket = new WebSocket(host);
|
|
175
204
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
205
|
+
this.websocket.onopen = function () {
|
|
206
|
+
_this.send({
|
|
207
|
+
event: 'whoami'
|
|
208
|
+
});
|
|
179
209
|
|
|
180
|
-
|
|
181
|
-
|
|
210
|
+
while (_this.buffer.length) {
|
|
211
|
+
var message = _this.buffer[0];
|
|
182
212
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
213
|
+
_this.send(message);
|
|
214
|
+
|
|
215
|
+
_this.buffer.splice(0, 1);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
186
218
|
|
|
187
|
-
|
|
188
|
-
|
|
219
|
+
this.websocket.onmessage = function (messageEvent) {
|
|
220
|
+
var message = _this.parseMessage(messageEvent.data);
|
|
189
221
|
|
|
190
|
-
if (
|
|
191
|
-
|
|
222
|
+
if (!message) {
|
|
223
|
+
return;
|
|
192
224
|
}
|
|
193
225
|
|
|
194
|
-
|
|
195
|
-
|
|
226
|
+
if (message.channel) {
|
|
227
|
+
_this.options.debug && console.log("Received event ".concat(message.event, " on channel ").concat(message.channel));
|
|
196
228
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
};
|
|
229
|
+
if (_this.listeners[message.channel] && _this.listeners[message.channel][message.event]) {
|
|
230
|
+
_this.listeners[message.channel][message.event](message.data);
|
|
231
|
+
}
|
|
201
232
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
_this.socketId = socketId;
|
|
205
|
-
console.log("just set socketId to ".concat(socketId));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
206
235
|
|
|
207
|
-
|
|
208
|
-
|
|
236
|
+
if (_this.internalListeners[message.event]) {
|
|
237
|
+
_this.internalListeners[message.event](message.data);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
209
240
|
|
|
210
|
-
|
|
241
|
+
this.websocket.onclose = function () {
|
|
242
|
+
if (_this.socketId && !_this.closing || !_this.socketId) {
|
|
243
|
+
_this.options.debug && console.info('Connection lost, reconnecting...');
|
|
244
|
+
setTimeout(function () {
|
|
245
|
+
_this.socketId = undefined;
|
|
211
246
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
event: 'whoami'
|
|
217
|
-
}); // send ping every 60 seconds to keep connection alive
|
|
247
|
+
_this.connect(host);
|
|
248
|
+
}, 1000);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
218
251
|
|
|
219
|
-
|
|
220
|
-
|
|
252
|
+
this.on('whoami', function (_ref) {
|
|
253
|
+
var socketId = _ref.socket_id;
|
|
254
|
+
_this.socketId = socketId;
|
|
255
|
+
_this.options.debug && console.log("just set socketId to ".concat(socketId));
|
|
221
256
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
225
|
-
}, 60 * 1000);
|
|
226
|
-
return this;
|
|
227
|
-
}
|
|
257
|
+
while (_this.channelBacklog.length) {
|
|
258
|
+
var channel = _this.channelBacklog[0];
|
|
228
259
|
|
|
229
|
-
|
|
260
|
+
_this.actuallySubscribe(channel);
|
|
261
|
+
|
|
262
|
+
_this.channelBacklog.splice(0, 1);
|
|
263
|
+
}
|
|
264
|
+
}); // send ping every 60 seconds to keep connection alive
|
|
265
|
+
|
|
266
|
+
this.pingInterval = setInterval(function () {
|
|
267
|
+
if (_this.websocket.readyState === _this.websocket.OPEN) {
|
|
268
|
+
_this.options.debug && console.log('Sending ping');
|
|
269
|
+
|
|
270
|
+
_this.send({
|
|
271
|
+
event: 'ping'
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}, 60 * 1000);
|
|
275
|
+
}
|
|
276
|
+
}, {
|
|
230
277
|
key: "parseMessage",
|
|
231
278
|
value: function parseMessage(body) {
|
|
232
279
|
try {
|
|
233
280
|
return JSON.parse(body);
|
|
234
281
|
} catch (error) {
|
|
235
|
-
console.error(error);
|
|
282
|
+
this.options.debug && console.error(error);
|
|
236
283
|
return undefined;
|
|
237
284
|
}
|
|
238
285
|
}
|
|
@@ -259,6 +306,7 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
259
306
|
}, {
|
|
260
307
|
key: "close",
|
|
261
308
|
value: function close() {
|
|
309
|
+
this.closing = true;
|
|
262
310
|
this.internalListeners = {};
|
|
263
311
|
clearInterval(this.pingInterval);
|
|
264
312
|
this.pingInterval = undefined;
|
|
@@ -279,26 +327,32 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
279
327
|
var _this2 = this;
|
|
280
328
|
|
|
281
329
|
if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
|
|
282
|
-
console.log("Sending auth request for channel ".concat(channel.name));
|
|
330
|
+
this.options.debug && console.log("Sending auth request for channel ".concat(channel.name));
|
|
331
|
+
|
|
332
|
+
if (this.options.bearerToken) {
|
|
333
|
+
this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
|
|
334
|
+
}
|
|
335
|
+
|
|
283
336
|
axios.post(this.options.authEndpoint, {
|
|
284
337
|
socket_id: this.getSocketId(),
|
|
285
338
|
channel_name: channel.name
|
|
339
|
+
}, {
|
|
340
|
+
headers: this.options.auth.headers || {}
|
|
286
341
|
}).then(function (response) {
|
|
287
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
342
|
+
_this2.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
288
343
|
|
|
289
344
|
_this2.send({
|
|
290
345
|
event: 'subscribe',
|
|
291
|
-
data: {
|
|
292
|
-
channel: channel.name
|
|
293
|
-
|
|
294
|
-
}
|
|
346
|
+
data: _extends({
|
|
347
|
+
channel: channel.name
|
|
348
|
+
}, response.data)
|
|
295
349
|
});
|
|
296
350
|
})["catch"](function (error) {
|
|
297
|
-
console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
298
|
-
console.error(error);
|
|
351
|
+
_this2.options.debug && console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
352
|
+
_this2.options.debug && console.error(error);
|
|
299
353
|
});
|
|
300
354
|
} else {
|
|
301
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
355
|
+
this.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
302
356
|
this.send({
|
|
303
357
|
event: 'subscribe',
|
|
304
358
|
data: {
|
|
@@ -507,9 +561,12 @@ var LaravelEchoApiGateway = (function (exports) {
|
|
|
507
561
|
}, {
|
|
508
562
|
key: "whisper",
|
|
509
563
|
value: function whisper(event, data) {
|
|
564
|
+
var channel = this.name;
|
|
565
|
+
var formattedEvent = "client-" + event;
|
|
510
566
|
this.socket.send({
|
|
511
|
-
event:
|
|
512
|
-
data: data
|
|
567
|
+
"event": formattedEvent,
|
|
568
|
+
data: data,
|
|
569
|
+
channel: channel
|
|
513
570
|
});
|
|
514
571
|
return this;
|
|
515
572
|
}
|
|
@@ -17,20 +17,44 @@ function _defineProperties(target, props) {
|
|
|
17
17
|
function _createClass(Constructor, protoProps, staticProps) {
|
|
18
18
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
19
19
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
20
|
+
Object.defineProperty(Constructor, "prototype", {
|
|
21
|
+
writable: false
|
|
22
|
+
});
|
|
20
23
|
return Constructor;
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
function _extends() {
|
|
27
|
+
_extends = Object.assign || function (target) {
|
|
28
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
29
|
+
var source = arguments[i];
|
|
30
|
+
|
|
31
|
+
for (var key in source) {
|
|
32
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
33
|
+
target[key] = source[key];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return target;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return _extends.apply(this, arguments);
|
|
42
|
+
}
|
|
43
|
+
|
|
23
44
|
function _inherits(subClass, superClass) {
|
|
24
45
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
25
46
|
throw new TypeError("Super expression must either be null or a function");
|
|
26
47
|
}
|
|
27
48
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
Object.defineProperty(subClass, "prototype", {
|
|
50
|
+
value: Object.create(superClass && superClass.prototype, {
|
|
51
|
+
constructor: {
|
|
52
|
+
value: subClass,
|
|
53
|
+
writable: true,
|
|
54
|
+
configurable: true
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
57
|
+
writable: false
|
|
34
58
|
});
|
|
35
59
|
if (superClass) _setPrototypeOf(subClass, superClass);
|
|
36
60
|
}
|
|
@@ -57,7 +81,7 @@ function _isNativeReflectConstruct() {
|
|
|
57
81
|
if (typeof Proxy === "function") return true;
|
|
58
82
|
|
|
59
83
|
try {
|
|
60
|
-
|
|
84
|
+
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
|
61
85
|
return true;
|
|
62
86
|
} catch (e) {
|
|
63
87
|
return false;
|
|
@@ -75,6 +99,8 @@ function _assertThisInitialized(self) {
|
|
|
75
99
|
function _possibleConstructorReturn(self, call) {
|
|
76
100
|
if (call && (typeof call === "object" || typeof call === "function")) {
|
|
77
101
|
return call;
|
|
102
|
+
} else if (call !== void 0) {
|
|
103
|
+
throw new TypeError("Derived constructors may only return object or undefined");
|
|
78
104
|
}
|
|
79
105
|
|
|
80
106
|
return _assertThisInitialized(self);
|
|
@@ -153,83 +179,104 @@ class Connector {
|
|
|
153
179
|
|
|
154
180
|
var Websocket = /*#__PURE__*/function () {
|
|
155
181
|
function Websocket(options) {
|
|
156
|
-
var _this = this;
|
|
157
|
-
|
|
158
182
|
_classCallCheck(this, Websocket);
|
|
159
183
|
|
|
160
184
|
this.buffer = [];
|
|
161
185
|
this.listeners = {};
|
|
162
186
|
this.internalListeners = {};
|
|
163
187
|
this.channelBacklog = [];
|
|
188
|
+
this.closing = false;
|
|
164
189
|
this.options = options;
|
|
165
|
-
this.
|
|
190
|
+
this.connect(this.options.host);
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
166
193
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
194
|
+
_createClass(Websocket, [{
|
|
195
|
+
key: "connect",
|
|
196
|
+
value: function connect(host) {
|
|
197
|
+
var _this = this;
|
|
170
198
|
|
|
171
|
-
|
|
199
|
+
this.options.debug && console.log('Connecting');
|
|
200
|
+
this.websocket = new WebSocket(host);
|
|
172
201
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
202
|
+
this.websocket.onopen = function () {
|
|
203
|
+
_this.send({
|
|
204
|
+
event: 'whoami'
|
|
205
|
+
});
|
|
176
206
|
|
|
177
|
-
|
|
178
|
-
|
|
207
|
+
while (_this.buffer.length) {
|
|
208
|
+
var message = _this.buffer[0];
|
|
179
209
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
210
|
+
_this.send(message);
|
|
211
|
+
|
|
212
|
+
_this.buffer.splice(0, 1);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
183
215
|
|
|
184
|
-
|
|
185
|
-
|
|
216
|
+
this.websocket.onmessage = function (messageEvent) {
|
|
217
|
+
var message = _this.parseMessage(messageEvent.data);
|
|
186
218
|
|
|
187
|
-
if (
|
|
188
|
-
|
|
219
|
+
if (!message) {
|
|
220
|
+
return;
|
|
189
221
|
}
|
|
190
222
|
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
if (message.channel) {
|
|
224
|
+
_this.options.debug && console.log("Received event ".concat(message.event, " on channel ").concat(message.channel));
|
|
193
225
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
226
|
+
if (_this.listeners[message.channel] && _this.listeners[message.channel][message.event]) {
|
|
227
|
+
_this.listeners[message.channel][message.event](message.data);
|
|
228
|
+
}
|
|
198
229
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
_this.socketId = socketId;
|
|
202
|
-
console.log("just set socketId to ".concat(socketId));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
203
232
|
|
|
204
|
-
|
|
205
|
-
|
|
233
|
+
if (_this.internalListeners[message.event]) {
|
|
234
|
+
_this.internalListeners[message.event](message.data);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
206
237
|
|
|
207
|
-
|
|
238
|
+
this.websocket.onclose = function () {
|
|
239
|
+
if (_this.socketId && !_this.closing || !_this.socketId) {
|
|
240
|
+
_this.options.debug && console.info('Connection lost, reconnecting...');
|
|
241
|
+
setTimeout(function () {
|
|
242
|
+
_this.socketId = undefined;
|
|
208
243
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
event: 'whoami'
|
|
214
|
-
}); // send ping every 60 seconds to keep connection alive
|
|
244
|
+
_this.connect(host);
|
|
245
|
+
}, 1000);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
215
248
|
|
|
216
|
-
|
|
217
|
-
|
|
249
|
+
this.on('whoami', function (_ref) {
|
|
250
|
+
var socketId = _ref.socket_id;
|
|
251
|
+
_this.socketId = socketId;
|
|
252
|
+
_this.options.debug && console.log("just set socketId to ".concat(socketId));
|
|
218
253
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
});
|
|
222
|
-
}, 60 * 1000);
|
|
223
|
-
return this;
|
|
224
|
-
}
|
|
254
|
+
while (_this.channelBacklog.length) {
|
|
255
|
+
var channel = _this.channelBacklog[0];
|
|
225
256
|
|
|
226
|
-
|
|
257
|
+
_this.actuallySubscribe(channel);
|
|
258
|
+
|
|
259
|
+
_this.channelBacklog.splice(0, 1);
|
|
260
|
+
}
|
|
261
|
+
}); // send ping every 60 seconds to keep connection alive
|
|
262
|
+
|
|
263
|
+
this.pingInterval = setInterval(function () {
|
|
264
|
+
if (_this.websocket.readyState === _this.websocket.OPEN) {
|
|
265
|
+
_this.options.debug && console.log('Sending ping');
|
|
266
|
+
|
|
267
|
+
_this.send({
|
|
268
|
+
event: 'ping'
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}, 60 * 1000);
|
|
272
|
+
}
|
|
273
|
+
}, {
|
|
227
274
|
key: "parseMessage",
|
|
228
275
|
value: function parseMessage(body) {
|
|
229
276
|
try {
|
|
230
277
|
return JSON.parse(body);
|
|
231
278
|
} catch (error) {
|
|
232
|
-
console.error(error);
|
|
279
|
+
this.options.debug && console.error(error);
|
|
233
280
|
return undefined;
|
|
234
281
|
}
|
|
235
282
|
}
|
|
@@ -256,6 +303,7 @@ var Websocket = /*#__PURE__*/function () {
|
|
|
256
303
|
}, {
|
|
257
304
|
key: "close",
|
|
258
305
|
value: function close() {
|
|
306
|
+
this.closing = true;
|
|
259
307
|
this.internalListeners = {};
|
|
260
308
|
clearInterval(this.pingInterval);
|
|
261
309
|
this.pingInterval = undefined;
|
|
@@ -276,26 +324,32 @@ var Websocket = /*#__PURE__*/function () {
|
|
|
276
324
|
var _this2 = this;
|
|
277
325
|
|
|
278
326
|
if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
|
|
279
|
-
console.log("Sending auth request for channel ".concat(channel.name));
|
|
327
|
+
this.options.debug && console.log("Sending auth request for channel ".concat(channel.name));
|
|
328
|
+
|
|
329
|
+
if (this.options.bearerToken) {
|
|
330
|
+
this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
|
|
331
|
+
}
|
|
332
|
+
|
|
280
333
|
axios.post(this.options.authEndpoint, {
|
|
281
334
|
socket_id: this.getSocketId(),
|
|
282
335
|
channel_name: channel.name
|
|
336
|
+
}, {
|
|
337
|
+
headers: this.options.auth.headers || {}
|
|
283
338
|
}).then(function (response) {
|
|
284
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
339
|
+
_this2.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
285
340
|
|
|
286
341
|
_this2.send({
|
|
287
342
|
event: 'subscribe',
|
|
288
|
-
data: {
|
|
289
|
-
channel: channel.name
|
|
290
|
-
|
|
291
|
-
}
|
|
343
|
+
data: _extends({
|
|
344
|
+
channel: channel.name
|
|
345
|
+
}, response.data)
|
|
292
346
|
});
|
|
293
347
|
})["catch"](function (error) {
|
|
294
|
-
console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
295
|
-
console.error(error);
|
|
348
|
+
_this2.options.debug && console.log("Auth request for channel ".concat(channel.name, " failed"));
|
|
349
|
+
_this2.options.debug && console.error(error);
|
|
296
350
|
});
|
|
297
351
|
} else {
|
|
298
|
-
console.log("Subscribing to channels ".concat(channel.name));
|
|
352
|
+
this.options.debug && console.log("Subscribing to channels ".concat(channel.name));
|
|
299
353
|
this.send({
|
|
300
354
|
event: 'subscribe',
|
|
301
355
|
data: {
|
|
@@ -504,9 +558,12 @@ var Channel$1 = /*#__PURE__*/function (_BaseChannel) {
|
|
|
504
558
|
}, {
|
|
505
559
|
key: "whisper",
|
|
506
560
|
value: function whisper(event, data) {
|
|
561
|
+
var channel = this.name;
|
|
562
|
+
var formattedEvent = "client-" + event;
|
|
507
563
|
this.socket.send({
|
|
508
|
-
event:
|
|
509
|
-
data: data
|
|
564
|
+
"event": formattedEvent,
|
|
565
|
+
data: data,
|
|
566
|
+
channel: channel
|
|
510
567
|
});
|
|
511
568
|
return this;
|
|
512
569
|
}
|
package/js-src/Channel.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {EventFormatter} from 'laravel-echo/src/util';
|
|
2
|
-
import {Channel as BaseChannel} from 'laravel-echo/src/channel/channel';
|
|
3
|
-
import {PresenceChannel} from "laravel-echo/src/channel";
|
|
4
|
-
import {Websocket} from "./Websocket";
|
|
1
|
+
import { EventFormatter } from 'laravel-echo/src/util';
|
|
2
|
+
import { Channel as BaseChannel } from 'laravel-echo/src/channel/channel';
|
|
3
|
+
import { PresenceChannel } from "laravel-echo/src/channel";
|
|
4
|
+
import { Websocket } from "./Websocket";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* This class represents a Pusher channel.
|
|
@@ -105,9 +105,12 @@ export class Channel extends BaseChannel implements PresenceChannel {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
whisper(event: string, data: object): Channel {
|
|
108
|
+
let channel = this.name;
|
|
109
|
+
let formattedEvent = "client-" + event;
|
|
108
110
|
this.socket.send({
|
|
109
|
-
event,
|
|
111
|
+
"event": formattedEvent,
|
|
110
112
|
data,
|
|
113
|
+
channel,
|
|
111
114
|
})
|
|
112
115
|
|
|
113
116
|
return this;
|
package/js-src/Websocket.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AxiosResponse } from "axios";
|
|
2
|
+
import { Channel } from "./Channel";
|
|
3
|
+
|
|
4
|
+
export type Options = { authEndpoint: string, host: string, bearerToken: string, auth: any, debug: boolean };
|
|
3
5
|
|
|
4
|
-
export type Options = { authEndpoint: string, host: string };
|
|
5
6
|
export type MessageBody = { event: string, channel?: string, data: object };
|
|
6
7
|
|
|
7
8
|
export class Websocket {
|
|
@@ -19,14 +20,20 @@ export class Websocket {
|
|
|
19
20
|
|
|
20
21
|
private socketId: string;
|
|
21
22
|
|
|
23
|
+
private closing = false;
|
|
24
|
+
|
|
22
25
|
private pingInterval: NodeJS.Timeout;
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
this.options
|
|
27
|
+
private connect(host: string): void {
|
|
28
|
+
this.options.debug && console.log('Connecting');
|
|
26
29
|
|
|
27
|
-
this.websocket = new WebSocket(
|
|
30
|
+
this.websocket = new WebSocket(host)
|
|
28
31
|
|
|
29
32
|
this.websocket.onopen = () => {
|
|
33
|
+
this.send({
|
|
34
|
+
event: 'whoami',
|
|
35
|
+
})
|
|
36
|
+
|
|
30
37
|
while (this.buffer.length) {
|
|
31
38
|
const message = this.buffer[0]
|
|
32
39
|
|
|
@@ -44,7 +51,7 @@ export class Websocket {
|
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
if (message.channel) {
|
|
47
|
-
console.log(`Received event ${message.event} on channel ${message.channel}`)
|
|
54
|
+
this.options.debug && console.log(`Received event ${message.event} on channel ${message.channel}`)
|
|
48
55
|
|
|
49
56
|
if (this.listeners[message.channel] && this.listeners[message.channel][message.event]) {
|
|
50
57
|
this.listeners[message.channel][message.event](message.data)
|
|
@@ -56,12 +63,24 @@ export class Websocket {
|
|
|
56
63
|
if (this.internalListeners[message.event]) {
|
|
57
64
|
this.internalListeners[message.event](message.data)
|
|
58
65
|
}
|
|
66
|
+
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
|
|
70
|
+
this.websocket.onclose = () => {
|
|
71
|
+
if (this.socketId && !this.closing || !this.socketId) {
|
|
72
|
+
this.options.debug && console.info('Connection lost, reconnecting...');
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
this.socketId = undefined
|
|
75
|
+
this.connect(host)
|
|
76
|
+
}, 1000);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
61
80
|
this.on('whoami', ({ socket_id: socketId }) => {
|
|
62
81
|
this.socketId = socketId
|
|
63
82
|
|
|
64
|
-
console.log(`just set socketId to ${socketId}`)
|
|
83
|
+
this.options.debug && console.log(`just set socketId to ${socketId}`)
|
|
65
84
|
|
|
66
85
|
while (this.channelBacklog.length) {
|
|
67
86
|
const channel = this.channelBacklog[0]
|
|
@@ -72,19 +91,24 @@ export class Websocket {
|
|
|
72
91
|
}
|
|
73
92
|
})
|
|
74
93
|
|
|
75
|
-
this.send({
|
|
76
|
-
event: 'whoami',
|
|
77
|
-
})
|
|
78
94
|
|
|
79
95
|
// send ping every 60 seconds to keep connection alive
|
|
80
96
|
this.pingInterval = setInterval(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
if (this.websocket.readyState === this.websocket.OPEN) {
|
|
98
|
+
this.options.debug && console.log('Sending ping')
|
|
99
|
+
this.send({
|
|
100
|
+
event: 'ping',
|
|
101
|
+
})
|
|
102
|
+
}
|
|
86
103
|
}, 60 * 1000)
|
|
87
104
|
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
constructor(options: Options) {
|
|
108
|
+
this.options = options;
|
|
109
|
+
|
|
110
|
+
this.connect(this.options.host);
|
|
111
|
+
|
|
88
112
|
return this
|
|
89
113
|
}
|
|
90
114
|
|
|
@@ -92,7 +116,7 @@ export class Websocket {
|
|
|
92
116
|
try {
|
|
93
117
|
return JSON.parse(body)
|
|
94
118
|
} catch (error) {
|
|
95
|
-
console.error(error)
|
|
119
|
+
this.options.debug && console.error(error)
|
|
96
120
|
|
|
97
121
|
return undefined
|
|
98
122
|
}
|
|
@@ -115,7 +139,8 @@ export class Websocket {
|
|
|
115
139
|
this.buffer.push(message)
|
|
116
140
|
}
|
|
117
141
|
|
|
118
|
-
close
|
|
142
|
+
close(): void {
|
|
143
|
+
this.closing = true
|
|
119
144
|
this.internalListeners = {}
|
|
120
145
|
|
|
121
146
|
clearInterval(this.pingInterval)
|
|
@@ -134,27 +159,33 @@ export class Websocket {
|
|
|
134
159
|
|
|
135
160
|
private actuallySubscribe(channel: Channel): void {
|
|
136
161
|
if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
|
|
137
|
-
console.log(`Sending auth request for channel ${channel.name}`)
|
|
162
|
+
this.options.debug && console.log(`Sending auth request for channel ${channel.name}`)
|
|
163
|
+
|
|
164
|
+
if (this.options.bearerToken) {
|
|
165
|
+
this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
|
|
166
|
+
}
|
|
138
167
|
|
|
139
168
|
axios.post(this.options.authEndpoint, {
|
|
140
169
|
socket_id: this.getSocketId(),
|
|
141
170
|
channel_name: channel.name,
|
|
171
|
+
}, {
|
|
172
|
+
headers: this.options.auth.headers || {}
|
|
142
173
|
}).then((response: AxiosResponse) => {
|
|
143
|
-
console.log(`Subscribing to channels ${channel.name}`)
|
|
174
|
+
this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
|
|
144
175
|
|
|
145
176
|
this.send({
|
|
146
177
|
event: 'subscribe',
|
|
147
178
|
data: {
|
|
148
179
|
channel: channel.name,
|
|
149
|
-
|
|
180
|
+
...response.data
|
|
150
181
|
},
|
|
151
182
|
})
|
|
152
183
|
}).catch((error) => {
|
|
153
|
-
console.log(`Auth request for channel ${channel.name} failed`)
|
|
154
|
-
console.error(error)
|
|
184
|
+
this.options.debug && console.log(`Auth request for channel ${channel.name} failed`)
|
|
185
|
+
this.options.debug && console.error(error)
|
|
155
186
|
})
|
|
156
187
|
} else {
|
|
157
|
-
console.log(`Subscribing to channels ${channel.name}`)
|
|
188
|
+
this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
|
|
158
189
|
|
|
159
190
|
this.send({
|
|
160
191
|
event: 'subscribe',
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import WS from "jest-websocket-mock";
|
|
2
|
-
import {Connector} from "../js-src/Connector";
|
|
3
|
-
import {Channel} from "../js-src/Channel";
|
|
2
|
+
import { Connector } from "../js-src/Connector";
|
|
3
|
+
import { Channel } from "../js-src/Channel";
|
|
4
|
+
|
|
5
|
+
const mockedHost = 'ws://localhost:1234';
|
|
4
6
|
|
|
5
7
|
describe('Connector', () => {
|
|
6
8
|
let server: WS;
|
|
7
9
|
|
|
8
10
|
beforeEach(() => {
|
|
9
|
-
|
|
11
|
+
jest.useRealTimers();
|
|
12
|
+
server = new WS(mockedHost);
|
|
10
13
|
});
|
|
11
14
|
|
|
12
15
|
afterEach(() => {
|
|
@@ -15,7 +18,7 @@ describe('Connector', () => {
|
|
|
15
18
|
|
|
16
19
|
test('socket id is correctly set', async () => {
|
|
17
20
|
const connector = new Connector({
|
|
18
|
-
host:
|
|
21
|
+
host: mockedHost,
|
|
19
22
|
})
|
|
20
23
|
|
|
21
24
|
await server.connected;
|
|
@@ -26,9 +29,29 @@ describe('Connector', () => {
|
|
|
26
29
|
expect(connector.socketId()).toBe('test-socket-id')
|
|
27
30
|
})
|
|
28
31
|
|
|
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
|
+
|
|
29
52
|
test('we can subscribe to a channel and listen to events', async () => {
|
|
30
53
|
const connector = new Connector({
|
|
31
|
-
host:
|
|
54
|
+
host: mockedHost,
|
|
32
55
|
})
|
|
33
56
|
|
|
34
57
|
await server.connected;
|
|
@@ -54,4 +77,33 @@ describe('Connector', () => {
|
|
|
54
77
|
expect(handler1).toBeCalled();
|
|
55
78
|
expect(handler2).not.toBeCalled();
|
|
56
79
|
})
|
|
80
|
+
|
|
81
|
+
test('we can send a whisper event', async () => {
|
|
82
|
+
const connector = new Connector({
|
|
83
|
+
host: mockedHost,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
await server.connected;
|
|
87
|
+
|
|
88
|
+
await expect(server).toReceiveMessage('{"event":"whoami"}');
|
|
89
|
+
server.send('{"event":"whoami","data":{"socket_id":"test-socket-id"}}')
|
|
90
|
+
|
|
91
|
+
const channel = connector.channel('my-test-channel')
|
|
92
|
+
|
|
93
|
+
await expect(server).toReceiveMessage('{"event":"subscribe","data":{"channel":"my-test-channel"}}');
|
|
94
|
+
|
|
95
|
+
server.send('{"event":"subscription_succeeded","channel":"my-test-channel"}')
|
|
96
|
+
|
|
97
|
+
expect(channel).toBeInstanceOf(Channel)
|
|
98
|
+
|
|
99
|
+
const handler1 = jest.fn();
|
|
100
|
+
const handler2 = jest.fn();
|
|
101
|
+
|
|
102
|
+
channel.on('client-whisper', handler1)
|
|
103
|
+
|
|
104
|
+
server.send('{"event":"client-whisper","data":"whisper","channel":"my-test-channel","data":{}}')
|
|
105
|
+
|
|
106
|
+
expect(handler1).toBeCalled();
|
|
107
|
+
expect(handler2).not.toBeCalled();
|
|
108
|
+
})
|
|
57
109
|
});
|
package/package.json
CHANGED