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