raspberryGPIOhtmlserver/node_modules/engine.io-client/lib/transports/websocket.js
node_modules/engine.io-client/lib/transports/websocket.jsRaw
1/**
2 * Module dependencies.
3 */
4
5var Transport = require('../transport');
6var parser = require('engine.io-parser');
7var parseqs = require('parseqs');
8var inherit = require('component-inherit');
9var debug = require('debug')('engine.io-client:websocket');
10
11/**
12 * `ws` exposes a WebSocket-compatible interface in
13 * Node, or the `WebSocket` or `MozWebSocket` globals
14 * in the browser.
15 */
16
17var WebSocket = require('ws');
18
19/**
20 * Module exports.
21 */
22
23module.exports = WS;
24
25/**
26 * WebSocket transport constructor.
27 *
28 * @api {Object} connection options
29 * @api public
30 */
31
32function WS(opts){
33 var forceBase64 = (opts && opts.forceBase64);
34 if (forceBase64) {
35 this.supportsBinary = false;
36 }
37 Transport.call(this, opts);
38}
39
40/**
41 * Inherits from Transport.
42 */
43
44inherit(WS, Transport);
45
46/**
47 * Transport name.
48 *
49 * @api public
50 */
51
52WS.prototype.name = 'websocket';
53
54/*
55 * WebSockets support binary
56 */
57
58WS.prototype.supportsBinary = true;
59
60/**
61 * Opens socket.
62 *
63 * @api private
64 */
65
66WS.prototype.doOpen = function(){
67 if (!this.check()) {
68 // let probe timeout
69 return;
70 }
71
72 var self = this;
73 var uri = this.uri();
74 var protocols = void(0);
75 var opts = { agent: this.agent };
76
77 this.ws = new WebSocket(uri, protocols, opts);
78
79 if (this.ws.binaryType === undefined) {
80 this.supportsBinary = false;
81 }
82
83 this.ws.binaryType = 'arraybuffer';
84 this.addEventListeners();
85};
86
87/**
88 * Adds event listeners to the socket
89 *
90 * @api private
91 */
92
93WS.prototype.addEventListeners = function(){
94 var self = this;
95
96 this.ws.onopen = function(){
97 self.onOpen();
98 };
99 this.ws.onclose = function(){
100 self.onClose();
101 };
102 this.ws.onmessage = function(ev){
103 self.onData(ev.data);
104 };
105 this.ws.onerror = function(e){
106 self.onError('websocket error', e);
107 };
108};
109
110/**
111 * Override `onData` to use a timer on iOS.
112 * See: https://gist.github.com/mloughran/2052006
113 *
114 * @api private
115 */
116
117if ('undefined' != typeof navigator
118 && /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
119 WS.prototype.onData = function(data){
120 var self = this;
121 setTimeout(function(){
122 Transport.prototype.onData.call(self, data);
123 }, 0);
124 };
125}
126
127/**
128 * Writes data to socket.
129 *
130 * @param {Array} array of packets.
131 * @api private
132 */
133
134WS.prototype.write = function(packets){
135 var self = this;
136 this.writable = false;
137 // encodePacket efficient as it uses WS framing
138 // no need for encodePayload
139 for (var i = 0, l = packets.length; i < l; i++) {
140 parser.encodePacket(packets[i], this.supportsBinary, function(data) {
141 //Sometimes the websocket has already been closed but the browser didn't
142 //have a chance of informing us about it yet, in that case send will
143 //throw an error
144 try {
145 self.ws.send(data);
146 } catch (e){
147 debug('websocket closed before onclose event');
148 }
149 });
150 }
151
152 function ondrain() {
153 self.writable = true;
154 self.emit('drain');
155 }
156 // fake drain
157 // defer to next tick to allow Socket to clear writeBuffer
158 setTimeout(ondrain, 0);
159};
160
161/**
162 * Called upon close
163 *
164 * @api private
165 */
166
167WS.prototype.onClose = function(){
168 Transport.prototype.onClose.call(this);
169};
170
171/**
172 * Closes socket.
173 *
174 * @api private
175 */
176
177WS.prototype.doClose = function(){
178 if (typeof this.ws !== 'undefined') {
179 this.ws.close();
180 }
181};
182
183/**
184 * Generates uri for connection.
185 *
186 * @api private
187 */
188
189WS.prototype.uri = function(){
190 var query = this.query || {};
191 var schema = this.secure ? 'wss' : 'ws';
192 var port = '';
193
194 // avoid port if default for schema
195 if (this.port && (('wss' == schema && this.port != 443)
196 || ('ws' == schema && this.port != 80))) {
197 port = ':' + this.port;
198 }
199
200 // append timestamp to URI
201 if (this.timestampRequests) {
202 query[this.timestampParam] = +new Date;
203 }
204
205 // communicate binary support capabilities
206 if (!this.supportsBinary) {
207 query.b64 = 1;
208 }
209
210 query = parseqs.encode(query);
211
212 // prepend ? to query
213 if (query.length) {
214 query = '?' + query;
215 }
216
217 return schema + '://' + this.hostname + port + this.path + query;
218};
219
220/**
221 * Feature detection for WebSocket.
222 *
223 * @return {Boolean} whether this transport is available.
224 * @api public
225 */
226
227WS.prototype.check = function(){
228 return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
229};