opal-phoenix 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/opal-phoenix.gemspec +4 -3
- data/opal/phoenix/push.rb +1 -1
- data/opal/vendor/phoenix.js +930 -398
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 38ac7cf7be4678294fd06dc5f09bcb1b1b25e89c8f1f460f1667565a2db0b46e
|
4
|
+
data.tar.gz: 07e31ef83dbda2ff2997ab026f406bd0889eb3f43e7104ee3404b5f1dbde19da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6a758d3bd9f8760049a2c30000fc82d7ef80f2366cb7acd24d56ae673b87f099dca853b8fb2804cc35c2b9b4a27181ef7c62cf252089bdcf5046f927a8ff74b
|
7
|
+
data.tar.gz: fa341b8f9f8fb71ccfec3f977888e60b499cce11ad6c83092a9cea21cf15cf86ee8b161064105bc7a3fb62158b70cb6914aca9ff7880796cba990976dd1a8cfe
|
data/opal-phoenix.gemspec
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'opal-phoenix'
|
3
|
-
s.version = '0.0.
|
3
|
+
s.version = '0.0.8'
|
4
4
|
s.authors = ['Michał Kalbarczyk']
|
5
5
|
s.email = 'fazibear@gmail.com'
|
6
6
|
s.homepage = 'http://github.com/fazibear/opal-phoenix'
|
7
7
|
s.summary = 'Phoenix client wrapper for opal'
|
8
8
|
s.description = 'Phoenix client wrapper for opal'
|
9
|
+
s.license = 'MIT'
|
9
10
|
|
10
11
|
s.files = `git ls-files`.split("\n")
|
11
12
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
12
13
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
14
|
s.require_paths = ['lib']
|
14
15
|
|
15
|
-
s.add_dependency 'opal'
|
16
|
-
s.add_development_dependency 'rake'
|
16
|
+
s.add_dependency 'opal', '~> 0'
|
17
|
+
s.add_development_dependency 'rake', '~> 0'
|
17
18
|
end
|
data/opal/phoenix/push.rb
CHANGED
data/opal/vendor/phoenix.js
CHANGED
@@ -1,185 +1,217 @@
|
|
1
|
-
(function(
|
1
|
+
(function (global, factory) {
|
2
|
+
typeof exports === 'object' ? factory(exports) :
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
4
|
+
factory(global.Phoenix = global.Phoenix || {});
|
5
|
+
}(this, (function (exports) {
|
2
6
|
"use strict";
|
3
7
|
|
4
|
-
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
5
|
-
|
6
8
|
Object.defineProperty(exports, "__esModule", {
|
7
9
|
value: true
|
8
10
|
});
|
9
11
|
|
10
|
-
|
12
|
+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
11
13
|
|
12
|
-
function
|
14
|
+
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
15
|
+
|
16
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
17
|
+
|
18
|
+
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
13
19
|
|
14
20
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
15
21
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
//
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
22
|
+
/**
|
23
|
+
* Phoenix Channels JavaScript client
|
24
|
+
*
|
25
|
+
* ## Socket Connection
|
26
|
+
*
|
27
|
+
* A single connection is established to the server and
|
28
|
+
* channels are multiplexed over the connection.
|
29
|
+
* Connect to the server using the `Socket` class:
|
30
|
+
*
|
31
|
+
* ```javascript
|
32
|
+
* let socket = new Socket("/socket", {params: {userToken: "123"}})
|
33
|
+
* socket.connect()
|
34
|
+
* ```
|
35
|
+
*
|
36
|
+
* The `Socket` constructor takes the mount point of the socket,
|
37
|
+
* the authentication params, as well as options that can be found in
|
38
|
+
* the Socket docs, such as configuring the `LongPoll` transport, and
|
39
|
+
* heartbeat.
|
40
|
+
*
|
41
|
+
* ## Channels
|
42
|
+
*
|
43
|
+
* Channels are isolated, concurrent processes on the server that
|
44
|
+
* subscribe to topics and broker events between the client and server.
|
45
|
+
* To join a channel, you must provide the topic, and channel params for
|
46
|
+
* authorization. Here's an example chat room example where `"new_msg"`
|
47
|
+
* events are listened for, messages are pushed to the server, and
|
48
|
+
* the channel is joined with ok/error/timeout matches:
|
49
|
+
*
|
50
|
+
* ```javascript
|
51
|
+
* let channel = socket.channel("room:123", {token: roomToken})
|
52
|
+
* channel.on("new_msg", msg => console.log("Got message", msg) )
|
53
|
+
* $input.onEnter( e => {
|
54
|
+
* channel.push("new_msg", {body: e.target.val}, 10000)
|
55
|
+
* .receive("ok", (msg) => console.log("created message", msg) )
|
56
|
+
* .receive("error", (reasons) => console.log("create failed", reasons) )
|
57
|
+
* .receive("timeout", () => console.log("Networking issue...") )
|
58
|
+
* })
|
59
|
+
*
|
60
|
+
* channel.join()
|
61
|
+
* .receive("ok", ({messages}) => console.log("catching up", messages) )
|
62
|
+
* .receive("error", ({reason}) => console.log("failed join", reason) )
|
63
|
+
* .receive("timeout", () => console.log("Networking issue. Still waiting..."))
|
64
|
+
*```
|
65
|
+
*
|
66
|
+
* ## Joining
|
67
|
+
*
|
68
|
+
* Creating a channel with `socket.channel(topic, params)`, binds the params to
|
69
|
+
* `channel.params`, which are sent up on `channel.join()`.
|
70
|
+
* Subsequent rejoins will send up the modified params for
|
71
|
+
* updating authorization params, or passing up last_message_id information.
|
72
|
+
* Successful joins receive an "ok" status, while unsuccessful joins
|
73
|
+
* receive "error".
|
74
|
+
*
|
75
|
+
* ## Duplicate Join Subscriptions
|
76
|
+
*
|
77
|
+
* While the client may join any number of topics on any number of channels,
|
78
|
+
* the client may only hold a single subscription for each unique topic at any
|
79
|
+
* given time. When attempting to create a duplicate subscription,
|
80
|
+
* the server will close the existing channel, log a warning, and
|
81
|
+
* spawn a new channel for the topic. The client will have their
|
82
|
+
* `channel.onClose` callbacks fired for the existing channel, and the new
|
83
|
+
* channel join will have its receive hooks processed as normal.
|
84
|
+
*
|
85
|
+
* ## Pushing Messages
|
86
|
+
*
|
87
|
+
* From the previous example, we can see that pushing messages to the server
|
88
|
+
* can be done with `channel.push(eventName, payload)` and we can optionally
|
89
|
+
* receive responses from the push. Additionally, we can use
|
90
|
+
* `receive("timeout", callback)` to abort waiting for our other `receive` hooks
|
91
|
+
* and take action after some period of waiting. The default timeout is 10000ms.
|
92
|
+
*
|
93
|
+
*
|
94
|
+
* ## Socket Hooks
|
95
|
+
*
|
96
|
+
* Lifecycle events of the multiplexed connection can be hooked into via
|
97
|
+
* `socket.onError()` and `socket.onClose()` events, ie:
|
98
|
+
*
|
99
|
+
* ```javascript
|
100
|
+
* socket.onError( () => console.log("there was an error with the connection!") )
|
101
|
+
* socket.onClose( () => console.log("the connection dropped") )
|
102
|
+
* ```
|
103
|
+
*
|
104
|
+
*
|
105
|
+
* ## Channel Hooks
|
106
|
+
*
|
107
|
+
* For each joined channel, you can bind to `onError` and `onClose` events
|
108
|
+
* to monitor the channel lifecycle, ie:
|
109
|
+
*
|
110
|
+
* ```javascript
|
111
|
+
* channel.onError( () => console.log("there was an error!") )
|
112
|
+
* channel.onClose( () => console.log("the channel has gone away gracefully") )
|
113
|
+
* ```
|
114
|
+
*
|
115
|
+
* ### onError hooks
|
116
|
+
*
|
117
|
+
* `onError` hooks are invoked if the socket connection drops, or the channel
|
118
|
+
* crashes on the server. In either case, a channel rejoin is attempted
|
119
|
+
* automatically in an exponential backoff manner.
|
120
|
+
*
|
121
|
+
* ### onClose hooks
|
122
|
+
*
|
123
|
+
* `onClose` hooks are invoked only in two cases. 1) the channel explicitly
|
124
|
+
* closed on the server, or 2). The client explicitly closed, by calling
|
125
|
+
* `channel.leave()`
|
126
|
+
*
|
127
|
+
*
|
128
|
+
* ## Presence
|
129
|
+
*
|
130
|
+
* The `Presence` object provides features for syncing presence information
|
131
|
+
* from the server with the client and handling presences joining and leaving.
|
132
|
+
*
|
133
|
+
* ### Syncing initial state from the server
|
134
|
+
*
|
135
|
+
* `Presence.syncState` is used to sync the list of presences on the server
|
136
|
+
* with the client's state. An optional `onJoin` and `onLeave` callback can
|
137
|
+
* be provided to react to changes in the client's local presences across
|
138
|
+
* disconnects and reconnects with the server.
|
139
|
+
*
|
140
|
+
* `Presence.syncDiff` is used to sync a diff of presence join and leave
|
141
|
+
* events from the server, as they happen. Like `syncState`, `syncDiff`
|
142
|
+
* accepts optional `onJoin` and `onLeave` callbacks to react to a user
|
143
|
+
* joining or leaving from a device.
|
144
|
+
*
|
145
|
+
* ### Listing Presences
|
146
|
+
*
|
147
|
+
* `Presence.list` is used to return a list of presence information
|
148
|
+
* based on the local state of metadata. By default, all presence
|
149
|
+
* metadata is returned, but a `listBy` function can be supplied to
|
150
|
+
* allow the client to select which metadata to use for a given presence.
|
151
|
+
* For example, you may have a user online from different devices with
|
152
|
+
* a metadata status of "online", but they have set themselves to "away"
|
153
|
+
* on another device. In this case, the app may choose to use the "away"
|
154
|
+
* status for what appears on the UI. The example below defines a `listBy`
|
155
|
+
* function which prioritizes the first metadata which was registered for
|
156
|
+
* each user. This could be the first tab they opened, or the first device
|
157
|
+
* they came online from:
|
158
|
+
*
|
159
|
+
* ```javascript
|
160
|
+
* let state = {}
|
161
|
+
* state = Presence.syncState(state, stateFromServer)
|
162
|
+
* let listBy = (id, {metas: [first, ...rest]}) => {
|
163
|
+
* first.count = rest.length + 1 // count of this user's presences
|
164
|
+
* first.id = id
|
165
|
+
* return first
|
166
|
+
* }
|
167
|
+
* let onlineUsers = Presence.list(state, listBy)
|
168
|
+
* ```
|
169
|
+
*
|
170
|
+
*
|
171
|
+
* ### Example Usage
|
172
|
+
* ```javascript
|
173
|
+
* // detect if user has joined for the 1st time or from another tab/device
|
174
|
+
* let onJoin = (id, current, newPres) => {
|
175
|
+
* if(!current){
|
176
|
+
* console.log("user has entered for the first time", newPres)
|
177
|
+
* } else {
|
178
|
+
* console.log("user additional presence", newPres)
|
179
|
+
* }
|
180
|
+
* }
|
181
|
+
* // detect if user has left from all tabs/devices, or is still present
|
182
|
+
* let onLeave = (id, current, leftPres) => {
|
183
|
+
* if(current.metas.length === 0){
|
184
|
+
* console.log("user has left from all devices", leftPres)
|
185
|
+
* } else {
|
186
|
+
* console.log("user left from a device", leftPres)
|
187
|
+
* }
|
188
|
+
* }
|
189
|
+
* let presences = {} // client's initial empty presence state
|
190
|
+
* // receive initial presence data from server, sent after join
|
191
|
+
* myChannel.on("presence_state", state => {
|
192
|
+
* presences = Presence.syncState(presences, state, onJoin, onLeave)
|
193
|
+
* displayUsers(Presence.list(presences))
|
194
|
+
* })
|
195
|
+
* // receive "presence_diff" from server, containing join/leave events
|
196
|
+
* myChannel.on("presence_diff", diff => {
|
197
|
+
* presences = Presence.syncDiff(presences, diff, onJoin, onLeave)
|
198
|
+
* this.setState({users: Presence.list(room.presences, listBy)})
|
199
|
+
* })
|
200
|
+
* ```
|
201
|
+
* @module phoenix
|
202
|
+
*/
|
203
|
+
|
204
|
+
var global = typeof self !== "undefined" ? self : window;
|
205
|
+
var VSN = "2.0.0";
|
176
206
|
var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 };
|
177
207
|
var DEFAULT_TIMEOUT = 10000;
|
208
|
+
var WS_CLOSE_NORMAL = 1000;
|
178
209
|
var CHANNEL_STATES = {
|
179
210
|
closed: "closed",
|
180
211
|
errored: "errored",
|
181
212
|
joined: "joined",
|
182
|
-
joining: "joining"
|
213
|
+
joining: "joining",
|
214
|
+
leaving: "leaving"
|
183
215
|
};
|
184
216
|
var CHANNEL_EVENTS = {
|
185
217
|
close: "phx_close",
|
@@ -188,21 +220,21 @@ var CHANNEL_EVENTS = {
|
|
188
220
|
reply: "phx_reply",
|
189
221
|
leave: "phx_leave"
|
190
222
|
};
|
223
|
+
var CHANNEL_LIFECYCLE_EVENTS = [CHANNEL_EVENTS.close, CHANNEL_EVENTS.error, CHANNEL_EVENTS.join, CHANNEL_EVENTS.reply, CHANNEL_EVENTS.leave];
|
191
224
|
var TRANSPORTS = {
|
192
225
|
longpoll: "longpoll",
|
193
226
|
websocket: "websocket"
|
194
227
|
};
|
195
228
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
// timeout - The push timeout in milliseconds
|
204
|
-
//
|
229
|
+
/**
|
230
|
+
* Initializes the Push
|
231
|
+
* @param {Channel} channel - The Channel
|
232
|
+
* @param {string} event - The event, for example `"phx_join"`
|
233
|
+
* @param {Object} payload - The payload, for example `{user_id: 123}`
|
234
|
+
* @param {number} timeout - The push timeout in milliseconds
|
235
|
+
*/
|
205
236
|
|
237
|
+
var Push = function () {
|
206
238
|
function Push(channel, event, payload, timeout) {
|
207
239
|
_classCallCheck(this, Push);
|
208
240
|
|
@@ -216,17 +248,24 @@ var Push = (function () {
|
|
216
248
|
this.sent = false;
|
217
249
|
}
|
218
250
|
|
251
|
+
/**
|
252
|
+
*
|
253
|
+
* @param {number} timeout
|
254
|
+
*/
|
255
|
+
|
256
|
+
|
219
257
|
_createClass(Push, [{
|
220
258
|
key: "resend",
|
221
259
|
value: function resend(timeout) {
|
222
260
|
this.timeout = timeout;
|
223
|
-
this.
|
224
|
-
this.ref = null;
|
225
|
-
this.refEvent = null;
|
226
|
-
this.receivedResp = null;
|
227
|
-
this.sent = false;
|
261
|
+
this.reset();
|
228
262
|
this.send();
|
229
263
|
}
|
264
|
+
|
265
|
+
/**
|
266
|
+
*
|
267
|
+
*/
|
268
|
+
|
230
269
|
}, {
|
231
270
|
key: "send",
|
232
271
|
value: function send() {
|
@@ -239,9 +278,17 @@ var Push = (function () {
|
|
239
278
|
topic: this.channel.topic,
|
240
279
|
event: this.event,
|
241
280
|
payload: this.payload,
|
242
|
-
ref: this.ref
|
281
|
+
ref: this.ref,
|
282
|
+
join_ref: this.channel.joinRef()
|
243
283
|
});
|
244
284
|
}
|
285
|
+
|
286
|
+
/**
|
287
|
+
*
|
288
|
+
* @param {*} status
|
289
|
+
* @param {*} callback
|
290
|
+
*/
|
291
|
+
|
245
292
|
}, {
|
246
293
|
key: "receive",
|
247
294
|
value: function receive(status, callback) {
|
@@ -253,14 +300,43 @@ var Push = (function () {
|
|
253
300
|
return this;
|
254
301
|
}
|
255
302
|
|
256
|
-
|
303
|
+
/**
|
304
|
+
* Updates the Push payload for subsequent resends
|
305
|
+
*
|
306
|
+
* @param {Object} payload
|
307
|
+
* @returns {Push}
|
308
|
+
*/
|
309
|
+
|
310
|
+
}, {
|
311
|
+
key: "updatePayload",
|
312
|
+
value: function updatePayload(payload) {
|
313
|
+
this.payload = payload;
|
314
|
+
}
|
315
|
+
|
316
|
+
/**
|
317
|
+
* @private
|
318
|
+
*/
|
319
|
+
|
320
|
+
}, {
|
321
|
+
key: "reset",
|
322
|
+
value: function reset() {
|
323
|
+
this.cancelRefEvent();
|
324
|
+
this.ref = null;
|
325
|
+
this.refEvent = null;
|
326
|
+
this.receivedResp = null;
|
327
|
+
this.sent = false;
|
328
|
+
}
|
329
|
+
|
330
|
+
/**
|
331
|
+
* @private
|
332
|
+
*/
|
257
333
|
|
258
334
|
}, {
|
259
335
|
key: "matchReceive",
|
260
336
|
value: function matchReceive(_ref) {
|
261
|
-
var status = _ref.status
|
262
|
-
|
263
|
-
|
337
|
+
var status = _ref.status,
|
338
|
+
response = _ref.response,
|
339
|
+
ref = _ref.ref;
|
264
340
|
|
265
341
|
this.recHooks.filter(function (h) {
|
266
342
|
return h.status === status;
|
@@ -268,6 +344,11 @@ var Push = (function () {
|
|
268
344
|
return h.callback(response);
|
269
345
|
});
|
270
346
|
}
|
347
|
+
|
348
|
+
/**
|
349
|
+
* @private
|
350
|
+
*/
|
351
|
+
|
271
352
|
}, {
|
272
353
|
key: "cancelRefEvent",
|
273
354
|
value: function cancelRefEvent() {
|
@@ -276,19 +357,29 @@ var Push = (function () {
|
|
276
357
|
}
|
277
358
|
this.channel.off(this.refEvent);
|
278
359
|
}
|
360
|
+
|
361
|
+
/**
|
362
|
+
* @private
|
363
|
+
*/
|
364
|
+
|
279
365
|
}, {
|
280
366
|
key: "cancelTimeout",
|
281
367
|
value: function cancelTimeout() {
|
282
368
|
clearTimeout(this.timeoutTimer);
|
283
369
|
this.timeoutTimer = null;
|
284
370
|
}
|
371
|
+
|
372
|
+
/**
|
373
|
+
* @private
|
374
|
+
*/
|
375
|
+
|
285
376
|
}, {
|
286
377
|
key: "startTimeout",
|
287
378
|
value: function startTimeout() {
|
288
379
|
var _this = this;
|
289
380
|
|
290
381
|
if (this.timeoutTimer) {
|
291
|
-
|
382
|
+
this.cancelTimeout();
|
292
383
|
}
|
293
384
|
this.ref = this.channel.socket.makeRef();
|
294
385
|
this.refEvent = this.channel.replyEventName(this.ref);
|
@@ -304,11 +395,21 @@ var Push = (function () {
|
|
304
395
|
_this.trigger("timeout", {});
|
305
396
|
}, this.timeout);
|
306
397
|
}
|
398
|
+
|
399
|
+
/**
|
400
|
+
* @private
|
401
|
+
*/
|
402
|
+
|
307
403
|
}, {
|
308
404
|
key: "hasReceived",
|
309
405
|
value: function hasReceived(status) {
|
310
406
|
return this.receivedResp && this.receivedResp.status === status;
|
311
407
|
}
|
408
|
+
|
409
|
+
/**
|
410
|
+
* @private
|
411
|
+
*/
|
412
|
+
|
312
413
|
}, {
|
313
414
|
key: "trigger",
|
314
415
|
value: function trigger(status, response) {
|
@@ -317,9 +418,17 @@ var Push = (function () {
|
|
317
418
|
}]);
|
318
419
|
|
319
420
|
return Push;
|
320
|
-
}
|
421
|
+
}();
|
321
422
|
|
322
|
-
|
423
|
+
/**
|
424
|
+
*
|
425
|
+
* @param {string} topic
|
426
|
+
* @param {Object} params
|
427
|
+
* @param {Socket} socket
|
428
|
+
*/
|
429
|
+
|
430
|
+
|
431
|
+
var Channel = exports.Channel = function () {
|
323
432
|
function Channel(topic, params, socket) {
|
324
433
|
var _this2 = this;
|
325
434
|
|
@@ -330,6 +439,7 @@ var Channel = exports.Channel = (function () {
|
|
330
439
|
this.params = params || {};
|
331
440
|
this.socket = socket;
|
332
441
|
this.bindings = [];
|
442
|
+
this.bindingRef = 0;
|
333
443
|
this.timeout = this.socket.timeout;
|
334
444
|
this.joinedOnce = false;
|
335
445
|
this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout);
|
@@ -346,22 +456,28 @@ var Channel = exports.Channel = (function () {
|
|
346
456
|
_this2.pushBuffer = [];
|
347
457
|
});
|
348
458
|
this.onClose(function () {
|
349
|
-
_this2.
|
459
|
+
_this2.rejoinTimer.reset();
|
460
|
+
_this2.socket.log("channel", "close " + _this2.topic + " " + _this2.joinRef());
|
350
461
|
_this2.state = CHANNEL_STATES.closed;
|
351
462
|
_this2.socket.remove(_this2);
|
352
463
|
});
|
353
464
|
this.onError(function (reason) {
|
465
|
+
if (_this2.isLeaving() || _this2.isClosed()) {
|
466
|
+
return;
|
467
|
+
}
|
354
468
|
_this2.socket.log("channel", "error " + _this2.topic, reason);
|
355
469
|
_this2.state = CHANNEL_STATES.errored;
|
356
470
|
_this2.rejoinTimer.scheduleTimeout();
|
357
471
|
});
|
358
472
|
this.joinPush.receive("timeout", function () {
|
359
|
-
if (_this2.
|
473
|
+
if (!_this2.isJoining()) {
|
360
474
|
return;
|
361
475
|
}
|
362
|
-
|
363
|
-
|
476
|
+
_this2.socket.log("channel", "timeout " + _this2.topic + " (" + _this2.joinRef() + ")", _this2.joinPush.timeout);
|
477
|
+
var leavePush = new Push(_this2, CHANNEL_EVENTS.leave, {}, _this2.timeout);
|
478
|
+
leavePush.send();
|
364
479
|
_this2.state = CHANNEL_STATES.errored;
|
480
|
+
_this2.joinPush.reset();
|
365
481
|
_this2.rejoinTimer.scheduleTimeout();
|
366
482
|
});
|
367
483
|
this.on(CHANNEL_EVENTS.reply, function (payload, ref) {
|
@@ -369,6 +485,11 @@ var Channel = exports.Channel = (function () {
|
|
369
485
|
});
|
370
486
|
}
|
371
487
|
|
488
|
+
/**
|
489
|
+
* @private
|
490
|
+
*/
|
491
|
+
|
492
|
+
|
372
493
|
_createClass(Channel, [{
|
373
494
|
key: "rejoinUntilConnected",
|
374
495
|
value: function rejoinUntilConnected() {
|
@@ -377,52 +498,127 @@ var Channel = exports.Channel = (function () {
|
|
377
498
|
this.rejoin();
|
378
499
|
}
|
379
500
|
}
|
501
|
+
|
502
|
+
/**
|
503
|
+
* Join the channel
|
504
|
+
* @param {integer} timeout
|
505
|
+
* @returns {Push}
|
506
|
+
*/
|
507
|
+
|
380
508
|
}, {
|
381
509
|
key: "join",
|
382
510
|
value: function join() {
|
383
|
-
var timeout = arguments.length
|
511
|
+
var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout;
|
384
512
|
|
385
513
|
if (this.joinedOnce) {
|
386
514
|
throw "tried to join multiple times. 'join' can only be called a single time per channel instance";
|
387
515
|
} else {
|
388
516
|
this.joinedOnce = true;
|
517
|
+
this.rejoin(timeout);
|
518
|
+
return this.joinPush;
|
389
519
|
}
|
390
|
-
this.rejoin(timeout);
|
391
|
-
return this.joinPush;
|
392
520
|
}
|
521
|
+
|
522
|
+
/**
|
523
|
+
* Updates the params passed as the second argument to `new Channel("topic", params, socket)`
|
524
|
+
* Any subsequent reconnects on the channel will send the updated params to the `join` callback on the sever
|
525
|
+
*
|
526
|
+
* @param {Object} params
|
527
|
+
*/
|
528
|
+
|
529
|
+
}, {
|
530
|
+
key: "updateJoinParams",
|
531
|
+
value: function updateJoinParams() {
|
532
|
+
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
533
|
+
|
534
|
+
this.params = params;
|
535
|
+
this.joinPush.updatePayload(params);
|
536
|
+
}
|
537
|
+
|
538
|
+
/**
|
539
|
+
* Hook into channel close
|
540
|
+
* @param {Function} callback
|
541
|
+
*/
|
542
|
+
|
393
543
|
}, {
|
394
544
|
key: "onClose",
|
395
545
|
value: function onClose(callback) {
|
396
546
|
this.on(CHANNEL_EVENTS.close, callback);
|
397
547
|
}
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Hook into channel errors
|
551
|
+
* @param {Function} callback
|
552
|
+
*/
|
553
|
+
|
398
554
|
}, {
|
399
555
|
key: "onError",
|
400
556
|
value: function onError(callback) {
|
401
|
-
this.on(CHANNEL_EVENTS.error, function (reason) {
|
557
|
+
return this.on(CHANNEL_EVENTS.error, function (reason) {
|
402
558
|
return callback(reason);
|
403
559
|
});
|
404
560
|
}
|
561
|
+
|
562
|
+
/**
|
563
|
+
* Subscribes on channel events
|
564
|
+
*
|
565
|
+
* Subscription returns a ref counter, which can be used later to
|
566
|
+
* unsubscribe the exact event listener
|
567
|
+
*
|
568
|
+
* @example
|
569
|
+
* const ref1 = channel.on("event", do_stuff)
|
570
|
+
* const ref2 = channel.on("event", do_other_stuff)
|
571
|
+
* channel.off("event", ref1)
|
572
|
+
* // Since unsubscription, do_stuff won't fire,
|
573
|
+
* // while do_other_stuff will keep firing on the "event"
|
574
|
+
*
|
575
|
+
* @param {string} event
|
576
|
+
* @param {Function} callback
|
577
|
+
* @returns {integer} ref
|
578
|
+
*/
|
579
|
+
|
405
580
|
}, {
|
406
581
|
key: "on",
|
407
582
|
value: function on(event, callback) {
|
408
|
-
|
583
|
+
var ref = this.bindingRef++;
|
584
|
+
this.bindings.push({ event: event, ref: ref, callback: callback });
|
585
|
+
return ref;
|
409
586
|
}
|
587
|
+
|
588
|
+
/**
|
589
|
+
* @param {string} event
|
590
|
+
* @param {integer} ref
|
591
|
+
*/
|
592
|
+
|
410
593
|
}, {
|
411
594
|
key: "off",
|
412
|
-
value: function off(event) {
|
595
|
+
value: function off(event, ref) {
|
413
596
|
this.bindings = this.bindings.filter(function (bind) {
|
414
|
-
return bind.event
|
597
|
+
return !(bind.event === event && (typeof ref === "undefined" || ref === bind.ref));
|
415
598
|
});
|
416
599
|
}
|
600
|
+
|
601
|
+
/**
|
602
|
+
* @private
|
603
|
+
*/
|
604
|
+
|
417
605
|
}, {
|
418
606
|
key: "canPush",
|
419
607
|
value: function canPush() {
|
420
|
-
return this.socket.isConnected() && this.
|
608
|
+
return this.socket.isConnected() && this.isJoined();
|
421
609
|
}
|
610
|
+
|
611
|
+
/**
|
612
|
+
* @param {string} event
|
613
|
+
* @param {Object} payload
|
614
|
+
* @param {number} [timeout]
|
615
|
+
* @returns {Push}
|
616
|
+
*/
|
617
|
+
|
422
618
|
}, {
|
423
619
|
key: "push",
|
424
620
|
value: function push(event, payload) {
|
425
|
-
var timeout = arguments.length
|
621
|
+
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.timeout;
|
426
622
|
|
427
623
|
if (!this.joinedOnce) {
|
428
624
|
throw "tried to push '" + event + "' to '" + this.topic + "' before joining. Use channel.join() before pushing events";
|
@@ -438,26 +634,31 @@ var Channel = exports.Channel = (function () {
|
|
438
634
|
return pushEvent;
|
439
635
|
}
|
440
636
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
637
|
+
/** Leaves the channel
|
638
|
+
*
|
639
|
+
* Unsubscribes from server events, and
|
640
|
+
* instructs channel to terminate on server
|
641
|
+
*
|
642
|
+
* Triggers onClose() hooks
|
643
|
+
*
|
644
|
+
* To receive leave acknowledgements, use the a `receive`
|
645
|
+
* hook to bind to the server ack, ie:
|
646
|
+
*
|
647
|
+
* @example
|
648
|
+
* channel.leave().receive("ok", () => alert("left!") )
|
649
|
+
*
|
650
|
+
* @param {integer} timeout
|
651
|
+
* @returns {Push}
|
652
|
+
*/
|
453
653
|
|
454
654
|
}, {
|
455
655
|
key: "leave",
|
456
656
|
value: function leave() {
|
457
657
|
var _this3 = this;
|
458
658
|
|
459
|
-
var timeout = arguments.length
|
659
|
+
var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout;
|
460
660
|
|
661
|
+
this.state = CHANNEL_STATES.leaving;
|
461
662
|
var onClose = function onClose() {
|
462
663
|
_this3.socket.log("channel", "leave " + _this3.topic);
|
463
664
|
_this3.trigger(CHANNEL_EVENTS.close, "leave");
|
@@ -476,88 +677,245 @@ var Channel = exports.Channel = (function () {
|
|
476
677
|
return leavePush;
|
477
678
|
}
|
478
679
|
|
479
|
-
|
480
|
-
|
481
|
-
|
680
|
+
/**
|
681
|
+
* Overridable message hook
|
682
|
+
*
|
683
|
+
* Receives all events for specialized message handling
|
684
|
+
* before dispatching to the channel callbacks.
|
685
|
+
*
|
686
|
+
* Must return the payload, modified or unmodified
|
687
|
+
* @param {string} event
|
688
|
+
* @param {Object} payload
|
689
|
+
* @param {integer} ref
|
690
|
+
* @returns {Object}
|
691
|
+
*/
|
482
692
|
|
483
693
|
}, {
|
484
694
|
key: "onMessage",
|
485
|
-
value: function onMessage(event, payload, ref) {
|
695
|
+
value: function onMessage(event, payload, ref) {
|
696
|
+
return payload;
|
697
|
+
}
|
486
698
|
|
487
|
-
|
699
|
+
/**
|
700
|
+
* @private
|
701
|
+
*/
|
488
702
|
|
489
703
|
}, {
|
490
704
|
key: "isMember",
|
491
|
-
value: function isMember(topic) {
|
492
|
-
|
705
|
+
value: function isMember(topic, event, payload, joinRef) {
|
706
|
+
if (this.topic !== topic) {
|
707
|
+
return false;
|
708
|
+
}
|
709
|
+
var isLifecycleEvent = CHANNEL_LIFECYCLE_EVENTS.indexOf(event) >= 0;
|
710
|
+
|
711
|
+
if (joinRef && isLifecycleEvent && joinRef !== this.joinRef()) {
|
712
|
+
this.socket.log("channel", "dropping outdated message", { topic: topic, event: event, payload: payload, joinRef: joinRef });
|
713
|
+
return false;
|
714
|
+
} else {
|
715
|
+
return true;
|
716
|
+
}
|
717
|
+
}
|
718
|
+
|
719
|
+
/**
|
720
|
+
* @private
|
721
|
+
*/
|
722
|
+
|
723
|
+
}, {
|
724
|
+
key: "joinRef",
|
725
|
+
value: function joinRef() {
|
726
|
+
return this.joinPush.ref;
|
493
727
|
}
|
728
|
+
|
729
|
+
/**
|
730
|
+
* @private
|
731
|
+
*/
|
732
|
+
|
494
733
|
}, {
|
495
734
|
key: "sendJoin",
|
496
735
|
value: function sendJoin(timeout) {
|
497
736
|
this.state = CHANNEL_STATES.joining;
|
498
737
|
this.joinPush.resend(timeout);
|
499
738
|
}
|
739
|
+
|
740
|
+
/**
|
741
|
+
* @private
|
742
|
+
*/
|
743
|
+
|
500
744
|
}, {
|
501
745
|
key: "rejoin",
|
502
746
|
value: function rejoin() {
|
503
|
-
var timeout = arguments.length
|
747
|
+
var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout;
|
748
|
+
if (this.isLeaving()) {
|
749
|
+
return;
|
750
|
+
}
|
504
751
|
this.sendJoin(timeout);
|
505
752
|
}
|
753
|
+
|
754
|
+
/**
|
755
|
+
* @private
|
756
|
+
*/
|
757
|
+
|
506
758
|
}, {
|
507
759
|
key: "trigger",
|
508
|
-
value: function trigger(
|
509
|
-
|
760
|
+
value: function trigger(event, payload, ref, joinRef) {
|
761
|
+
var _this4 = this;
|
762
|
+
|
763
|
+
var handledPayload = this.onMessage(event, payload, ref, joinRef);
|
764
|
+
if (payload && !handledPayload) {
|
765
|
+
throw "channel onMessage callbacks must return the payload, modified or unmodified";
|
766
|
+
}
|
767
|
+
|
510
768
|
this.bindings.filter(function (bind) {
|
511
|
-
return bind.event ===
|
769
|
+
return bind.event === event;
|
512
770
|
}).map(function (bind) {
|
513
|
-
return bind.callback(
|
771
|
+
return bind.callback(handledPayload, ref, joinRef || _this4.joinRef());
|
514
772
|
});
|
515
773
|
}
|
774
|
+
|
775
|
+
/**
|
776
|
+
* @private
|
777
|
+
*/
|
778
|
+
|
516
779
|
}, {
|
517
780
|
key: "replyEventName",
|
518
781
|
value: function replyEventName(ref) {
|
519
782
|
return "chan_reply_" + ref;
|
520
783
|
}
|
784
|
+
|
785
|
+
/**
|
786
|
+
* @private
|
787
|
+
*/
|
788
|
+
|
789
|
+
}, {
|
790
|
+
key: "isClosed",
|
791
|
+
value: function isClosed() {
|
792
|
+
return this.state === CHANNEL_STATES.closed;
|
793
|
+
}
|
794
|
+
|
795
|
+
/**
|
796
|
+
* @private
|
797
|
+
*/
|
798
|
+
|
799
|
+
}, {
|
800
|
+
key: "isErrored",
|
801
|
+
value: function isErrored() {
|
802
|
+
return this.state === CHANNEL_STATES.errored;
|
803
|
+
}
|
804
|
+
|
805
|
+
/**
|
806
|
+
* @private
|
807
|
+
*/
|
808
|
+
|
809
|
+
}, {
|
810
|
+
key: "isJoined",
|
811
|
+
value: function isJoined() {
|
812
|
+
return this.state === CHANNEL_STATES.joined;
|
813
|
+
}
|
814
|
+
|
815
|
+
/**
|
816
|
+
* @private
|
817
|
+
*/
|
818
|
+
|
819
|
+
}, {
|
820
|
+
key: "isJoining",
|
821
|
+
value: function isJoining() {
|
822
|
+
return this.state === CHANNEL_STATES.joining;
|
823
|
+
}
|
824
|
+
|
825
|
+
/**
|
826
|
+
* @private
|
827
|
+
*/
|
828
|
+
|
829
|
+
}, {
|
830
|
+
key: "isLeaving",
|
831
|
+
value: function isLeaving() {
|
832
|
+
return this.state === CHANNEL_STATES.leaving;
|
833
|
+
}
|
521
834
|
}]);
|
522
835
|
|
523
836
|
return Channel;
|
524
|
-
}
|
525
|
-
|
526
|
-
var
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
// return [1000, 5000, 10000][tries - 1] || 10000
|
544
|
-
// }
|
545
|
-
//
|
546
|
-
// logger - The optional function for specialized logging, ie:
|
547
|
-
// `logger: (kind, msg, data) => { console.log(`${kind}: ${msg}`, data) }
|
548
|
-
//
|
549
|
-
// longpollerTimeout - The maximum timeout of a long poll AJAX request.
|
550
|
-
// Defaults to 20s (double the server long poll timer).
|
551
|
-
//
|
552
|
-
// params - The optional params to pass when connecting
|
553
|
-
//
|
554
|
-
// For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim)
|
555
|
-
//
|
837
|
+
}();
|
838
|
+
|
839
|
+
var Serializer = {
|
840
|
+
encode: function encode(msg, callback) {
|
841
|
+
var payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];
|
842
|
+
return callback(JSON.stringify(payload));
|
843
|
+
},
|
844
|
+
decode: function decode(rawPayload, callback) {
|
845
|
+
var _JSON$parse = JSON.parse(rawPayload),
|
846
|
+
_JSON$parse2 = _slicedToArray(_JSON$parse, 5),
|
847
|
+
join_ref = _JSON$parse2[0],
|
848
|
+
ref = _JSON$parse2[1],
|
849
|
+
topic = _JSON$parse2[2],
|
850
|
+
event = _JSON$parse2[3],
|
851
|
+
payload = _JSON$parse2[4];
|
852
|
+
|
853
|
+
return callback({ join_ref: join_ref, ref: ref, topic: topic, event: event, payload: payload });
|
854
|
+
}
|
855
|
+
};
|
556
856
|
|
857
|
+
/** Initializes the Socket
|
858
|
+
*
|
859
|
+
*
|
860
|
+
* For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim)
|
861
|
+
*
|
862
|
+
* @param {string} endPoint - The string WebSocket endpoint, ie, `"ws://example.com/socket"`,
|
863
|
+
* `"wss://example.com"`
|
864
|
+
* `"/socket"` (inherited host & protocol)
|
865
|
+
* @param {Object} [opts] - Optional configuration
|
866
|
+
* @param {string} [opts.transport] - The Websocket Transport, for example WebSocket or Phoenix.LongPoll.
|
867
|
+
*
|
868
|
+
* Defaults to WebSocket with automatic LongPoll fallback.
|
869
|
+
* @param {Function} [opts.encode] - The function to encode outgoing messages.
|
870
|
+
*
|
871
|
+
* Defaults to JSON:
|
872
|
+
*
|
873
|
+
* ```javascript
|
874
|
+
* (payload, callback) => callback(JSON.stringify(payload))
|
875
|
+
* ```
|
876
|
+
*
|
877
|
+
* @param {Function} [opts.decode] - The function to decode incoming messages.
|
878
|
+
*
|
879
|
+
* Defaults to JSON:
|
880
|
+
*
|
881
|
+
* ```javascript
|
882
|
+
* (payload, callback) => callback(JSON.parse(payload))
|
883
|
+
* ```
|
884
|
+
*
|
885
|
+
* @param {number} [opts.timeout] - The default timeout in milliseconds to trigger push timeouts.
|
886
|
+
*
|
887
|
+
* Defaults `DEFAULT_TIMEOUT`
|
888
|
+
* @param {number} [opts.heartbeatIntervalMs] - The millisec interval to send a heartbeat message
|
889
|
+
* @param {number} [opts.reconnectAfterMs] - The optional function that returns the millsec reconnect interval.
|
890
|
+
*
|
891
|
+
* Defaults to stepped backoff of:
|
892
|
+
*
|
893
|
+
* ```javascript
|
894
|
+
* function(tries){
|
895
|
+
* return [1000, 5000, 10000][tries - 1] || 10000
|
896
|
+
* }
|
897
|
+
* ```
|
898
|
+
* @param {Function} [opts.logger] - The optional function for specialized logging, ie:
|
899
|
+
* ```javascript
|
900
|
+
* function(kind, msg, data) {
|
901
|
+
* console.log(`${kind}: ${msg}`, data)
|
902
|
+
* }
|
903
|
+
* ```
|
904
|
+
*
|
905
|
+
* @param {number} [opts.longpollerTimeout] - The maximum timeout of a long poll AJAX request.
|
906
|
+
*
|
907
|
+
* Defaults to 20s (double the server long poll timer).
|
908
|
+
*
|
909
|
+
* @param {Object} [opts.params] - The optional params to pass when connecting
|
910
|
+
*
|
911
|
+
*
|
912
|
+
*/
|
913
|
+
|
914
|
+
var Socket = exports.Socket = function () {
|
557
915
|
function Socket(endPoint) {
|
558
|
-
var
|
916
|
+
var _this5 = this;
|
559
917
|
|
560
|
-
var opts = arguments.length
|
918
|
+
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
561
919
|
|
562
920
|
_classCallCheck(this, Socket);
|
563
921
|
|
@@ -566,7 +924,16 @@ var Socket = exports.Socket = (function () {
|
|
566
924
|
this.sendBuffer = [];
|
567
925
|
this.ref = 0;
|
568
926
|
this.timeout = opts.timeout || DEFAULT_TIMEOUT;
|
569
|
-
this.transport = opts.transport ||
|
927
|
+
this.transport = opts.transport || global.WebSocket || LongPoll;
|
928
|
+
this.defaultEncoder = Serializer.encode;
|
929
|
+
this.defaultDecoder = Serializer.decode;
|
930
|
+
if (this.transport !== LongPoll) {
|
931
|
+
this.encode = opts.encode || this.defaultEncoder;
|
932
|
+
this.decode = opts.decode || this.defaultDecoder;
|
933
|
+
} else {
|
934
|
+
this.encode = this.defaultEncoder;
|
935
|
+
this.decode = this.defaultDecoder;
|
936
|
+
}
|
570
937
|
this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 30000;
|
571
938
|
this.reconnectAfterMs = opts.reconnectAfterMs || function (tries) {
|
572
939
|
return [1000, 2000, 5000, 10000][tries - 1] || 10000;
|
@@ -575,18 +942,34 @@ var Socket = exports.Socket = (function () {
|
|
575
942
|
this.longpollerTimeout = opts.longpollerTimeout || 20000;
|
576
943
|
this.params = opts.params || {};
|
577
944
|
this.endPoint = endPoint + "/" + TRANSPORTS.websocket;
|
945
|
+
this.heartbeatTimer = null;
|
946
|
+
this.pendingHeartbeatRef = null;
|
578
947
|
this.reconnectTimer = new Timer(function () {
|
579
|
-
|
580
|
-
return
|
948
|
+
_this5.disconnect(function () {
|
949
|
+
return _this5.connect();
|
581
950
|
});
|
582
951
|
}, this.reconnectAfterMs);
|
583
952
|
}
|
584
953
|
|
954
|
+
/**
|
955
|
+
* Returns the socket protocol
|
956
|
+
*
|
957
|
+
* @returns {string}
|
958
|
+
*/
|
959
|
+
|
960
|
+
|
585
961
|
_createClass(Socket, [{
|
586
962
|
key: "protocol",
|
587
963
|
value: function protocol() {
|
588
964
|
return location.protocol.match(/^https/) ? "wss" : "ws";
|
589
965
|
}
|
966
|
+
|
967
|
+
/**
|
968
|
+
* The fully qualifed socket url
|
969
|
+
*
|
970
|
+
* @returns {string}
|
971
|
+
*/
|
972
|
+
|
590
973
|
}, {
|
591
974
|
key: "endPointURL",
|
592
975
|
value: function endPointURL() {
|
@@ -600,6 +983,13 @@ var Socket = exports.Socket = (function () {
|
|
600
983
|
|
601
984
|
return this.protocol() + "://" + location.host + uri;
|
602
985
|
}
|
986
|
+
|
987
|
+
/**
|
988
|
+
* @param {Function} callback
|
989
|
+
* @param {integer} code
|
990
|
+
* @param {string} reason
|
991
|
+
*/
|
992
|
+
|
603
993
|
}, {
|
604
994
|
key: "disconnect",
|
605
995
|
value: function disconnect(callback, code, reason) {
|
@@ -615,12 +1005,15 @@ var Socket = exports.Socket = (function () {
|
|
615
1005
|
callback && callback();
|
616
1006
|
}
|
617
1007
|
|
618
|
-
|
1008
|
+
/**
|
1009
|
+
*
|
1010
|
+
* @param {Object} params - The params to send when connecting, for example `{user_id: userToken}`
|
1011
|
+
*/
|
619
1012
|
|
620
1013
|
}, {
|
621
1014
|
key: "connect",
|
622
1015
|
value: function connect(params) {
|
623
|
-
var
|
1016
|
+
var _this6 = this;
|
624
1017
|
|
625
1018
|
if (params) {
|
626
1019
|
console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor");
|
@@ -633,20 +1026,25 @@ var Socket = exports.Socket = (function () {
|
|
633
1026
|
this.conn = new this.transport(this.endPointURL());
|
634
1027
|
this.conn.timeout = this.longpollerTimeout;
|
635
1028
|
this.conn.onopen = function () {
|
636
|
-
return
|
1029
|
+
return _this6.onConnOpen();
|
637
1030
|
};
|
638
1031
|
this.conn.onerror = function (error) {
|
639
|
-
return
|
1032
|
+
return _this6.onConnError(error);
|
640
1033
|
};
|
641
1034
|
this.conn.onmessage = function (event) {
|
642
|
-
return
|
1035
|
+
return _this6.onConnMessage(event);
|
643
1036
|
};
|
644
1037
|
this.conn.onclose = function (event) {
|
645
|
-
return
|
1038
|
+
return _this6.onConnClose(event);
|
646
1039
|
};
|
647
1040
|
}
|
648
1041
|
|
649
|
-
|
1042
|
+
/**
|
1043
|
+
* Logs the message. Override `this.logger` for specialized logging. noops by default
|
1044
|
+
* @param {string} kind
|
1045
|
+
* @param {string} msg
|
1046
|
+
* @param {Object} data
|
1047
|
+
*/
|
650
1048
|
|
651
1049
|
}, {
|
652
1050
|
key: "log",
|
@@ -654,51 +1052,83 @@ var Socket = exports.Socket = (function () {
|
|
654
1052
|
this.logger(kind, msg, data);
|
655
1053
|
}
|
656
1054
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
1055
|
+
/**
|
1056
|
+
* Registers callbacks for connection open events
|
1057
|
+
*
|
1058
|
+
* @example socket.onOpen(function(){ console.info("the socket was opened") })
|
1059
|
+
*
|
1060
|
+
* @param {Function} callback
|
1061
|
+
*/
|
663
1062
|
|
664
1063
|
}, {
|
665
1064
|
key: "onOpen",
|
666
1065
|
value: function onOpen(callback) {
|
667
1066
|
this.stateChangeCallbacks.open.push(callback);
|
668
1067
|
}
|
1068
|
+
|
1069
|
+
/**
|
1070
|
+
* Registers callbacks for connection close events
|
1071
|
+
* @param {Function} callback
|
1072
|
+
*/
|
1073
|
+
|
669
1074
|
}, {
|
670
1075
|
key: "onClose",
|
671
1076
|
value: function onClose(callback) {
|
672
1077
|
this.stateChangeCallbacks.close.push(callback);
|
673
1078
|
}
|
1079
|
+
|
1080
|
+
/**
|
1081
|
+
* Registers callbacks for connection error events
|
1082
|
+
*
|
1083
|
+
* @example socket.onError(function(error){ alert("An error occurred") })
|
1084
|
+
*
|
1085
|
+
* @param {Function} callback
|
1086
|
+
*/
|
1087
|
+
|
674
1088
|
}, {
|
675
1089
|
key: "onError",
|
676
1090
|
value: function onError(callback) {
|
677
1091
|
this.stateChangeCallbacks.error.push(callback);
|
678
1092
|
}
|
1093
|
+
|
1094
|
+
/**
|
1095
|
+
* Registers callbacks for connection message events
|
1096
|
+
* @param {Function} callback
|
1097
|
+
*/
|
1098
|
+
|
679
1099
|
}, {
|
680
1100
|
key: "onMessage",
|
681
1101
|
value: function onMessage(callback) {
|
682
1102
|
this.stateChangeCallbacks.message.push(callback);
|
683
1103
|
}
|
1104
|
+
|
1105
|
+
/**
|
1106
|
+
* @private
|
1107
|
+
*/
|
1108
|
+
|
684
1109
|
}, {
|
685
1110
|
key: "onConnOpen",
|
686
1111
|
value: function onConnOpen() {
|
687
|
-
var
|
1112
|
+
var _this7 = this;
|
688
1113
|
|
689
|
-
this.log("transport", "connected to " + this.endPointURL()
|
1114
|
+
this.log("transport", "connected to " + this.endPointURL());
|
690
1115
|
this.flushSendBuffer();
|
691
1116
|
this.reconnectTimer.reset();
|
692
1117
|
if (!this.conn.skipHeartbeat) {
|
693
1118
|
clearInterval(this.heartbeatTimer);
|
694
1119
|
this.heartbeatTimer = setInterval(function () {
|
695
|
-
return
|
1120
|
+
return _this7.sendHeartbeat();
|
696
1121
|
}, this.heartbeatIntervalMs);
|
697
1122
|
}
|
698
1123
|
this.stateChangeCallbacks.open.forEach(function (callback) {
|
699
1124
|
return callback();
|
700
1125
|
});
|
701
1126
|
}
|
1127
|
+
|
1128
|
+
/**
|
1129
|
+
* @private
|
1130
|
+
*/
|
1131
|
+
|
702
1132
|
}, {
|
703
1133
|
key: "onConnClose",
|
704
1134
|
value: function onConnClose(event) {
|
@@ -710,6 +1140,11 @@ var Socket = exports.Socket = (function () {
|
|
710
1140
|
return callback(event);
|
711
1141
|
});
|
712
1142
|
}
|
1143
|
+
|
1144
|
+
/**
|
1145
|
+
* @private
|
1146
|
+
*/
|
1147
|
+
|
713
1148
|
}, {
|
714
1149
|
key: "onConnError",
|
715
1150
|
value: function onConnError(error) {
|
@@ -719,6 +1154,11 @@ var Socket = exports.Socket = (function () {
|
|
719
1154
|
return callback(error);
|
720
1155
|
});
|
721
1156
|
}
|
1157
|
+
|
1158
|
+
/**
|
1159
|
+
* @private
|
1160
|
+
*/
|
1161
|
+
|
722
1162
|
}, {
|
723
1163
|
key: "triggerChanError",
|
724
1164
|
value: function triggerChanError() {
|
@@ -726,6 +1166,11 @@ var Socket = exports.Socket = (function () {
|
|
726
1166
|
return channel.trigger(CHANNEL_EVENTS.error);
|
727
1167
|
});
|
728
1168
|
}
|
1169
|
+
|
1170
|
+
/**
|
1171
|
+
* @returns {string}
|
1172
|
+
*/
|
1173
|
+
|
729
1174
|
}, {
|
730
1175
|
key: "connectionState",
|
731
1176
|
value: function connectionState() {
|
@@ -740,41 +1185,68 @@ var Socket = exports.Socket = (function () {
|
|
740
1185
|
return "closed";
|
741
1186
|
}
|
742
1187
|
}
|
1188
|
+
|
1189
|
+
/**
|
1190
|
+
* @returns {boolean}
|
1191
|
+
*/
|
1192
|
+
|
743
1193
|
}, {
|
744
1194
|
key: "isConnected",
|
745
1195
|
value: function isConnected() {
|
746
1196
|
return this.connectionState() === "open";
|
747
1197
|
}
|
1198
|
+
|
1199
|
+
/**
|
1200
|
+
* @param {Channel}
|
1201
|
+
*/
|
1202
|
+
|
748
1203
|
}, {
|
749
1204
|
key: "remove",
|
750
1205
|
value: function remove(channel) {
|
751
1206
|
this.channels = this.channels.filter(function (c) {
|
752
|
-
return
|
1207
|
+
return c.joinRef() !== channel.joinRef();
|
753
1208
|
});
|
754
1209
|
}
|
1210
|
+
|
1211
|
+
/**
|
1212
|
+
* Initiates a new channel for the given topic
|
1213
|
+
*
|
1214
|
+
* @param {string} topic
|
1215
|
+
* @param {Object} chanParams - Parameters for the channel
|
1216
|
+
* @returns {Channel}
|
1217
|
+
*/
|
1218
|
+
|
755
1219
|
}, {
|
756
1220
|
key: "channel",
|
757
1221
|
value: function channel(topic) {
|
758
|
-
var chanParams = arguments.length
|
1222
|
+
var chanParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
759
1223
|
|
760
1224
|
var chan = new Channel(topic, chanParams, this);
|
761
1225
|
this.channels.push(chan);
|
762
1226
|
return chan;
|
763
1227
|
}
|
1228
|
+
|
1229
|
+
/**
|
1230
|
+
* @param {Object} data
|
1231
|
+
*/
|
1232
|
+
|
764
1233
|
}, {
|
765
1234
|
key: "push",
|
766
1235
|
value: function push(data) {
|
767
|
-
var
|
1236
|
+
var _this8 = this;
|
768
1237
|
|
769
|
-
var topic = data.topic
|
770
|
-
|
771
|
-
|
772
|
-
|
1238
|
+
var topic = data.topic,
|
1239
|
+
event = data.event,
|
1240
|
+
payload = data.payload,
|
1241
|
+
ref = data.ref,
|
1242
|
+
join_ref = data.join_ref;
|
773
1243
|
|
774
1244
|
var callback = function callback() {
|
775
|
-
|
1245
|
+
_this8.encode(data, function (result) {
|
1246
|
+
_this8.conn.send(result);
|
1247
|
+
});
|
776
1248
|
};
|
777
|
-
this.log("push", topic + " " + event + " (" + ref + ")", payload);
|
1249
|
+
this.log("push", topic + " " + event + " (" + join_ref + ", " + ref + ")", payload);
|
778
1250
|
if (this.isConnected()) {
|
779
1251
|
callback();
|
780
1252
|
} else {
|
@@ -782,7 +1254,10 @@ var Socket = exports.Socket = (function () {
|
|
782
1254
|
}
|
783
1255
|
}
|
784
1256
|
|
785
|
-
|
1257
|
+
/**
|
1258
|
+
* Return the next message ref, accounting for overflows
|
1259
|
+
* @returns {string}
|
1260
|
+
*/
|
786
1261
|
|
787
1262
|
}, {
|
788
1263
|
key: "makeRef",
|
@@ -802,7 +1277,14 @@ var Socket = exports.Socket = (function () {
|
|
802
1277
|
if (!this.isConnected()) {
|
803
1278
|
return;
|
804
1279
|
}
|
805
|
-
|
1280
|
+
if (this.pendingHeartbeatRef) {
|
1281
|
+
this.pendingHeartbeatRef = null;
|
1282
|
+
this.log("transport", "heartbeat timeout. Attempting to re-establish connection");
|
1283
|
+
this.conn.close(WS_CLOSE_NORMAL, "hearbeat timeout");
|
1284
|
+
return;
|
1285
|
+
}
|
1286
|
+
this.pendingHeartbeatRef = this.makeRef();
|
1287
|
+
this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef });
|
806
1288
|
}
|
807
1289
|
}, {
|
808
1290
|
key: "flushSendBuffer",
|
@@ -817,28 +1299,36 @@ var Socket = exports.Socket = (function () {
|
|
817
1299
|
}, {
|
818
1300
|
key: "onConnMessage",
|
819
1301
|
value: function onConnMessage(rawMessage) {
|
820
|
-
var
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
1302
|
+
var _this9 = this;
|
1303
|
+
|
1304
|
+
this.decode(rawMessage.data, function (msg) {
|
1305
|
+
var topic = msg.topic,
|
1306
|
+
event = msg.event,
|
1307
|
+
payload = msg.payload,
|
1308
|
+
ref = msg.ref,
|
1309
|
+
join_ref = msg.join_ref;
|
1310
|
+
|
1311
|
+
if (ref && ref === _this9.pendingHeartbeatRef) {
|
1312
|
+
_this9.pendingHeartbeatRef = null;
|
1313
|
+
}
|
1314
|
+
|
1315
|
+
_this9.log("receive", (payload.status || "") + " " + topic + " " + event + " " + (ref && "(" + ref + ")" || ""), payload);
|
1316
|
+
_this9.channels.filter(function (channel) {
|
1317
|
+
return channel.isMember(topic, event, payload, join_ref);
|
1318
|
+
}).forEach(function (channel) {
|
1319
|
+
return channel.trigger(event, payload, ref, join_ref);
|
1320
|
+
});
|
1321
|
+
_this9.stateChangeCallbacks.message.forEach(function (callback) {
|
1322
|
+
return callback(msg);
|
1323
|
+
});
|
834
1324
|
});
|
835
1325
|
}
|
836
1326
|
}]);
|
837
1327
|
|
838
1328
|
return Socket;
|
839
|
-
}
|
1329
|
+
}();
|
840
1330
|
|
841
|
-
var LongPoll = exports.LongPoll =
|
1331
|
+
var LongPoll = exports.LongPoll = function () {
|
842
1332
|
function LongPoll(endPoint) {
|
843
1333
|
_classCallCheck(this, LongPoll);
|
844
1334
|
|
@@ -880,7 +1370,7 @@ var LongPoll = exports.LongPoll = (function () {
|
|
880
1370
|
}, {
|
881
1371
|
key: "poll",
|
882
1372
|
value: function poll() {
|
883
|
-
var
|
1373
|
+
var _this10 = this;
|
884
1374
|
|
885
1375
|
if (!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)) {
|
886
1376
|
return;
|
@@ -888,11 +1378,11 @@ var LongPoll = exports.LongPoll = (function () {
|
|
888
1378
|
|
889
1379
|
Ajax.request("GET", this.endpointURL(), "application/json", null, this.timeout, this.ontimeout.bind(this), function (resp) {
|
890
1380
|
if (resp) {
|
891
|
-
var status = resp.status
|
892
|
-
|
893
|
-
|
1381
|
+
var status = resp.status,
|
1382
|
+
token = resp.token,
|
1383
|
+
messages = resp.messages;
|
894
1384
|
|
895
|
-
|
1385
|
+
_this10.token = token;
|
896
1386
|
} else {
|
897
1387
|
var status = 0;
|
898
1388
|
}
|
@@ -900,22 +1390,22 @@ var LongPoll = exports.LongPoll = (function () {
|
|
900
1390
|
switch (status) {
|
901
1391
|
case 200:
|
902
1392
|
messages.forEach(function (msg) {
|
903
|
-
return
|
1393
|
+
return _this10.onmessage({ data: msg });
|
904
1394
|
});
|
905
|
-
|
1395
|
+
_this10.poll();
|
906
1396
|
break;
|
907
1397
|
case 204:
|
908
|
-
|
1398
|
+
_this10.poll();
|
909
1399
|
break;
|
910
1400
|
case 410:
|
911
|
-
|
912
|
-
|
913
|
-
|
1401
|
+
_this10.readyState = SOCKET_STATES.open;
|
1402
|
+
_this10.onopen();
|
1403
|
+
_this10.poll();
|
914
1404
|
break;
|
915
1405
|
case 0:
|
916
1406
|
case 500:
|
917
|
-
|
918
|
-
|
1407
|
+
_this10.onerror();
|
1408
|
+
_this10.closeAndRetry();
|
919
1409
|
break;
|
920
1410
|
default:
|
921
1411
|
throw "unhandled poll status " + status;
|
@@ -925,12 +1415,12 @@ var LongPoll = exports.LongPoll = (function () {
|
|
925
1415
|
}, {
|
926
1416
|
key: "send",
|
927
1417
|
value: function send(body) {
|
928
|
-
var
|
1418
|
+
var _this11 = this;
|
929
1419
|
|
930
1420
|
Ajax.request("POST", this.endpointURL(), "application/json", body, this.timeout, this.onerror.bind(this, "timeout"), function (resp) {
|
931
1421
|
if (!resp || resp.status !== 200) {
|
932
|
-
|
933
|
-
|
1422
|
+
_this11.onerror(resp && resp.status);
|
1423
|
+
_this11.closeAndRetry();
|
934
1424
|
}
|
935
1425
|
});
|
936
1426
|
}
|
@@ -943,9 +1433,9 @@ var LongPoll = exports.LongPoll = (function () {
|
|
943
1433
|
}]);
|
944
1434
|
|
945
1435
|
return LongPoll;
|
946
|
-
}
|
1436
|
+
}();
|
947
1437
|
|
948
|
-
var Ajax = exports.Ajax =
|
1438
|
+
var Ajax = exports.Ajax = function () {
|
949
1439
|
function Ajax() {
|
950
1440
|
_classCallCheck(this, Ajax);
|
951
1441
|
}
|
@@ -953,24 +1443,24 @@ var Ajax = exports.Ajax = (function () {
|
|
953
1443
|
_createClass(Ajax, null, [{
|
954
1444
|
key: "request",
|
955
1445
|
value: function request(method, endPoint, accept, body, timeout, ontimeout, callback) {
|
956
|
-
if (
|
1446
|
+
if (global.XDomainRequest) {
|
957
1447
|
var req = new XDomainRequest(); // IE8, IE9
|
958
1448
|
this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback);
|
959
1449
|
} else {
|
960
|
-
var
|
1450
|
+
var _req = global.XMLHttpRequest ? new global.XMLHttpRequest() : // IE7+, Firefox, Chrome, Opera, Safari
|
961
1451
|
new ActiveXObject("Microsoft.XMLHTTP"); // IE6, IE5
|
962
|
-
this.xhrRequest(
|
1452
|
+
this.xhrRequest(_req, method, endPoint, accept, body, timeout, ontimeout, callback);
|
963
1453
|
}
|
964
1454
|
}
|
965
1455
|
}, {
|
966
1456
|
key: "xdomainRequest",
|
967
1457
|
value: function xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) {
|
968
|
-
var
|
1458
|
+
var _this12 = this;
|
969
1459
|
|
970
1460
|
req.timeout = timeout;
|
971
1461
|
req.open(method, endPoint);
|
972
1462
|
req.onload = function () {
|
973
|
-
var response =
|
1463
|
+
var response = _this12.parseJSON(req.responseText);
|
974
1464
|
callback && callback(response);
|
975
1465
|
};
|
976
1466
|
if (ontimeout) {
|
@@ -985,17 +1475,17 @@ var Ajax = exports.Ajax = (function () {
|
|
985
1475
|
}, {
|
986
1476
|
key: "xhrRequest",
|
987
1477
|
value: function xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) {
|
988
|
-
var
|
1478
|
+
var _this13 = this;
|
989
1479
|
|
990
|
-
req.timeout = timeout;
|
991
1480
|
req.open(method, endPoint, true);
|
1481
|
+
req.timeout = timeout;
|
992
1482
|
req.setRequestHeader("Content-Type", accept);
|
993
1483
|
req.onerror = function () {
|
994
1484
|
callback && callback(null);
|
995
1485
|
};
|
996
1486
|
req.onreadystatechange = function () {
|
997
|
-
if (req.readyState ===
|
998
|
-
var response =
|
1487
|
+
if (req.readyState === _this13.states.complete && callback) {
|
1488
|
+
var response = _this13.parseJSON(req.responseText);
|
999
1489
|
callback(response);
|
1000
1490
|
}
|
1001
1491
|
};
|
@@ -1008,7 +1498,16 @@ var Ajax = exports.Ajax = (function () {
|
|
1008
1498
|
}, {
|
1009
1499
|
key: "parseJSON",
|
1010
1500
|
value: function parseJSON(resp) {
|
1011
|
-
|
1501
|
+
if (!resp || resp === "") {
|
1502
|
+
return null;
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
try {
|
1506
|
+
return JSON.parse(resp);
|
1507
|
+
} catch (e) {
|
1508
|
+
console && console.log("failed to parse JSON response", resp);
|
1509
|
+
return null;
|
1510
|
+
}
|
1012
1511
|
}
|
1013
1512
|
}, {
|
1014
1513
|
key: "serialize",
|
@@ -1041,76 +1540,101 @@ var Ajax = exports.Ajax = (function () {
|
|
1041
1540
|
}]);
|
1042
1541
|
|
1043
1542
|
return Ajax;
|
1044
|
-
}
|
1543
|
+
}();
|
1045
1544
|
|
1046
1545
|
Ajax.states = { complete: 4 };
|
1047
1546
|
|
1048
1547
|
var Presence = exports.Presence = {
|
1049
|
-
syncState: function syncState(
|
1050
|
-
var
|
1548
|
+
syncState: function syncState(currentState, newState, onJoin, onLeave) {
|
1549
|
+
var _this14 = this;
|
1051
1550
|
|
1551
|
+
var state = this.clone(currentState);
|
1552
|
+
state.presences = state.presences || {};
|
1553
|
+
state.synced = true;
|
1554
|
+
var pendingDiffs = state.pendingDiffs || [];
|
1052
1555
|
var joins = {};
|
1053
1556
|
var leaves = {};
|
1054
1557
|
|
1055
|
-
this.map(state, function (key, presence) {
|
1558
|
+
this.map(state.presences, function (key, presence) {
|
1056
1559
|
if (!newState[key]) {
|
1057
|
-
leaves[key] =
|
1560
|
+
leaves[key] = presence;
|
1058
1561
|
}
|
1059
1562
|
});
|
1060
1563
|
this.map(newState, function (key, newPresence) {
|
1061
|
-
var currentPresence = state[key];
|
1564
|
+
var currentPresence = state.presences[key];
|
1062
1565
|
if (currentPresence) {
|
1063
|
-
(function () {
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
}
|
1084
|
-
})();
|
1566
|
+
var newRefs = newPresence.metas.map(function (m) {
|
1567
|
+
return m.phx_ref;
|
1568
|
+
});
|
1569
|
+
var curRefs = currentPresence.metas.map(function (m) {
|
1570
|
+
return m.phx_ref;
|
1571
|
+
});
|
1572
|
+
var joinedMetas = newPresence.metas.filter(function (m) {
|
1573
|
+
return curRefs.indexOf(m.phx_ref) < 0;
|
1574
|
+
});
|
1575
|
+
var leftMetas = currentPresence.metas.filter(function (m) {
|
1576
|
+
return newRefs.indexOf(m.phx_ref) < 0;
|
1577
|
+
});
|
1578
|
+
if (joinedMetas.length > 0) {
|
1579
|
+
joins[key] = newPresence;
|
1580
|
+
joins[key].metas = joinedMetas;
|
1581
|
+
}
|
1582
|
+
if (leftMetas.length > 0) {
|
1583
|
+
leaves[key] = _this14.clone(currentPresence);
|
1584
|
+
leaves[key].metas = leftMetas;
|
1585
|
+
}
|
1085
1586
|
} else {
|
1086
1587
|
joins[key] = newPresence;
|
1087
1588
|
}
|
1088
1589
|
});
|
1089
|
-
|
1590
|
+
|
1591
|
+
state = this.syncDiff(state, { joins: joins, leaves: leaves }, onJoin, onLeave);
|
1592
|
+
|
1593
|
+
pendingDiffs.forEach(function (diff) {
|
1594
|
+
state = _this14.syncDiff(state, { joins: diff.joins, leaves: diff.leaves }, diff.onJoin, diff.onLeave);
|
1595
|
+
});
|
1596
|
+
state.pendingDiffs = [];
|
1597
|
+
|
1598
|
+
return state;
|
1090
1599
|
},
|
1091
|
-
syncDiff: function syncDiff(
|
1092
|
-
var joins = _ref2.joins
|
1093
|
-
|
1600
|
+
syncDiff: function syncDiff(currentState, _ref2, onJoin, onLeave) {
|
1601
|
+
var joins = _ref2.joins,
|
1602
|
+
leaves = _ref2.leaves;
|
1603
|
+
|
1604
|
+
var state = this.clone(currentState);
|
1605
|
+
state.presences = state.presences || {};
|
1606
|
+
state.pendingDiffs = state.pendingDiffs || [];
|
1607
|
+
|
1608
|
+
if (!state.synced) {
|
1609
|
+
state.pendingDiffs.push({ joins: joins, leaves: leaves, onJoin: onJoin, onLeave: onLeave });
|
1610
|
+
return state;
|
1611
|
+
}
|
1094
1612
|
|
1095
1613
|
if (!onJoin) {
|
1096
|
-
onJoin = function () {};
|
1614
|
+
onJoin = function onJoin() {};
|
1097
1615
|
}
|
1098
1616
|
if (!onLeave) {
|
1099
|
-
onLeave = function () {};
|
1617
|
+
onLeave = function onLeave() {};
|
1100
1618
|
}
|
1101
1619
|
|
1102
1620
|
this.map(joins, function (key, newPresence) {
|
1103
|
-
var currentPresence = state[key];
|
1104
|
-
state[key] = newPresence;
|
1621
|
+
var currentPresence = state.presences[key];
|
1622
|
+
state.presences[key] = newPresence;
|
1105
1623
|
if (currentPresence) {
|
1106
|
-
var _state$key
|
1624
|
+
var _state$presences$key$;
|
1107
1625
|
|
1108
|
-
|
1626
|
+
var joinedRefs = state.presences[key].metas.map(function (m) {
|
1627
|
+
return m.phx_ref;
|
1628
|
+
});
|
1629
|
+
var curMetas = currentPresence.metas.filter(function (m) {
|
1630
|
+
return joinedRefs.indexOf(m.phx_ref) < 0;
|
1631
|
+
});
|
1632
|
+
(_state$presences$key$ = state.presences[key].metas).unshift.apply(_state$presences$key$, _toConsumableArray(curMetas));
|
1109
1633
|
}
|
1110
1634
|
onJoin(key, currentPresence, newPresence);
|
1111
1635
|
});
|
1112
1636
|
this.map(leaves, function (key, leftPresence) {
|
1113
|
-
var currentPresence = state[key];
|
1637
|
+
var currentPresence = state.presences[key];
|
1114
1638
|
if (!currentPresence) {
|
1115
1639
|
return;
|
1116
1640
|
}
|
@@ -1122,13 +1646,15 @@ var Presence = exports.Presence = {
|
|
1122
1646
|
});
|
1123
1647
|
onLeave(key, currentPresence, leftPresence);
|
1124
1648
|
if (currentPresence.metas.length === 0) {
|
1125
|
-
delete state[key];
|
1649
|
+
delete state.presences[key];
|
1126
1650
|
}
|
1127
1651
|
});
|
1652
|
+
return state;
|
1128
1653
|
},
|
1129
|
-
list: function list(
|
1654
|
+
list: function list(state, chooser) {
|
1655
|
+
var presences = state.presences || {};
|
1130
1656
|
if (!chooser) {
|
1131
|
-
chooser = function (key, pres) {
|
1657
|
+
chooser = function chooser(key, pres) {
|
1132
1658
|
return pres;
|
1133
1659
|
};
|
1134
1660
|
}
|
@@ -1138,6 +1664,7 @@ var Presence = exports.Presence = {
|
|
1138
1664
|
});
|
1139
1665
|
},
|
1140
1666
|
|
1667
|
+
|
1141
1668
|
// private
|
1142
1669
|
|
1143
1670
|
map: function map(obj, func) {
|
@@ -1150,21 +1677,25 @@ var Presence = exports.Presence = {
|
|
1150
1677
|
}
|
1151
1678
|
};
|
1152
1679
|
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
//
|
1166
|
-
|
1167
|
-
|
1680
|
+
/**
|
1681
|
+
*
|
1682
|
+
* Creates a timer that accepts a `timerCalc` function to perform
|
1683
|
+
* calculated timeout retries, such as exponential backoff.
|
1684
|
+
*
|
1685
|
+
* @example
|
1686
|
+
* let reconnectTimer = new Timer(() => this.connect(), function(tries){
|
1687
|
+
* return [1000, 5000, 10000][tries - 1] || 10000
|
1688
|
+
* })
|
1689
|
+
* reconnectTimer.scheduleTimeout() // fires after 1000
|
1690
|
+
* reconnectTimer.scheduleTimeout() // fires after 5000
|
1691
|
+
* reconnectTimer.reset()
|
1692
|
+
* reconnectTimer.scheduleTimeout() // fires after 1000
|
1693
|
+
*
|
1694
|
+
* @param {Function} callback
|
1695
|
+
* @param {Function} timerCalc
|
1696
|
+
*/
|
1697
|
+
|
1698
|
+
var Timer = function () {
|
1168
1699
|
function Timer(callback, timerCalc) {
|
1169
1700
|
_classCallCheck(this, Timer);
|
1170
1701
|
|
@@ -1181,24 +1712,25 @@ var Timer = (function () {
|
|
1181
1712
|
clearTimeout(this.timer);
|
1182
1713
|
}
|
1183
1714
|
|
1184
|
-
|
1715
|
+
/**
|
1716
|
+
* Cancels any previous scheduleTimeout and schedules callback
|
1717
|
+
*/
|
1185
1718
|
|
1186
1719
|
}, {
|
1187
1720
|
key: "scheduleTimeout",
|
1188
1721
|
value: function scheduleTimeout() {
|
1189
|
-
var
|
1722
|
+
var _this15 = this;
|
1190
1723
|
|
1191
1724
|
clearTimeout(this.timer);
|
1192
1725
|
|
1193
1726
|
this.timer = setTimeout(function () {
|
1194
|
-
|
1195
|
-
|
1727
|
+
_this15.tries = _this15.tries + 1;
|
1728
|
+
_this15.callback();
|
1196
1729
|
}, this.timerCalc(this.tries + 1));
|
1197
1730
|
}
|
1198
1731
|
}]);
|
1199
1732
|
|
1200
1733
|
return Timer;
|
1201
|
-
}
|
1202
|
-
|
1734
|
+
}();
|
1203
1735
|
|
1204
|
-
})
|
1736
|
+
})));
|