UNPKG

5.11 kBJavaScriptView Raw
1
2/**
3 * socket.io
4 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
5 * MIT Licensed
6 */
7
8(function (exports, io) {
9
10 /**
11 * Parser namespace.
12 *
13 * @namespace
14 */
15
16 var parser = exports.parser = {};
17
18 /**
19 * Packet types.
20 */
21
22 var packets = parser.packets = [
23 'disconnect'
24 , 'connect'
25 , 'heartbeat'
26 , 'message'
27 , 'json'
28 , 'event'
29 , 'ack'
30 , 'error'
31 , 'noop'
32 ];
33
34 /**
35 * Errors reasons.
36 */
37
38 var reasons = parser.reasons = [
39 'transport not supported'
40 , 'client not handshaken'
41 , 'unauthorized'
42 ];
43
44 /**
45 * Errors advice.
46 */
47
48 var advice = parser.advice = [
49 'reconnect'
50 ];
51
52 /**
53 * Shortcuts.
54 */
55
56 var JSON = io.JSON
57 , indexOf = io.util.indexOf;
58
59 /**
60 * Encodes a packet.
61 *
62 * @api private
63 */
64
65 parser.encodePacket = function (packet) {
66 var type = indexOf(packets, packet.type)
67 , id = packet.id || ''
68 , endpoint = packet.endpoint || ''
69 , ack = packet.ack
70 , data = null;
71
72 switch (packet.type) {
73 case 'error':
74 var reason = packet.reason ? indexOf(reasons, packet.reason) : ''
75 , adv = packet.advice ? indexOf(advice, packet.advice) : ''
76
77 if (reason !== '' || adv !== '')
78 data = reason + (adv !== '' ? ('+' + adv) : '')
79
80 break;
81
82 case 'message':
83 if (packet.data !== '')
84 data = packet.data;
85 break;
86
87 case 'event':
88 var ev = { name: packet.name };
89
90 if (packet.args && packet.args.length) {
91 ev.args = packet.args;
92 }
93
94 data = JSON.stringify(ev);
95 break;
96
97 case 'json':
98 data = JSON.stringify(packet.data);
99 break;
100
101 case 'connect':
102 if (packet.qs)
103 data = packet.qs;
104 break;
105
106 case 'ack':
107 data = packet.ackId
108 + (packet.args && packet.args.length
109 ? '+' + JSON.stringify(packet.args) : '');
110 break;
111 }
112
113 // construct packet with required fragments
114 var encoded = [
115 type
116 , id + (ack == 'data' ? '+' : '')
117 , endpoint
118 ];
119
120 // data fragment is optional
121 if (data !== null && data !== undefined)
122 encoded.push(data);
123
124 return encoded.join(':');
125 };
126
127 /**
128 * Encodes multiple messages (payload).
129 *
130 * @param {Array} messages
131 * @api private
132 */
133
134 parser.encodePayload = function (packets) {
135 var decoded = '';
136
137 if (packets.length == 1)
138 return packets[0];
139
140 for (var i = 0, l = packets.length; i < l; i++) {
141 var packet = packets[i];
142 decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
143 }
144
145 return decoded;
146 };
147
148 /**
149 * Decodes a packet
150 *
151 * @api private
152 */
153
154 var regexp = /^([^:]+):([0-9]+)?(\+)?:([^:]+)?:?(.*)?$/;
155
156 parser.decodePacket = function (data) {
157 var pieces = data.match(regexp);
158
159 if (!pieces) return {};
160
161 var id = pieces[2] || ''
162 , data = pieces[5] || ''
163 , packet = {
164 type: packets[pieces[1]]
165 , endpoint: pieces[4] || ''
166 };
167
168 // whether we need to acknowledge the packet
169 if (id) {
170 packet.id = id;
171 if (pieces[3])
172 packet.ack = 'data';
173 else
174 packet.ack = true;
175 }
176
177 // handle different packet types
178 switch (packet.type) {
179 case 'error':
180 var pieces = data.split('+');
181 packet.reason = reasons[pieces[0]] || '';
182 packet.advice = advice[pieces[1]] || '';
183 break;
184
185 case 'message':
186 packet.data = data || '';
187 break;
188
189 case 'event':
190 try {
191 var opts = JSON.parse(data);
192 packet.name = opts.name;
193 packet.args = opts.args;
194 } catch (e) { }
195
196 packet.args = packet.args || [];
197 break;
198
199 case 'json':
200 try {
201 packet.data = JSON.parse(data);
202 } catch (e) { }
203 break;
204
205 case 'connect':
206 packet.qs = data || '';
207 break;
208
209 case 'ack':
210 var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
211 if (pieces) {
212 packet.ackId = pieces[1];
213 packet.args = [];
214
215 if (pieces[3]) {
216 try {
217 packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];
218 } catch (e) { }
219 }
220 }
221 break;
222
223 case 'disconnect':
224 case 'heartbeat':
225 break;
226 };
227
228 return packet;
229 };
230
231 /**
232 * Decodes data payload. Detects multiple messages
233 *
234 * @return {Array} messages
235 * @api public
236 */
237
238 parser.decodePayload = function (data) {
239 if (data[0] == '\ufffd') {
240 var ret = [];
241
242 for (var i = 1, length = ''; i < data.length; i++) {
243 if (data[i] == '\ufffd') {
244 ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));
245 i += Number(length) + 1;
246 length = '';
247 } else {
248 length += data[i];
249 }
250 }
251
252 return ret;
253 } else {
254 return [parser.decodePacket(data)];
255 }
256 };
257
258})(
259 'undefined' != typeof io ? io : module.exports
260 , 'undefined' != typeof io ? io : module.parent.exports
261);