pubsub-js-client 0.6.1 → 25.0.6

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.

Potentially problematic release.


This version of pubsub-js-client might be problematic. Click here for more details.

@@ -1,177 +0,0 @@
1
-
2
- import EventsDispatcher from "./events";
3
- import logging from "./log";
4
- import util from "./util";
5
- import IframeClient from "./IframeClient";
6
- import IframeHost from "./IframeHost";
7
- import WebsocketClient from "./WebsocketClient";
8
- import PubsubTest from "./PubsubTest";
9
-
10
- var logger = logging._getLogger("PubsubDriver");
11
-
12
- const SOCKET_CLOSED_RECONNECT_TIME = 1 * 1000; // 1 second
13
- const RESPONSE_TIMEOUT = 30 * 1000; // 30 seconds
14
- const ERR_RESPONSE_TIMEOUT = "response timeout";
15
- const NONCE_LENGTH = 30;
16
- const DEFER_TEST_TIME = 30 * 1000; // 30 seconds
17
-
18
- const twitchUrlRegexp = /^https?:\/\/([\w-]+\.)*twitch\.(tv|tech)(:\d+)?\/.*$/;
19
-
20
- var pctTester = 0.0;
21
-
22
- class PubsubDriver extends EventsDispatcher {
23
-
24
- constructor (env) {
25
- // opts should include: environment
26
- super(env);
27
-
28
- this._env = util.urlParams.pubsub_environment || env;
29
-
30
- this._clientReady = false;
31
- this._hasDisconnected = false;
32
- this._queuedRequests = [];
33
-
34
- this._numDisconnects = 0;
35
-
36
- if (util.inIframe() && twitchUrlRegexp.test(document.referrer)) {
37
- // check parent location, if ok, create iframe with specified domain
38
- logger.debug("Driver is in an iframe");
39
- this._client = new IframeClient({
40
- parentUrl: document.referrer
41
- });
42
- this._clientType = "iframe-verified";
43
- } else {
44
- logger.debug("Driver is not in an iframe");
45
- this._client = new WebsocketClient({
46
- env: this._env
47
- });
48
- this._iframeHost = new IframeHost(this._client);
49
- this._clientType = "ws";
50
- }
51
-
52
- // Pubsub Tester
53
- if (util.urlParams.force_pubsub_tester === "true") {
54
- pctTester = 1.0;
55
- } else if (util.urlParams.force_pubsub_tester === "false") {
56
- pctTester = 0.0;
57
- }
58
- if (Math.random() < pctTester) {
59
- // Defer starting the test to avoid wasting resources during page load.
60
- window.setTimeout(this.runTest.bind(this), DEFER_TEST_TIME);
61
- }
62
-
63
- this._client.on("unverified", this._clientUnverified, this);
64
- this._client.on("verified", this._clientVerified, this);
65
- this._client.verify();
66
- }
67
-
68
- runTest () {
69
- this._tester = new PubsubTest({
70
- env: this._env,
71
- driver: this
72
- });
73
- }
74
-
75
- connect () {
76
- // return this._client.connect();
77
- }
78
-
79
- Listen (opts) {
80
- if (this._clientReady) {
81
- this._client.Listen(opts);
82
- } else {
83
- this._queuedRequests.push({type: "LISTEN", opts: opts});
84
- }
85
- }
86
-
87
- Unlisten (opts) {
88
- if (this._clientReady) {
89
- this._client.Unlisten(opts);
90
- } else {
91
- this._queuedRequests.push({type: "UNLISTEN", opts: opts});
92
- }
93
- }
94
-
95
- simulateReceivedMessage(topic, message) {
96
- const msg = {
97
- data: {message, topic},
98
- type: "MESSAGE-SIMULATED"
99
- };
100
- this._client._onMessage(msg);
101
- }
102
-
103
- _flushQueuedRequests () {
104
- logger.debug("Flushing " + this._queuedRequests.length + " queued requests");
105
- while (this._queuedRequests.length > 0) {
106
- var req = this._queuedRequests.shift();
107
- switch (req.type) {
108
- case "LISTEN":
109
- this._client.Listen(req.opts);
110
- break;
111
- case "UNLISTEN":
112
- this._client.Unlisten(req.opts);
113
- break;
114
- }
115
- }
116
- }
117
-
118
- _clientConnected () {
119
- logger.debug("Client connected");
120
- this._client.on("disconnected", this._clientDisconnected, this);
121
- this._trigger("connected");
122
- if (this._hasDisconnected) {
123
- this._trigger("reconnected");
124
- }
125
- this._clientReady = true;
126
- this._flushQueuedRequests();
127
- }
128
-
129
- _clientDisconnected () {
130
- logger.debug("Client disconnected");
131
- this._trigger("disconnected");
132
- this._clientReady = false;
133
- this._numDisconnects += 1;
134
- this._hasDisconnected = true;
135
- }
136
-
137
- _clientVerified () {
138
- logger.debug("Client verified (type = " + this._clientType + ")");
139
- this._client.on("connected", this._clientConnected, this);
140
- this._client.connect();
141
- }
142
-
143
- _clientUnverified () {
144
- // only triggered by iframe clients
145
- logger.debug("Unverified IframeClient");
146
- this._client.off("verified", this._clientVerified, this);
147
- this._client.off("unverified", this._clientUnverified, this);
148
-
149
- this._client = new WebsocketClient({
150
- env: this._env
151
- });
152
- this._clientType = "iframe-unverified";
153
-
154
- this._client.on("unverified", this._clientUnverified, this);
155
- this._client.on("verified", this._clientVerified, this);
156
- this._client.verify();
157
- }
158
- }
159
-
160
- window.__Twitch__pubsubInstances = window.__Twitch__pubsubInstances || {
161
- production: null,
162
- staging: null,
163
- darklaunch: null
164
- };
165
-
166
- function getInstance(env) {
167
- if (env !== "production" && env !== "staging" && env !== "darklaunch") {
168
- throw "Invalid Pubsub instance environment";
169
- }
170
- if (window.__Twitch__pubsubInstances[env] === null) {
171
- // create driver
172
- window.__Twitch__pubsubInstances[env] = new PubsubDriver(env);
173
- }
174
- return window.__Twitch__pubsubInstances[env];
175
- }
176
-
177
- export default {getInstance};
@@ -1,186 +0,0 @@
1
- import EventsDispatcher from "./events";
2
- import logging from "./log";
3
- import util from "./util";
4
-
5
- var logger = logging._getLogger("PubsubSocket");
6
-
7
- const MAX_CONNECTION_DELAY = 120;
8
-
9
- const ERR_SOCKET_CLOSED = "socket_closed";
10
- const ERR_PONG_TIMEOUT = "missed_pong";
11
- const ERR_CONNECTION_FAILED = "max_connection_attempts";
12
- const ERR_NOT_READY = "not_ready";
13
- const ERR_FAILED_SEND = "failed_send";
14
-
15
- const PONG_TIMEOUT = 30 * 1000; // 30 seconds
16
- const PING_INTERVAL = 4 * 60 * 1000; // 4 minutes
17
-
18
- /*
19
- PubsubSocket is responsible for managing the WebSocket connction to Pubsub Edge, hiding the details of ping/pong, connection retries, and parsing received message types from the PubsubDriver.
20
- It retries connecting with exponential backoff if it fails to connect.
21
- When it opens, it triggers an "open" event.
22
- If it closes unexpectedly, it triggers a "connection_failure" event.
23
- It handles pings/pongs, and triggers a "pong_timeout" event if a pong isn't received.
24
- If it is intentionally closed, it triggers a "closed" event when it closes.
25
- If it receives a RESPONSE type message from the Pubsub, it triggers a "response" event.
26
- If it receives a MESSAGE type message from the Pubsub, it triggers a "message" event.
27
- If it receives a RECONNECT type message from the Pubsub, it triggers a "reconnect" event.
28
- */
29
-
30
- class PubsubSocket extends EventsDispatcher {
31
- constructor (opts) {
32
- super(opts);
33
- this._opts = opts;
34
- this._addr = opts.addr;
35
-
36
- this._connectionAttempts = 0;
37
- this._sentPing = this._receivedPong = false;
38
-
39
- this._id = "[" + util.generateString(10) + "] ";
40
-
41
- window.addEventListener("beforeunload", this._beforeUnload.bind(this));
42
- }
43
-
44
- connect () {
45
- logger.debug(this._id + "connecting to " + this._addr);
46
- this._connecting = true;
47
- try {
48
- this._socket = new WebSocket(this._addr);
49
- this._socket.onmessage = this._onMessage.bind(this);
50
- this._socket.onerror = this._onError.bind(this);
51
- this._socket.onclose = this._onClose.bind(this);
52
- this._socket.onopen = this._onOpen.bind(this);
53
- } catch (e) {
54
- this._trigger("connection_failure");
55
- }
56
- }
57
-
58
- close () {
59
- logger.debug(this._id + "closing");
60
- this._closing = true;
61
- this._clearTimeouts();
62
- this._socket.close();
63
- }
64
-
65
- send (msg) {
66
- logger.debug(this._id + "sending " + JSON.stringify(msg));
67
- if (this._isReady()) {
68
- this._socket.send(JSON.stringify(msg));
69
- } else {
70
- this._trigger("error", ERR_NOT_READY);
71
- }
72
- }
73
-
74
- _isReady () {
75
- logger.debug(this._id + "_isReady called");
76
- if (this._socket) {
77
- return (this._socket.readyState === WebSocket.OPEN);
78
- } else {
79
- return false;
80
- }
81
- }
82
-
83
- _onMessage (event) {
84
- logger.debug(this._id + "received message: " + event.data);
85
- try {
86
- var msg = JSON.parse(event.data);
87
- switch (msg.type) {
88
- case "RESPONSE":
89
- this._trigger("response", msg);
90
- break;
91
- case "MESSAGE":
92
- this._trigger("message", msg);
93
- break;
94
- case "PONG":
95
- this._receivedPong = true;
96
- break;
97
- case "RECONNECT":
98
- this._trigger("reconnect");
99
- break;
100
- }
101
- } catch (e) {
102
- // bad json parse
103
- logger.debug("onMessage JSON Parse error: " + e);
104
- }
105
- }
106
-
107
- _onError (event) {
108
- // Irrelevant since the _onClose event is about to be triggered
109
- logger.debug(this._id + "error: " + JSON.stringify(event));
110
- }
111
-
112
- _onClose (event) {
113
- logger.debug(this._id + "onClose triggered with code " + event.code + "(closing = " + this._closing + ", connecting = " + this._connecting + ")");
114
- this._clearTimeouts();
115
- if (this._connecting) {
116
- // Failed during connection, retry with exponential backoff
117
- var connectionDelay = Math.pow(2, this._connectionAttempts);
118
- if (connectionDelay > MAX_CONNECTION_DELAY) {
119
- connectionDelay = MAX_CONNECTION_DELAY;
120
- }
121
- logger.debug(this._id + "reconnecting in " + connectionDelay + " seconds");
122
- this._connectionAttempts += 1;
123
- this._nextConnectionAttempt = setTimeout(this.connect.bind(this), 1000 * connectionDelay);
124
- } else if (this._closing) {
125
- // Intentionally closed itself (due to an error), don't send an 'unexpected_closed' error since the relevant error will have already been sent
126
- this._closed = true;
127
- this._trigger("connection_failure");
128
- } else if (this._windowUnloading) {
129
- // Closed because the browser window is being refreshed or redirected
130
- // Don't trigger anything, whole object is going to be destroyed by the browser anyhow
131
- return;
132
- } else {
133
- // Unintentionally closed, trigger an error so the Driver knows to re-fetch state
134
- logger.debug(this._id + "unexpected close");
135
- var line = "pubsub-js-client unexpected_close. code: " + event.code + ", reason: " + event.reason + ", wasClean: " + event.wasClean;
136
- this._closed = true;
137
- this._trigger("connection_failure");
138
- }
139
- }
140
-
141
- _onOpen (event) {
142
- logger.debug(this._id + " socket opened");
143
- this._connectionAttempts = 0;
144
- this._connecting = false;
145
-
146
- this._ping();
147
- this._pingInterval = window.setInterval(this._ping.bind(this), PING_INTERVAL);
148
- this._trigger("open");
149
- }
150
-
151
- _ping () {
152
- logger.debug(this._id + "sending PING");
153
- try {
154
- this._socket.send(JSON.stringify({type: "PING"}));
155
- this._sentPing = true;
156
- if (this._pongTimeout) {
157
- clearTimeout(this._pongTimeout);
158
- }
159
- this._pongTimeout = setTimeout(this._pongTimedOut.bind(this), PONG_TIMEOUT);
160
- } catch (e) {
161
- this.close();
162
- }
163
- }
164
-
165
- _pongTimedOut () {
166
- if (this._sentPing && !this._receivedPong) {
167
- logger.debug(this._id + "Pong timed out!");
168
- // Close the socket; this will initiate the reconnection flow automatically
169
- this.close();
170
- }
171
- }
172
-
173
- _clearTimeouts () {
174
- this._sentPing = this._receivedPong = false;
175
- clearTimeout(this._pongTimeout);
176
- clearInterval(this._pingInterval);
177
- clearTimeout(this._nextConnectionAttempt);
178
- }
179
-
180
- _beforeUnload () {
181
- this._windowUnloading = true;
182
- }
183
-
184
- }
185
-
186
- export default PubsubSocket;
package/src/PubsubTest.js DELETED
@@ -1,189 +0,0 @@
1
- /* globals $ */
2
-
3
- import util from "./util";
4
- import logging from "./log";
5
-
6
- const pubsterAddrProduction = "https://pubster.twitch.tv/publish";
7
- const pubsterAddrDarklaunch = "https://pubster-darklaunch.twitch.tv/publish";
8
-
9
- const uniqueKey = "pubsubtest.unique.";
10
- const sharedKey = "pubsubtest.shared." + util.randomInt(10); // 10 topics
11
- const pctPublishShared = 0.0001;
12
-
13
- const publishIntervalTime = 60 * 1000; // 60 seconds
14
- const ajaxTimeout = 30 * 1000; // 30 seconds
15
-
16
- const sampleRateSuccess = 0.1;
17
- const sampleRateFailure = 1.0;
18
-
19
- var logger = logging._getLogger("PubsubTest");
20
-
21
- class PubsubTest {
22
- constructor (opts) {
23
- if (!window.$) {
24
- logger.debug("PubsubTest could not be enabled. JQuery is undefined.");
25
- return;
26
- }
27
-
28
- logger.debug("PubsubTest enabled");
29
- this._env = opts.env;
30
- this._driver = opts.driver;
31
-
32
- switch (this._env) {
33
- case "production":
34
- this._addr = pubsterAddrProduction;
35
- break;
36
- case "darklaunch":
37
- this._addr = pubsterAddrDarklaunch;
38
- break;
39
- default:
40
- this._env = "production";
41
- this._addr = pubsterAddrProduction;
42
- }
43
-
44
- this._statKeys = {
45
- uniqueSuccess: "test.unique.success",
46
- uniqueFailure: "test.unique.failure",
47
- sharedSuccess: "test.shared.success",
48
- sharedFailure: "test.shared.failure"
49
- };
50
-
51
- this._uniqueKey = uniqueKey + util.generateString(20);
52
- this._sharedKey = sharedKey;
53
-
54
- this._listeningUnique = this._listeningShared = false;
55
- this.sendListens();
56
- }
57
-
58
- sendListens () {
59
- this._driver.Listen({
60
- topic: this._uniqueKey,
61
- auth: "",
62
- success: this._gotUniqueOk.bind(this),
63
- failure: this._gotUniqueFail.bind(this),
64
- message: this._gotUniqueMessage.bind(this)
65
- });
66
-
67
- this._driver.Listen({
68
- topic: this._sharedKey,
69
- auth: "",
70
- success: this._gotSharedOk.bind(this),
71
- failure: this._gotSharedFail.bind(this),
72
- message: this._gotSharedMessage.bind(this)
73
- });
74
- }
75
-
76
- _gotUniqueOk () {
77
- this._listeningUnique = true;
78
- if (this._listeningShared) {
79
- this.startTesting();
80
- }
81
- }
82
-
83
- _gotUniqueFail (err) {
84
- // Ignore
85
- }
86
-
87
- _gotSharedOk () {
88
- this._listeningShared = true;
89
- if (this._listeningUnique) {
90
- this.startTesting();
91
- }
92
- }
93
-
94
- _gotSharedFail (err) {
95
- // Ignore
96
- }
97
-
98
- startTesting() {
99
- logger.debug("startTesting");
100
- this._driver.on("connected", this.resumeTesting, this);
101
- this._driver.on("disconnected", this.stopTesting, this);
102
- this.checkAndSend();
103
- this._publishInterval = window.setInterval(this.checkAndSend.bind(this), publishIntervalTime);
104
- }
105
-
106
- resumeTesting() {
107
- logger.debug("resumeTesting");
108
- this.checkAndSend();
109
- this._publishInterval = window.setInterval(this.checkAndSend.bind(this), publishIntervalTime);
110
- }
111
-
112
- stopTesting() {
113
- logger.debug("stopTesting");
114
- clearInterval(this._publishInterval);
115
- this._receivedUniqueMessage = this._sentUniqueMessage = false;
116
- this._receivedSharedMessage = this._sentSharedMessage = false;
117
- }
118
-
119
- checkAndSend() {
120
- logger.debug("checkAndSend: unique: sent = " + this._sentUniqueMessage + ", received = " + this._receivedUniqueMessage);
121
- if (!this._receivedUniqueMessage && this._sentUniqueMessage) {
122
- // log unique error
123
- logger.debug("unique failure");
124
- }
125
- if (!this._receivedSharedMessage && this._sentSharedMessage) {
126
- // log shared error
127
- logger.debug("shared failure");
128
- }
129
-
130
- this._receivedUniqueMessage = this._sentUniqueMessage = false;
131
- this._receivedSharedMessage = this._sentSharedMessage = false;
132
-
133
- this._expectedMessage = util.generateString(30);
134
-
135
- // publish unique message to testPub
136
- $.ajax({
137
- type: "POST",
138
- url: this._addr,
139
- contentType: "application/json",
140
- timeout: ajaxTimeout,
141
- data: JSON.stringify({
142
- topics: [this._uniqueKey],
143
- data: this._expectedMessage
144
- }),
145
- success: (function () {
146
- logger.debug("unique message sent");
147
- this._sentUniqueMessage = true;
148
- }).bind(this)
149
- });
150
- this._sentUniqueMessageTime = util.time.now();
151
-
152
- // potentially publish shared message
153
- if (Math.random() < pctPublishShared) {
154
- $.ajax({
155
- type: "POST",
156
- url: this._addr,
157
- contentType: "application/json",
158
- timeout: ajaxTimeout,
159
- data: JSON.stringify({
160
- topics: [this._sharedKey],
161
- data: this._expectedMessage
162
- }),
163
- success: (function () {
164
- logger.debug("shared message sent");
165
- this._sentSharedMessage = true;
166
- }).bind(this)
167
- });
168
- this._sentSharedMessageTime = util.time.now();
169
- }
170
- }
171
-
172
- _gotUniqueMessage (msg) {
173
- logger.debug("received unique message: " + msg);
174
- if (msg === this._expectedMessage) {
175
- var rtt = util.time.now() - this._sentUniqueMessageTime;
176
- this._receivedUniqueMessage = true;
177
- }
178
- }
179
-
180
- _gotSharedMessage (msg) {
181
- if (msg === this._expectedMessage) {
182
- var rtt = util.time.now() - this._sentSharedMessageTime;
183
- this._receivedSharedMessage = true;
184
- }
185
- }
186
-
187
- }
188
-
189
- export default PubsubTest;