pusher-js 7.3.0 → 7.4.0
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/release.yml +1 -1
- package/.github/workflows/release_pr.yml +1 -1
- package/.github/workflows/run-tests.yml +2 -2
- package/.gitmodules +1 -1
- package/CHANGELOG.md +4 -0
- package/README.md +10 -30
- package/dist/node/pusher.js +127 -37
- package/dist/node/pusher.js.map +1 -1
- package/dist/react-native/pusher.js +2 -2
- package/dist/react-native/pusher.js.map +1 -1
- package/dist/web/pusher-with-encryption.js +127 -37
- package/dist/web/pusher-with-encryption.js.map +1 -1
- package/dist/web/pusher-with-encryption.min.js +2 -2
- package/dist/web/pusher-with-encryption.min.js.map +1 -1
- package/dist/web/pusher.js +127 -37
- package/dist/web/pusher.js.map +1 -1
- package/dist/web/pusher.min.js +2 -2
- package/dist/web/pusher.min.js.map +1 -1
- package/dist/worker/pusher-with-encryption.worker.js +127 -37
- package/dist/worker/pusher-with-encryption.worker.js.map +1 -1
- package/dist/worker/pusher-with-encryption.worker.min.js +2 -2
- package/dist/worker/pusher-with-encryption.worker.min.js.map +1 -1
- package/dist/worker/pusher.worker.js +127 -37
- package/dist/worker/pusher.worker.js.map +1 -1
- package/dist/worker/pusher.worker.min.js +2 -2
- package/dist/worker/pusher.worker.min.js.map +1 -1
- package/package.json +5 -4
- package/spec/javascripts/helpers/timers/promises.js +9 -0
- package/spec/javascripts/unit/core/channels/presence_channel_spec.js +85 -16
- package/spec/javascripts/unit/core/user_spec.js +13 -6
- package/src/core/channels/presence_channel.ts +21 -12
- package/src/core/http/http_socket.ts +3 -1
- package/src/core/pusher.ts +1 -1
- package/src/core/user.ts +65 -27
- package/src/core/utils/flat_promise.ts +10 -0
- package/src/runtimes/interface.ts +1 -0
- package/src/runtimes/node/runtime.ts +5 -0
- package/src/runtimes/react-native/runtime.ts +5 -0
- package/src/runtimes/web/runtime.ts +14 -0
- package/src/runtimes/worker/runtime.ts +14 -0
- package/types/src/core/strategies/transport_strategy.d.ts +3 -0
- package/types/src/core/user.d.ts +5 -1
- package/types/src/core/utils/flat_promise.d.ts +6 -0
- package/types/src/runtimes/interface.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pusher-js",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "Pusher Channels JavaScript library for browsers, React Native, NodeJS and web workers",
|
|
5
5
|
"main": "dist/node/pusher.js",
|
|
6
6
|
"browser": "dist/web/pusher.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"faye-websocket": "^0.11.3",
|
|
39
39
|
"fetch-mock": "git+https://git@github.com/jpatel531/fetch-mock.git",
|
|
40
40
|
"isomorphic-fetch": "^3.0.0",
|
|
41
|
-
"jasmine": "^3.
|
|
41
|
+
"jasmine": "^3.99.0",
|
|
42
42
|
"jasmine-spec-reporter": "^7.0.0",
|
|
43
43
|
"karma": "^6.4.0",
|
|
44
44
|
"karma-browserstack-launcher": "^1.6.0",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"prettier": "^1.19.1",
|
|
55
55
|
"source-map-loader": "^1.1.3",
|
|
56
56
|
"ts-loader": "^6.0.4",
|
|
57
|
-
"typescript": "^3.
|
|
57
|
+
"typescript": "^3.9.0",
|
|
58
58
|
"uglify-js": "^2.6.2",
|
|
59
59
|
"webpack": "^4.46.0",
|
|
60
60
|
"webpack-cli": "^3.3.12",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"xmlhttprequest": "^1.8.0"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"tweetnacl": "^1.0.3"
|
|
66
|
+
"tweetnacl": "^1.0.3",
|
|
67
|
+
"@types/node": "^14.14.31"
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -4,6 +4,8 @@ var Members = require('core/channels/members').default;
|
|
|
4
4
|
var Errors = require('core/errors');
|
|
5
5
|
var Factory = require('core/utils/factory').default;
|
|
6
6
|
var Mocks = require("mocks");
|
|
7
|
+
var flatPromise = require("core/utils/flat_promise").default;
|
|
8
|
+
var { setTimeout } = require("../../../helpers/timers/promises").default;
|
|
7
9
|
|
|
8
10
|
describe("PresenceChannel", function() {
|
|
9
11
|
var pusher;
|
|
@@ -47,7 +49,7 @@ describe("PresenceChannel", function() {
|
|
|
47
49
|
});
|
|
48
50
|
|
|
49
51
|
describe("#authorize", function() {
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
it("should call channelAuthorizer", function() {
|
|
52
54
|
const callback = function(){}
|
|
53
55
|
channel.authorize("1.23", callback);
|
|
@@ -56,30 +58,97 @@ describe("PresenceChannel", function() {
|
|
|
56
58
|
{ socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
it("should call the callback if an
|
|
61
|
+
it("should call the callback if an authorization error is encountered", function() {
|
|
60
62
|
const callback = jasmine.createSpy("callback")
|
|
61
63
|
channel.authorize("1.23", callback);
|
|
62
64
|
expect(channelAuthorizer.calls.count()).toEqual(1);
|
|
63
65
|
expect(channelAuthorizer).toHaveBeenCalledWith(
|
|
64
66
|
{ socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
|
|
65
67
|
const presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
presenceChannelCallback("error", {})
|
|
68
70
|
expect(callback).toHaveBeenCalledWith("error", {})
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
describe("when channel_data isn't present", function() {
|
|
74
|
+
let callback;
|
|
75
|
+
let presenceChannelCallback;
|
|
76
|
+
const authWithoutChannelData = {foo: 'bar'}
|
|
77
|
+
|
|
78
|
+
beforeEach(function() {
|
|
79
|
+
pusher.user = jasmine.createSpy("user");
|
|
80
|
+
|
|
81
|
+
callback = jasmine.createSpy("callback")
|
|
82
|
+
channel.authorize("1.23", callback);
|
|
83
|
+
expect(channelAuthorizer.calls.count()).toEqual(1);
|
|
84
|
+
expect(channelAuthorizer).toHaveBeenCalledWith(
|
|
85
|
+
{ socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
|
|
86
|
+
presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should call the callback with an error if no signin is in progress", async function() {
|
|
90
|
+
pusher.user.signinDonePromise = null;
|
|
91
|
+
|
|
92
|
+
presenceChannelCallback(null, authWithoutChannelData);
|
|
93
|
+
await setTimeout(10);
|
|
94
|
+
expect(callback).toHaveBeenCalledWith("Invalid auth response");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should wait for the in-progress sign in and call the callback with an error if signin failed", async function() {
|
|
98
|
+
const {promise, resolve} = flatPromise();
|
|
99
|
+
pusher.user.signinDonePromise = promise
|
|
100
|
+
|
|
101
|
+
// signin is in progress
|
|
102
|
+
presenceChannelCallback(null, authWithoutChannelData)
|
|
103
|
+
await setTimeout(10);
|
|
104
|
+
expect(callback).not.toHaveBeenCalled()
|
|
105
|
+
|
|
106
|
+
// Signin failed
|
|
107
|
+
pusher.user.user_data = null
|
|
108
|
+
resolve()
|
|
109
|
+
await setTimeout(10);
|
|
110
|
+
expect(callback).toHaveBeenCalledWith("Invalid auth response")
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should wait for the in-progress sign in and call the callback if signin succeeded", async function() {
|
|
114
|
+
const {promise, resolve} = flatPromise();
|
|
115
|
+
pusher.user.signinDonePromise = promise
|
|
116
|
+
|
|
117
|
+
// signin is in progress
|
|
118
|
+
presenceChannelCallback(null, authWithoutChannelData)
|
|
119
|
+
await setTimeout(10);
|
|
120
|
+
expect(callback).not.toHaveBeenCalled()
|
|
121
|
+
|
|
122
|
+
// Signin succeeded
|
|
123
|
+
pusher.user.user_data = {id: '123'}
|
|
124
|
+
resolve()
|
|
125
|
+
await setTimeout(10);
|
|
126
|
+
expect(callback).toHaveBeenCalledWith(null, authWithoutChannelData)
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should call the callback if the user is already signed in", async function() {
|
|
130
|
+
const {promise, resolve} = flatPromise();
|
|
131
|
+
pusher.user.signinDonePromise = promise
|
|
132
|
+
resolve()
|
|
133
|
+
pusher.user.user_data = {id: '123'}
|
|
134
|
+
|
|
135
|
+
// signin is in progress
|
|
136
|
+
presenceChannelCallback(null, authWithoutChannelData)
|
|
137
|
+
await setTimeout(10);
|
|
138
|
+
expect(callback).toHaveBeenCalledWith(null, authWithoutChannelData)
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should call the callback with an error if the user signin already failed", async function() {
|
|
142
|
+
const {promise, resolve} = flatPromise();
|
|
143
|
+
pusher.user.signinDonePromise = promise
|
|
144
|
+
resolve()
|
|
145
|
+
pusher.user.user_data = null
|
|
146
|
+
|
|
147
|
+
// signin is in progress
|
|
148
|
+
presenceChannelCallback(null, authWithoutChannelData)
|
|
149
|
+
await setTimeout(10);
|
|
150
|
+
expect(callback).toHaveBeenCalledWith("Invalid auth response")
|
|
151
|
+
});
|
|
83
152
|
});
|
|
84
153
|
|
|
85
154
|
it("should call the callback with auth data", function() {
|
|
@@ -89,7 +158,7 @@ describe("PresenceChannel", function() {
|
|
|
89
158
|
expect(channelAuthorizer).toHaveBeenCalledWith(
|
|
90
159
|
{ socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
|
|
91
160
|
const presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
|
|
92
|
-
|
|
161
|
+
|
|
93
162
|
const authdata = {
|
|
94
163
|
channel_data: "{\"user_id\":\"123\"}",
|
|
95
164
|
foo: 'bar'
|
|
@@ -82,7 +82,7 @@ describe("Pusher (User)", function () {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
pusher.connection.state = "connected";
|
|
85
|
-
pusher.connection.emit('connected');
|
|
85
|
+
pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
|
|
86
86
|
|
|
87
87
|
expect(pusher.config.userAuthenticator).toHaveBeenCalledWith(
|
|
88
88
|
{ socketId: "1.23" },
|
|
@@ -116,11 +116,11 @@ describe("Pusher (User)", function () {
|
|
|
116
116
|
pusher.config.userAuthenticator.calls.reset()
|
|
117
117
|
|
|
118
118
|
pusher.connection.state == "disconnected";
|
|
119
|
-
pusher.connection.emit(
|
|
119
|
+
pusher.connection.emit('state_change', {previous:'connected', current:'disconnected'});
|
|
120
120
|
pusher.connection.state == "connecting";
|
|
121
|
-
pusher.connection.emit(
|
|
121
|
+
pusher.connection.emit('state_change', {previous:'disconnected', current:'connecting'});
|
|
122
122
|
pusher.connection.state == "connected";
|
|
123
|
-
pusher.connection.emit(
|
|
123
|
+
pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
|
|
124
124
|
|
|
125
125
|
expect(pusher.config.userAuthenticator).toHaveBeenCalledWith(
|
|
126
126
|
{ socketId: "1.23" },
|
|
@@ -134,7 +134,7 @@ describe("Pusher (User)", function () {
|
|
|
134
134
|
|
|
135
135
|
it("should not signin when the connection is connected if signin() was never called", function () {
|
|
136
136
|
pusher.connection.state = "connected";
|
|
137
|
-
pusher.connection.emit('connected');
|
|
137
|
+
pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
|
|
138
138
|
expect(pusher.config.userAuthenticator).not.toHaveBeenCalled();
|
|
139
139
|
})
|
|
140
140
|
|
|
@@ -172,6 +172,7 @@ describe("Pusher (User)", function () {
|
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it('should process pusher:signin_success', async function () {
|
|
175
|
+
pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
|
|
175
176
|
transport.emit('message', {
|
|
176
177
|
data: JSON.stringify({
|
|
177
178
|
event: 'pusher:signin_success',
|
|
@@ -183,6 +184,7 @@ describe("Pusher (User)", function () {
|
|
|
183
184
|
|
|
184
185
|
expect(pusher.user.user_data).toEqual({ id: '1', name: 'test' });
|
|
185
186
|
expect(pusher.user.serverToUserChannel.subscriptionPending).toBe(true);
|
|
187
|
+
expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
|
|
186
188
|
});
|
|
187
189
|
|
|
188
190
|
it('should log warning if user_data is not JSON', async function () {
|
|
@@ -220,6 +222,7 @@ describe("Pusher (User)", function () {
|
|
|
220
222
|
expect(barCallback).not.toHaveBeenCalled();
|
|
221
223
|
|
|
222
224
|
// Sign in successfully
|
|
225
|
+
pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
|
|
223
226
|
transport.emit('message', {
|
|
224
227
|
data: JSON.stringify({
|
|
225
228
|
event: 'pusher:signin_success',
|
|
@@ -242,6 +245,7 @@ describe("Pusher (User)", function () {
|
|
|
242
245
|
'pusher.user.serverToUserChannel.subscribed to be true',
|
|
243
246
|
500
|
|
244
247
|
);
|
|
248
|
+
expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
|
|
245
249
|
|
|
246
250
|
// Send events on channel
|
|
247
251
|
transport.emit('message', {
|
|
@@ -259,6 +263,7 @@ describe("Pusher (User)", function () {
|
|
|
259
263
|
|
|
260
264
|
it('should cleanup the signed in state when disconnected', async function () {
|
|
261
265
|
// Sign in successfully
|
|
266
|
+
pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
|
|
262
267
|
transport.emit('message', {
|
|
263
268
|
data: JSON.stringify({
|
|
264
269
|
event: 'pusher:signin_success',
|
|
@@ -281,11 +286,13 @@ describe("Pusher (User)", function () {
|
|
|
281
286
|
'pusher.user.serverToUserChannel.subscribed to be true',
|
|
282
287
|
500
|
|
283
288
|
);
|
|
289
|
+
expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
|
|
290
|
+
|
|
284
291
|
expect(pusher.user.user_data).toEqual({ id: '1', name: 'test' });
|
|
285
292
|
expect(pusher.user.serverToUserChannel.subscribed).toBe(true);
|
|
286
293
|
|
|
287
294
|
// Disconnect
|
|
288
|
-
pusher.connection.emit('disconnected');
|
|
295
|
+
pusher.connection.emit('state_change', {previous:'connected', current:'disconnected'});
|
|
289
296
|
|
|
290
297
|
expect(pusher.user.user_data).toEqual(null);
|
|
291
298
|
expect(pusher.user.serverToUserChannel).toEqual(null);
|
|
@@ -20,26 +20,35 @@ export default class PresenceChannel extends PrivateChannel {
|
|
|
20
20
|
this.members = new Members();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/** Authorizes the connection as a member of the channel.
|
|
24
24
|
*
|
|
25
25
|
* @param {String} socketId
|
|
26
26
|
* @param {Function} callback
|
|
27
27
|
*/
|
|
28
28
|
authorize(socketId: string, callback: Function) {
|
|
29
|
-
super.authorize(socketId, (error, authData) => {
|
|
29
|
+
super.authorize(socketId, async (error, authData) => {
|
|
30
30
|
if (!error) {
|
|
31
31
|
authData = authData as ChannelAuthorizationData;
|
|
32
|
-
if (authData.channel_data
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
if (authData.channel_data != null) {
|
|
33
|
+
var channelData = JSON.parse(authData.channel_data);
|
|
34
|
+
this.members.setMyID(channelData.user_id);
|
|
35
|
+
} else {
|
|
36
|
+
await this.pusher.user.signinDonePromise;
|
|
37
|
+
if (this.pusher.user.user_data != null) {
|
|
38
|
+
// If the user is signed in, get the id of the authenticated user
|
|
39
|
+
// and allow the presence authorization to continue.
|
|
40
|
+
this.members.setMyID(this.pusher.user.user_data.id);
|
|
41
|
+
} else {
|
|
42
|
+
let suffix = UrlStore.buildLogSuffix('authorizationEndpoint');
|
|
43
|
+
Logger.error(
|
|
44
|
+
`Invalid auth response for channel '${this.name}', ` +
|
|
45
|
+
`expected 'channel_data' field. ${suffix}, ` +
|
|
46
|
+
`or the user should be signed in.`
|
|
47
|
+
);
|
|
48
|
+
callback('Invalid auth response');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
40
51
|
}
|
|
41
|
-
var channelData = JSON.parse(authData.channel_data);
|
|
42
|
-
this.members.setMyID(channelData.user_id);
|
|
43
52
|
}
|
|
44
53
|
callback(error, authData);
|
|
45
54
|
});
|
|
@@ -204,14 +204,16 @@ function replaceHost(url: string, hostname: string): string {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
function randomNumber(max: number): number {
|
|
207
|
-
return
|
|
207
|
+
return Runtime.randomInt(max);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function randomString(length: number): string {
|
|
211
211
|
var result = [];
|
|
212
|
+
|
|
212
213
|
for (var i = 0; i < length; i++) {
|
|
213
214
|
result.push(randomNumber(32).toString(32));
|
|
214
215
|
}
|
|
216
|
+
|
|
215
217
|
return result.join('');
|
|
216
218
|
}
|
|
217
219
|
|
package/src/core/pusher.ts
CHANGED
|
@@ -83,7 +83,7 @@ export default class Pusher {
|
|
|
83
83
|
|
|
84
84
|
this.channels = Factory.createChannels();
|
|
85
85
|
this.global_emitter = new EventsDispatcher();
|
|
86
|
-
this.sessionID =
|
|
86
|
+
this.sessionID = Runtime.randomInt(1000000000);
|
|
87
87
|
|
|
88
88
|
this.timeline = new Timeline(this.key, this.sessionID, {
|
|
89
89
|
cluster: this.config.cluster,
|
package/src/core/user.ts
CHANGED
|
@@ -6,26 +6,29 @@ import {
|
|
|
6
6
|
} from './auth/options';
|
|
7
7
|
import Channel from './channels/channel';
|
|
8
8
|
import EventsDispatcher from './events/dispatcher';
|
|
9
|
+
import flatPromise from './utils/flat_promise';
|
|
9
10
|
|
|
10
11
|
export default class UserFacade extends EventsDispatcher {
|
|
11
12
|
pusher: Pusher;
|
|
12
13
|
signin_requested: boolean = false;
|
|
13
14
|
user_data: any = null;
|
|
14
15
|
serverToUserChannel: Channel = null;
|
|
16
|
+
signinDonePromise: Promise<any> = null;
|
|
17
|
+
private _signinDoneResolve: Function = null;
|
|
15
18
|
|
|
16
19
|
public constructor(pusher: Pusher) {
|
|
17
20
|
super(function(eventName, data) {
|
|
18
21
|
Logger.debug('No callbacks on user for ' + eventName);
|
|
19
22
|
});
|
|
20
23
|
this.pusher = pusher;
|
|
21
|
-
this.pusher.connection.bind('
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
this.pusher.connection.bind('state_change', ({ previous, current }) => {
|
|
25
|
+
if (previous !== 'connected' && current === 'connected') {
|
|
26
|
+
this._signin();
|
|
27
|
+
}
|
|
28
|
+
if (previous === 'connected' && current !== 'connected') {
|
|
29
|
+
this._cleanup();
|
|
30
|
+
this._newSigninPromiseIfNeeded();
|
|
31
|
+
}
|
|
29
32
|
});
|
|
30
33
|
this.pusher.connection.bind('message', event => {
|
|
31
34
|
var eventName = event.event;
|
|
@@ -55,41 +58,45 @@ export default class UserFacade extends EventsDispatcher {
|
|
|
55
58
|
return;
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
this._newSigninPromiseIfNeeded();
|
|
62
|
+
|
|
58
63
|
if (this.pusher.connection.state !== 'connected') {
|
|
59
64
|
// Signin will be attempted when the connection is connected
|
|
60
65
|
return;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
const onAuthorize: UserAuthenticationCallback = (
|
|
64
|
-
err,
|
|
65
|
-
authData: UserAuthenticationData
|
|
66
|
-
) => {
|
|
67
|
-
if (err) {
|
|
68
|
-
Logger.warn(`Error during signin: ${err}`);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
this.pusher.send_event('pusher:signin', {
|
|
73
|
-
auth: authData.auth,
|
|
74
|
-
user_data: authData.user_data
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Later when we get pusher:singin_success event, the user will be marked as signed in
|
|
78
|
-
};
|
|
79
|
-
|
|
80
68
|
this.pusher.config.userAuthenticator(
|
|
81
69
|
{
|
|
82
70
|
socketId: this.pusher.connection.socket_id
|
|
83
71
|
},
|
|
84
|
-
|
|
72
|
+
this._onAuthorize
|
|
85
73
|
);
|
|
86
74
|
}
|
|
87
75
|
|
|
76
|
+
private _onAuthorize: UserAuthenticationCallback = (
|
|
77
|
+
err,
|
|
78
|
+
authData: UserAuthenticationData
|
|
79
|
+
) => {
|
|
80
|
+
if (err) {
|
|
81
|
+
Logger.warn(`Error during signin: ${err}`);
|
|
82
|
+
this._cleanup();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.pusher.send_event('pusher:signin', {
|
|
87
|
+
auth: authData.auth,
|
|
88
|
+
user_data: authData.user_data
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Later when we get pusher:singin_success event, the user will be marked as signed in
|
|
92
|
+
};
|
|
93
|
+
|
|
88
94
|
private _onSigninSuccess(data: any) {
|
|
89
95
|
try {
|
|
90
96
|
this.user_data = JSON.parse(data.user_data);
|
|
91
97
|
} catch (e) {
|
|
92
98
|
Logger.error(`Failed parsing user data after signin: ${data.user_data}`);
|
|
99
|
+
this._cleanup();
|
|
93
100
|
return;
|
|
94
101
|
}
|
|
95
102
|
|
|
@@ -97,9 +104,12 @@ export default class UserFacade extends EventsDispatcher {
|
|
|
97
104
|
Logger.error(
|
|
98
105
|
`user_data doesn't contain an id. user_data: ${this.user_data}`
|
|
99
106
|
);
|
|
107
|
+
this._cleanup();
|
|
100
108
|
return;
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
// Signin succeeded
|
|
112
|
+
this._signinDoneResolve();
|
|
103
113
|
this._subscribeChannels();
|
|
104
114
|
}
|
|
105
115
|
|
|
@@ -132,12 +142,40 @@ export default class UserFacade extends EventsDispatcher {
|
|
|
132
142
|
ensure_subscribed(this.serverToUserChannel);
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
private
|
|
145
|
+
private _cleanup() {
|
|
136
146
|
this.user_data = null;
|
|
137
147
|
if (this.serverToUserChannel) {
|
|
138
148
|
this.serverToUserChannel.unbind_all();
|
|
139
149
|
this.serverToUserChannel.disconnect();
|
|
140
150
|
this.serverToUserChannel = null;
|
|
141
151
|
}
|
|
152
|
+
|
|
153
|
+
if (this.signin_requested) {
|
|
154
|
+
// If signin is in progress and cleanup is called,
|
|
155
|
+
// Mark the current signin process as done.
|
|
156
|
+
this._signinDoneResolve();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private _newSigninPromiseIfNeeded() {
|
|
161
|
+
if (!this.signin_requested) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// If there is a promise and it is not resolved, return without creating a new one.
|
|
166
|
+
if (this.signinDonePromise && !(this.signinDonePromise as any).done) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// This promise is never rejected.
|
|
171
|
+
// It gets resolved when the signin process is done whether it failed or succeeded
|
|
172
|
+
const { promise, resolve, reject: _ } = flatPromise();
|
|
173
|
+
(promise as any).done = false;
|
|
174
|
+
const setDone = () => {
|
|
175
|
+
(promise as any).done = true;
|
|
176
|
+
};
|
|
177
|
+
promise.then(setDone).catch(setDone);
|
|
178
|
+
this.signinDonePromise = promise;
|
|
179
|
+
this._signinDoneResolve = resolve;
|
|
142
180
|
}
|
|
143
181
|
}
|
|
@@ -46,6 +46,7 @@ interface Runtime {
|
|
|
46
46
|
HTTPFactory: HTTPFactory;
|
|
47
47
|
isXHRSupported(): boolean;
|
|
48
48
|
createSocketRequest(method: string, url: string): HTTPRequest;
|
|
49
|
+
randomInt(max: number): number;
|
|
49
50
|
|
|
50
51
|
// these methods/types are only implemented in the web Runtime, so they're
|
|
51
52
|
// optional but must be included in the interface
|
|
@@ -6,6 +6,7 @@ import { Network } from './net_info';
|
|
|
6
6
|
import xhrAuth from 'isomorphic/auth/xhr_auth';
|
|
7
7
|
import { AuthTransports } from 'core/auth/auth_transports';
|
|
8
8
|
import xhrTimeline from 'isomorphic/timeline/xhr_timeline';
|
|
9
|
+
import { randomInt } from 'crypto';
|
|
9
10
|
|
|
10
11
|
// Very verbose but until unavoidable until
|
|
11
12
|
// TypeScript 2.1, when spread attributes will be
|
|
@@ -57,6 +58,10 @@ const NodeJS: Runtime = {
|
|
|
57
58
|
|
|
58
59
|
getNetwork() {
|
|
59
60
|
return Network;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
randomInt(max: number): number {
|
|
64
|
+
return randomInt(max);
|
|
60
65
|
}
|
|
61
66
|
};
|
|
62
67
|
|
|
@@ -4,6 +4,7 @@ import { Network } from './net_info';
|
|
|
4
4
|
import xhrAuth from 'isomorphic/auth/xhr_auth';
|
|
5
5
|
import { AuthTransports } from 'core/auth/auth_transports';
|
|
6
6
|
import xhrTimeline from 'isomorphic/timeline/xhr_timeline';
|
|
7
|
+
import { randomInt } from 'crypto';
|
|
7
8
|
|
|
8
9
|
// Very verbose but until unavoidable until
|
|
9
10
|
// TypeScript 2.1, when spread attributes will be
|
|
@@ -55,6 +56,10 @@ const ReactNative: Runtime = {
|
|
|
55
56
|
|
|
56
57
|
getNetwork() {
|
|
57
58
|
return Network;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
randomInt(max: number): number {
|
|
62
|
+
return randomInt(max);
|
|
58
63
|
}
|
|
59
64
|
};
|
|
60
65
|
|
|
@@ -154,6 +154,20 @@ var Runtime: Browser = {
|
|
|
154
154
|
} else if (window.detachEvent !== undefined) {
|
|
155
155
|
window.detachEvent('onunload', listener);
|
|
156
156
|
}
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
randomInt(max: number): number {
|
|
160
|
+
/**
|
|
161
|
+
* Return values in the range of [0, 1[
|
|
162
|
+
*/
|
|
163
|
+
const random = function() {
|
|
164
|
+
const crypto = window.crypto || window['msCrypto'];
|
|
165
|
+
const random = crypto.getRandomValues(new Uint32Array(1))[0];
|
|
166
|
+
|
|
167
|
+
return random / 2 ** 32;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return Math.floor(random() * max);
|
|
157
171
|
}
|
|
158
172
|
};
|
|
159
173
|
|
|
@@ -55,6 +55,20 @@ const Worker: Runtime = {
|
|
|
55
55
|
|
|
56
56
|
getNetwork() {
|
|
57
57
|
return Network;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
randomInt(max: number): number {
|
|
61
|
+
/**
|
|
62
|
+
* Return values in the range of [0, 1[
|
|
63
|
+
*/
|
|
64
|
+
const random = function() {
|
|
65
|
+
const crypto = window.crypto || window['msCrypto'];
|
|
66
|
+
const random = crypto.getRandomValues(new Uint32Array(1))[0];
|
|
67
|
+
|
|
68
|
+
return random / 2 ** 32;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return Math.floor(random() * max);
|
|
58
72
|
}
|
|
59
73
|
};
|
|
60
74
|
|
|
@@ -9,6 +9,9 @@ export default class TransportStrategy implements Strategy {
|
|
|
9
9
|
constructor(name: string, priority: number, transport: Transport, options: StrategyOptions);
|
|
10
10
|
isSupported(): boolean;
|
|
11
11
|
connect(minPriority: number, callback: Function): {
|
|
12
|
+
abort: () => void;
|
|
13
|
+
forceMinPriority: () => void;
|
|
14
|
+
} | {
|
|
12
15
|
abort: () => void;
|
|
13
16
|
forceMinPriority: (p: any) => void;
|
|
14
17
|
};
|
package/types/src/core/user.d.ts
CHANGED
|
@@ -6,10 +6,14 @@ export default class UserFacade extends EventsDispatcher {
|
|
|
6
6
|
signin_requested: boolean;
|
|
7
7
|
user_data: any;
|
|
8
8
|
serverToUserChannel: Channel;
|
|
9
|
+
signinDonePromise: Promise<any>;
|
|
10
|
+
private _signinDoneResolve;
|
|
9
11
|
constructor(pusher: Pusher);
|
|
10
12
|
signin(): void;
|
|
11
13
|
private _signin;
|
|
14
|
+
private _onAuthorize;
|
|
12
15
|
private _onSigninSuccess;
|
|
13
16
|
private _subscribeChannels;
|
|
14
|
-
private
|
|
17
|
+
private _cleanup;
|
|
18
|
+
private _newSigninPromiseIfNeeded;
|
|
15
19
|
}
|
|
@@ -33,6 +33,7 @@ interface Runtime {
|
|
|
33
33
|
HTTPFactory: HTTPFactory;
|
|
34
34
|
isXHRSupported(): boolean;
|
|
35
35
|
createSocketRequest(method: string, url: string): HTTPRequest;
|
|
36
|
+
randomInt(max: number): number;
|
|
36
37
|
getDocument?(): Document;
|
|
37
38
|
createScriptRequest?(url: string): any;
|
|
38
39
|
createJSONPRequest?(url: string, data: any): JSONPRequest;
|