opal-phoenix 0.0.7 → 0.0.8
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.
- 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
|
+
})));
|