subduino 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,242 +0,0 @@
1
- /*
2
- * Arduino-serial
3
- * --------------
4
- *
5
- * A simple command-line example program showing how a computer can
6
- * communicate with an Arduino board. Works on any POSIX system (Mac/Unix/PC)
7
- *
8
- *
9
- * Compile with something like:
10
- * gcc -o arduino-serial arduino-serial.c
11
- *
12
- * Created 5 December 2006
13
- * Copyleft (c) 2006, Tod E. Kurt, tod@todbot.com
14
- * http://todbot.com/blog/
15
- *
16
- *
17
- * Updated 8 December 2006:
18
- * Justin McBride discoevered B14400 & B28800 aren't in Linux's termios.h.
19
- * I've included his patch, but commented out for now. One really needs a
20
- * real make system when doing cross-platform C and I wanted to avoid that
21
- * for this little program. Those baudrates aren't used much anyway. :)
22
- *
23
- * Updated 26 December 2007:
24
- * Added ability to specify a delay (so you can wait for Arduino Diecimila)
25
- * Added ability to send a binary byte number
26
- *
27
- * Update 31 August 2008:
28
- * Added patch to clean up odd baudrates from Andy at hexapodia.org
29
- *
30
- */
31
-
32
- #include "cubduino.h"
33
-
34
-
35
-
36
- // Ruby 1.x compatibility
37
- #ifndef RSTRING_PTR
38
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
39
- #endif
40
- #ifndef RSTRING_LEN
41
- #define RSTRING_LEN(s) (RSTRING(s)->len)
42
- #endif
43
-
44
- VALUE Cubduino;
45
-
46
- VALUE sBaud, sDataBits, sStopBits, sParity; /* strings */
47
- VALUE sRts, sDtr, sCts, sDsr, sDcd, sRi;
48
-
49
-
50
- void Init_cubduino();
51
- //VALUE method_cwrite(VALUE self);
52
-
53
-
54
-
55
- void usage(void);
56
- int serialport_init(const char* serialport, int baud);
57
- int serialport_writebyte(int fd, uint8_t b);
58
- int serialport_write(int fd, const char* str);
59
- int serialport_read_until(int fd, char* buf, char until);
60
-
61
-
62
- int main(int argc, char *argv[])
63
- {
64
- int rc,n;
65
- int fd = 0;
66
- int baudrate = B9600; // default
67
- char serialport[256];
68
- char buf[256];
69
-
70
- /* parse options */
71
- int option_index = 0, opt;
72
- static struct option loptions[] = {
73
- {"help", no_argument, 0, 'h'},
74
- {"port", required_argument, 0, 'p'},
75
- {"baud", required_argument, 0, 'b'},
76
- {"send", required_argument, 0, 's'},
77
- {"receive", no_argument, 0, 'r'},
78
- {"num", required_argument, 0, 'n'},
79
- {"delay", required_argument, 0, 'd'}
80
- };
81
-
82
- while(1) {
83
- opt = getopt_long (argc, argv, "hp:b:s:rn:d:",
84
- loptions, &option_index);
85
- if (opt==-1) break;
86
- switch (opt) {
87
- case '0': break;
88
- case 'd':
89
- n = strtol(optarg,NULL,10);
90
- usleep(n * 1000 ); // sleep milliseconds
91
- break;
92
- case 'h':
93
- usage();
94
- break;
95
- case 'b':
96
- baudrate = strtol(optarg,NULL,10);
97
- break;
98
- case 'p':
99
- strcpy(serialport,optarg);
100
- fd = serialport_init(optarg, baudrate);
101
- if(fd==-1) return -1;
102
- break;
103
- case 'n':
104
- n = strtol(optarg, NULL, 10); // convert string to number
105
- rc = serialport_writebyte(fd, (uint8_t)n);
106
- if(rc==-1) return -1;
107
- break;
108
- case 's':
109
- strcpy(buf,optarg);
110
- rc = serialport_write(fd, buf);
111
- if(rc==-1) return -1;
112
- break;
113
- case 'r':
114
- serialport_read_until(fd, buf, '\n');
115
- printf("read: %s\n",buf);
116
- break;
117
- }
118
- }
119
-
120
- exit(EXIT_SUCCESS);
121
- } // end main
122
-
123
- int serialport_writebyte( int fd, uint8_t b)
124
- {
125
- int n = write(fd,&b,1);
126
- if( n!=1)
127
- return -1;
128
- return 0;
129
- }
130
-
131
- int serialport_write(int fd, const char* str)
132
- {
133
- int len = strlen(str);
134
- int n = write(fd, str, len);
135
- if( n!=len )
136
- return -1;
137
- return 0;
138
- }
139
-
140
- int serialport_read_until(int fd, char* buf, char until)
141
- {
142
- char b[1];
143
- int i=0;
144
- do {
145
- int n = read(fd, b, 1); // read a char at a time
146
- if( n==-1) return -1; // couldn't read
147
- if( n==0 ) {
148
- usleep( 10 * 1000 ); // wait 10 msec try again
149
- continue;
150
- }
151
- buf[i] = b[0]; i++;
152
- } while( b[0] != until );
153
-
154
- buf[i] = 0; // null terminate the string
155
- return 0;
156
- }
157
-
158
- // takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
159
- // and a baud rate (bps) and connects to that port at that speed and 8N1.
160
- // opens the port in fully raw mode so you can send binary data.
161
- // returns valid fd, or -1 on error
162
- int serialport_init(const char* serialport, int baud)
163
- {
164
- struct termios toptions;
165
- int fd;
166
-
167
- //fprintf(stderr,"init_serialport: opening port %s @ %d bps\n",
168
- // serialport,baud);
169
-
170
- fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
171
- if (fd == -1) {
172
- perror("init_serialport: Unable to open port ");
173
- return -1;
174
- }
175
-
176
- if (tcgetattr(fd, &toptions) < 0) {
177
- perror("init_serialport: Couldn't get term attributes");
178
- return -1;
179
- }
180
- speed_t brate = baud; // let you override switch below if needed
181
- switch(baud) {
182
- case 4800: brate=B4800; break;
183
- case 9600: brate=B9600; break;
184
- #ifdef B14400
185
- case 14400: brate=B14400; break;
186
- #endif
187
- case 19200: brate=B19200; break;
188
- #ifdef B28800
189
- case 28800: brate=B28800; break;
190
- #endif
191
- case 38400: brate=B38400; break;
192
- case 57600: brate=B57600; break;
193
- case 115200: brate=B115200; break;
194
- }
195
- cfsetispeed(&toptions, brate);
196
- cfsetospeed(&toptions, brate);
197
-
198
- // 8N1
199
- toptions.c_cflag &= ~PARENB;
200
- toptions.c_cflag &= ~CSTOPB;
201
- toptions.c_cflag &= ~CSIZE;
202
- toptions.c_cflag |= CS8;
203
- // no flow control
204
- toptions.c_cflag &= ~CRTSCTS;
205
-
206
- toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
207
- toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
208
-
209
- toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
210
- toptions.c_oflag &= ~OPOST; // make raw
211
-
212
- // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
213
- toptions.c_cc[VMIN] = 0;
214
- toptions.c_cc[VTIME] = 20;
215
-
216
- if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
217
- perror("init_serialport: Couldn't set term attributes");
218
- return -1;
219
- }
220
-
221
- return fd;
222
- }
223
-
224
- static VALUE method_write(VALUE class, VALUE arg) {
225
- printf("%s", RSTRING_PTR(arg));
226
- return Qnil;
227
- }
228
-
229
- static VALUE method_read() {
230
- int fd = 0;
231
- int baudrate = 9600;
232
- fd = serialport_init(optarg, baudrate);
233
- char buf[256];
234
- serialport_read_until(fd, buf, '\n');
235
- return rb_str_new2(buf);
236
- }
237
-
238
- void Init_cubduino() {
239
- Cubduino = rb_define_module("Cubduino");
240
- rb_define_singleton_method(Cubduino, "read", method_write, 0);
241
- rb_define_singleton_method(Cubduino, "write", method_write, 1);
242
- }
@@ -1,12 +0,0 @@
1
- #include <ruby.h>
2
-
3
- #include <stdio.h> /* Standard input/output definitions */
4
- #include <stdlib.h>
5
- #include <stdint.h> /* Standard types */
6
- #include <string.h> /* String function definitions */
7
- #include <unistd.h> /* UNIX standard function definitions */
8
- #include <fcntl.h> /* File control definitions */
9
- #include <errno.h> /* Error number definitions */
10
- #include <termios.h> /* POSIX terminal control definitions */
11
- #include <sys/ioctl.h>
12
- #include <getopt.h>
Binary file
Binary file
@@ -1,30 +0,0 @@
1
- module Subduino
2
-
3
-
4
-
5
- class Arduino
6
-
7
- def self.find_usb
8
- Dir['/dev/ttyUSB*'].first
9
- end
10
-
11
-
12
- def initialize
13
- end
14
-
15
- def send_to_arduino(string)
16
- string.to_s.chomp.split("").each do |char|
17
- @sp.putc char
18
- end
19
- end
20
-
21
- end
22
-
23
- # read << case comm
24
- # when "Temp" then "%0.2f C" % (value.to_i * 0.04)
25
- # when "Light" then "#{value.to_i * 2} Lux"
26
- # else
27
- # "#{comm}: #{value}"
28
- # end
29
-
30
- end
@@ -1,68 +0,0 @@
1
- // Arduino Node.js
2
-
3
-
4
- var sys = require('sys'),
5
- fs = require('fs'),
6
- faye = require('./vendor/faye');
7
-
8
- var dpath = "/dev/ttyUSB1";
9
-
10
- var client = new faye.Client('http://localhost:8000/faye');
11
-
12
- var subscription = client.subscribe('/foo', function(message) {
13
- sys.puts("SUB!!!"); // handle message
14
- });
15
-
16
- var log = function(txt) {
17
- sys.puts(txt)
18
- }
19
-
20
- var find_arduino = function(err, stats) {
21
- if(err)
22
- return log("Arduino not found...");
23
-
24
- log("DUIN!");
25
- log(sys.inspect(stats));
26
- }
27
-
28
- fs.stat("/dev/ttyUSB1", find_arduino);
29
-
30
-
31
- var spawn = require('child_process').spawn,
32
- stty = spawn('stty -F /dev/ttyUSB1 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts'); //, ['-lh', '/usr']);
33
-
34
- stty.stdout.on('data', function (data) {
35
- sys.print('stdout: ' + data);
36
- });
37
-
38
- stty.stderr.on('data', function (data) {
39
- log("Could not stty " + dpath);
40
- log('stderr: ' + data);
41
- });
42
-
43
- stty.on('exit', function (code) {
44
- if (code == 0)
45
- console.log('Done modding stty ' + dpath);
46
- });
47
-
48
-
49
- // stty -F /dev/ttyUSB1 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
50
- var rr = fs.createReadStream(dpath, {
51
- 'flags': 'r',
52
- 'encoding': 'ascii', // binary, utf8
53
- // 'mode': 0666,
54
- // 'bufferSize': 4 * 1024
55
- });
56
-
57
-
58
- rr.addListener('data', function (chunk) {
59
- log('data: ' + chunk);
60
- log(sys.inspect(chunk));
61
- });
62
-
63
- rr.on('end', function () {
64
- log('end, closed fs');
65
- });
66
-
67
-
68
-
@@ -1,45 +0,0 @@
1
- // Arduino <> Subduino/Node <> WWW
2
-
3
- var sys = require('sys'),
4
- http = require('http'),
5
- faye = require('./vendor/faye');
6
-
7
- var bayeux = new faye.NodeAdapter({
8
- mount: '/faye',
9
- timeout: 45
10
- });
11
-
12
- sys.puts("Starting server...");
13
-
14
- // process.on('SIGHUP', function () {
15
- // sys.puts('Got SIGHUP signal.');
16
- // });
17
- // process.on('SIGKILL', function () {
18
- // sys.puts('Got SIGHUP signal.');
19
- // });
20
-
21
- // Handle non-Bayeux requests
22
- var server = http.createServer(function(request, response) {
23
- response.writeHead(200, {'Content-Type': 'text/plain'});
24
- response.write('Nothing to see here...');
25
- response.end();
26
- });
27
-
28
- server.on('stream', function(stream) {
29
- sys.puts("Stream!");
30
- sys.puts(stream);
31
- })
32
-
33
- var listen_callback = function() {
34
- sys.log("Server started...");
35
- }
36
-
37
- bayeux.attach(server);
38
- server.listen(8000, listen_callback);
39
-
40
-
41
- // var client = new faye.Client('http://localhost:8000/faye');
42
- // bayeux.getClient().publish('/email/new', {
43
- // text: 'New email has arrived!',
44
- // inboxSize: 34
45
- // });
@@ -1,1925 +0,0 @@
1
- if (!this.Faye) Faye = {};
2
-
3
- Faye.extend = function(dest, source, overwrite) {
4
- if (!source) return dest;
5
- for (var key in source) {
6
- if (!source.hasOwnProperty(key)) continue;
7
- if (dest.hasOwnProperty(key) && overwrite === false) continue;
8
- if (dest[key] !== source[key])
9
- dest[key] = source[key];
10
- }
11
- return dest;
12
- };
13
-
14
- Faye.extend(Faye, {
15
- VERSION: '0.5.2',
16
-
17
- BAYEUX_VERSION: '1.0',
18
- ID_LENGTH: 128,
19
- JSONP_CALLBACK: 'jsonpcallback',
20
- CONNECTION_TYPES: ['long-polling', 'callback-polling', 'websocket'],
21
-
22
- MANDATORY_CONNECTION_TYPES: ['long-polling', 'callback-polling', 'in-process'],
23
-
24
- ENV: (function() { return this })(),
25
-
26
- random: function(bitlength) {
27
- bitlength = bitlength || this.ID_LENGTH;
28
- if (bitlength > 32) {
29
- var parts = Math.ceil(bitlength / 32),
30
- string = '';
31
- while (parts--) string += this.random(32);
32
- return string;
33
- }
34
- var field = Math.pow(2, bitlength);
35
- return Math.floor(Math.random() * field).toString(36);
36
- },
37
-
38
- commonElement: function(lista, listb) {
39
- for (var i = 0, n = lista.length; i < n; i++) {
40
- if (this.indexOf(listb, lista[i]) !== -1)
41
- return lista[i];
42
- }
43
- return null;
44
- },
45
-
46
- indexOf: function(list, needle) {
47
- for (var i = 0, n = list.length; i < n; i++) {
48
- if (list[i] === needle) return i;
49
- }
50
- return -1;
51
- },
52
-
53
- each: function(object, callback, scope) {
54
- if (object instanceof Array) {
55
- for (var i = 0, n = object.length; i < n; i++) {
56
- if (object[i] !== undefined)
57
- callback.call(scope || null, object[i], i);
58
- }
59
- } else {
60
- for (var key in object) {
61
- if (object.hasOwnProperty(key))
62
- callback.call(scope || null, key, object[key]);
63
- }
64
- }
65
- },
66
-
67
- map: function(object, callback, scope) {
68
- var result = [];
69
- this.each(object, function() {
70
- result.push(callback.apply(scope || null, arguments));
71
- });
72
- return result;
73
- },
74
-
75
- filter: function(array, callback, scope) {
76
- var result = [];
77
- this.each(array, function() {
78
- if (callback.apply(scope, arguments))
79
- result.push(arguments[0]);
80
- });
81
- return result;
82
- },
83
-
84
- size: function(object) {
85
- var size = 0;
86
- this.each(object, function() { size += 1 });
87
- return size;
88
- },
89
-
90
- enumEqual: function(actual, expected) {
91
- if (expected instanceof Array) {
92
- if (!(actual instanceof Array)) return false;
93
- var i = actual.length;
94
- if (i !== expected.length) return false;
95
- while (i--) {
96
- if (actual[i] !== expected[i]) return false;
97
- }
98
- return true;
99
- } else {
100
- if (!(actual instanceof Object)) return false;
101
- if (this.size(expected) !== this.size(actual)) return false;
102
- var result = true;
103
- this.each(actual, function(key, value) {
104
- result = result && (expected[key] === value);
105
- });
106
- return result;
107
- }
108
- },
109
-
110
- // http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/
111
- toJSON: function(object) {
112
- if (this.stringify)
113
- return this.stringify(object, function(key, value) {
114
- return (this[key] instanceof Array)
115
- ? this[key]
116
- : value;
117
- });
118
-
119
- return JSON.stringify(object);
120
- },
121
-
122
- timestamp: function() {
123
- var date = new Date(),
124
- year = date.getFullYear(),
125
- month = date.getMonth() + 1,
126
- day = date.getDate(),
127
- hour = date.getHours(),
128
- minute = date.getMinutes(),
129
- second = date.getSeconds();
130
-
131
- var pad = function(n) {
132
- return n < 10 ? '0' + n : String(n);
133
- };
134
-
135
- return pad(year) + '-' + pad(month) + '-' + pad(day) + ' ' +
136
- pad(hour) + ':' + pad(minute) + ':' + pad(second);
137
- }
138
- });
139
-
140
-
141
- Faye.Class = function(parent, methods) {
142
- if (typeof parent !== 'function') {
143
- methods = parent;
144
- parent = Object;
145
- }
146
-
147
- var klass = function() {
148
- if (!this.initialize) return this;
149
- return this.initialize.apply(this, arguments) || this;
150
- };
151
-
152
- var bridge = function() {};
153
- bridge.prototype = parent.prototype;
154
-
155
- klass.prototype = new bridge();
156
- Faye.extend(klass.prototype, methods);
157
-
158
- return klass;
159
- };
160
-
161
-
162
- Faye.Namespace = Faye.Class({
163
- initialize: function() {
164
- this._used = {};
165
- },
166
-
167
- generate: function() {
168
- var name = Faye.random();
169
- while (this._used.hasOwnProperty(name))
170
- name = Faye.random();
171
- return this._used[name] = name;
172
- }
173
- });
174
-
175
-
176
- Faye.Deferrable = {
177
- callback: function(callback, scope) {
178
- if (!callback) return;
179
-
180
- if (this._deferredStatus === 'succeeded')
181
- return callback.apply(scope, this._deferredArgs);
182
-
183
- this._callbacks = this._callbacks || [];
184
- this._callbacks.push([callback, scope]);
185
- },
186
-
187
- setDeferredStatus: function() {
188
- var args = Array.prototype.slice.call(arguments),
189
- status = args.shift();
190
-
191
- this._deferredStatus = status;
192
- this._deferredArgs = args;
193
-
194
- if (status !== 'succeeded') return;
195
- if (!this._callbacks) return;
196
-
197
- Faye.each(this._callbacks, function(callback) {
198
- callback[0].apply(callback[1], this._deferredArgs);
199
- }, this);
200
-
201
- this._callbacks = [];
202
- }
203
- };
204
-
205
-
206
- Faye.Publisher = {
207
- countSubscribers: function(eventType) {
208
- if (!this._subscribers || !this._subscribers[eventType]) return 0;
209
- return this._subscribers[eventType].length;
210
- },
211
-
212
- addSubscriber: function(eventType, listener, context) {
213
- this._subscribers = this._subscribers || {};
214
- var list = this._subscribers[eventType] = this._subscribers[eventType] || [];
215
- list.push([listener, context]);
216
- },
217
-
218
- removeSubscriber: function(eventType, listener, context) {
219
- if (!this._subscribers || !this._subscribers[eventType]) return;
220
-
221
- var list = this._subscribers[eventType],
222
- i = list.length;
223
-
224
- while (i--) {
225
- if (listener && list[i][0] !== listener) continue;
226
- if (context && list[i][1] !== context) continue;
227
- list.splice(i,1);
228
- }
229
- },
230
-
231
- publishEvent: function() {
232
- var args = Array.prototype.slice.call(arguments),
233
- eventType = args.shift();
234
-
235
- if (!this._subscribers || !this._subscribers[eventType]) return;
236
-
237
- Faye.each(this._subscribers[eventType], function(listener) {
238
- listener[0].apply(listener[1], args);
239
- });
240
- }
241
- };
242
-
243
-
244
- Faye.Timeouts = {
245
- addTimeout: function(name, delay, callback, scope) {
246
- this._timeouts = this._timeouts || {};
247
- if (this._timeouts.hasOwnProperty(name)) return;
248
- var self = this;
249
- this._timeouts[name] = setTimeout(function() {
250
- delete self._timeouts[name];
251
- callback.call(scope);
252
- }, 1000 * delay);
253
- },
254
-
255
- removeTimeout: function(name) {
256
- this._timeouts = this._timeouts || {};
257
- var timeout = this._timeouts[name];
258
- if (!timeout) return;
259
- clearTimeout(timeout);
260
- delete this._timeouts[name];
261
- }
262
- };
263
-
264
-
265
- Faye.Logging = {
266
- LOG_LEVELS: {
267
- error: 3,
268
- warn: 2,
269
- info: 1,
270
- debug: 0
271
- },
272
-
273
- logLevel: 'error',
274
-
275
- log: function(messageArgs, level) {
276
- if (!Faye.logger) return;
277
-
278
- var levels = Faye.Logging.LOG_LEVELS;
279
- if (levels[Faye.Logging.logLevel] > levels[level]) return;
280
-
281
- var messageArgs = Array.prototype.slice.apply(messageArgs),
282
- banner = ' [' + level.toUpperCase() + '] [Faye',
283
- klass = null,
284
-
285
- message = messageArgs.shift().replace(/\?/g, function() {
286
- try {
287
- return Faye.toJSON(messageArgs.shift());
288
- } catch (e) {
289
- return '[Object]';
290
- }
291
- });
292
-
293
- for (var key in Faye) {
294
- if (klass) continue;
295
- if (typeof Faye[key] !== 'function') continue;
296
- if (this instanceof Faye[key]) klass = key;
297
- }
298
- if (klass) banner += '.' + klass;
299
- banner += '] ';
300
-
301
- Faye.logger(Faye.timestamp() + banner + message);
302
- }
303
- };
304
-
305
- Faye.each(Faye.Logging.LOG_LEVELS, function(level, value) {
306
- Faye.Logging[level] = function() {
307
- this.log(arguments, level);
308
- };
309
- });
310
-
311
-
312
- Faye.Grammar = {
313
-
314
- LOWALPHA: /^[a-z]$/,
315
-
316
- UPALPHA: /^[A-Z]$/,
317
-
318
- ALPHA: /^([a-z]|[A-Z])$/,
319
-
320
- DIGIT: /^[0-9]$/,
321
-
322
- ALPHANUM: /^(([a-z]|[A-Z])|[0-9])$/,
323
-
324
- MARK: /^(\-|\_|\!|\~|\(|\)|\$|\@)$/,
325
-
326
- STRING: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
327
-
328
- TOKEN: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
329
-
330
- INTEGER: /^([0-9])+$/,
331
-
332
- CHANNEL_SEGMENT: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
333
-
334
- CHANNEL_SEGMENTS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
335
-
336
- CHANNEL_NAME: /^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
337
-
338
- WILD_CARD: /^\*{1,2}$/,
339
-
340
- CHANNEL_PATTERN: /^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,
341
-
342
- VERSION_ELEMENT: /^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,
343
-
344
- VERSION: /^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,
345
-
346
- CLIENT_ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
347
-
348
- ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
349
-
350
- ERROR_MESSAGE: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
351
-
352
- ERROR_ARGS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,
353
-
354
- ERROR_CODE: /^[0-9][0-9][0-9]$/,
355
-
356
- ERROR: /^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/
357
-
358
- };
359
-
360
-
361
- Faye.Extensible = {
362
- addExtension: function(extension) {
363
- this._extensions = this._extensions || [];
364
- this._extensions.push(extension);
365
- if (extension.added) extension.added();
366
- },
367
-
368
- removeExtension: function(extension) {
369
- if (!this._extensions) return;
370
- var i = this._extensions.length;
371
- while (i--) {
372
- if (this._extensions[i] !== extension) continue;
373
- this._extensions.splice(i,1);
374
- if (extension.removed) extension.removed();
375
- }
376
- },
377
-
378
- pipeThroughExtensions: function(stage, message, callback, scope) {
379
- if (!this._extensions) return callback.call(scope, message);
380
- var extensions = this._extensions.slice();
381
-
382
- var pipe = function(message) {
383
- if (!message) return callback.call(scope, message);
384
-
385
- var extension = extensions.shift();
386
- if (!extension) return callback.call(scope, message);
387
-
388
- if (extension[stage]) extension[stage](message, pipe);
389
- else pipe(message);
390
- };
391
- pipe(message);
392
- }
393
- };
394
-
395
-
396
- Faye.Channel = Faye.Class({
397
- initialize: function(name) {
398
- this.id = this.name = name;
399
- },
400
-
401
- push: function(message) {
402
- this.publishEvent('message', message);
403
- }
404
- });
405
-
406
- Faye.extend(Faye.Channel.prototype, Faye.Publisher);
407
-
408
- Faye.extend(Faye.Channel, {
409
- HANDSHAKE: '/meta/handshake',
410
- CONNECT: '/meta/connect',
411
- SUBSCRIBE: '/meta/subscribe',
412
- UNSUBSCRIBE: '/meta/unsubscribe',
413
- DISCONNECT: '/meta/disconnect',
414
-
415
- META: 'meta',
416
- SERVICE: 'service',
417
-
418
- isValid: function(name) {
419
- return Faye.Grammar.CHANNEL_NAME.test(name) ||
420
- Faye.Grammar.CHANNEL_PATTERN.test(name);
421
- },
422
-
423
- parse: function(name) {
424
- if (!this.isValid(name)) return null;
425
- return name.split('/').slice(1);
426
- },
427
-
428
- isMeta: function(name) {
429
- var segments = this.parse(name);
430
- return segments ? (segments[0] === this.META) : null;
431
- },
432
-
433
- isService: function(name) {
434
- var segments = this.parse(name);
435
- return segments ? (segments[0] === this.SERVICE) : null;
436
- },
437
-
438
- isSubscribable: function(name) {
439
- if (!this.isValid(name)) return null;
440
- return !this.isMeta(name) && !this.isService(name);
441
- },
442
-
443
- Tree: Faye.Class({
444
- initialize: function(value) {
445
- this._value = value;
446
- this._children = {};
447
- },
448
-
449
- eachChild: function(block, context) {
450
- Faye.each(this._children, function(key, subtree) {
451
- block.call(context, key, subtree);
452
- });
453
- },
454
-
455
- each: function(prefix, block, context) {
456
- this.eachChild(function(path, subtree) {
457
- path = prefix.concat(path);
458
- subtree.each(path, block, context);
459
- });
460
- if (this._value !== undefined) block.call(context, prefix, this._value);
461
- },
462
-
463
- getKeys: function() {
464
- return this.map(function(key, value) { return '/' + key.join('/') });
465
- },
466
-
467
- map: function(block, context) {
468
- var result = [];
469
- this.each([], function(path, value) {
470
- result.push(block.call(context, path, value));
471
- });
472
- return result;
473
- },
474
-
475
- get: function(name) {
476
- var tree = this.traverse(name);
477
- return tree ? tree._value : null;
478
- },
479
-
480
- set: function(name, value) {
481
- var subtree = this.traverse(name, true);
482
- if (subtree) subtree._value = value;
483
- },
484
-
485
- traverse: function(path, createIfAbsent) {
486
- if (typeof path === 'string') path = Faye.Channel.parse(path);
487
-
488
- if (path === null) return null;
489
- if (path.length === 0) return this;
490
-
491
- var subtree = this._children[path[0]];
492
- if (!subtree && !createIfAbsent) return null;
493
- if (!subtree) subtree = this._children[path[0]] = new Faye.Channel.Tree();
494
-
495
- return subtree.traverse(path.slice(1), createIfAbsent);
496
- },
497
-
498
- findOrCreate: function(channel) {
499
- var existing = this.get(channel);
500
- if (existing) return existing;
501
- existing = new Faye.Channel(channel);
502
- this.set(channel, existing);
503
- return existing;
504
- },
505
-
506
- glob: function(path) {
507
- if (typeof path === 'string') path = Faye.Channel.parse(path);
508
-
509
- if (path === null) return [];
510
- if (path.length === 0) return (this._value === undefined) ? [] : [this._value];
511
-
512
- var list = [];
513
-
514
- if (Faye.enumEqual(path, ['*'])) {
515
- Faye.each(this._children, function(key, subtree) {
516
- if (subtree._value !== undefined) list.push(subtree._value);
517
- });
518
- return list;
519
- }
520
-
521
- if (Faye.enumEqual(path, ['**'])) {
522
- list = this.map(function(key, value) { return value });
523
- if (this._value !== undefined) list.pop();
524
- return list;
525
- }
526
-
527
- Faye.each(this._children, function(key, subtree) {
528
- if (key !== path[0] && key !== '*') return;
529
- var sublist = subtree.glob(path.slice(1));
530
- Faye.each(sublist, function(channel) { list.push(channel) });
531
- });
532
-
533
- if (this._children['**']) list.push(this._children['**']._value);
534
- return list;
535
- },
536
-
537
- subscribe: function(names, callback, scope) {
538
- if (!callback) return;
539
- Faye.each(names, function(name) {
540
- var channel = this.findOrCreate(name);
541
- channel.addSubscriber('message', callback, scope);
542
- }, this);
543
- },
544
-
545
- unsubscribe: function(name, callback, scope) {
546
- var channel = this.get(name);
547
- if (!channel) return false;
548
- channel.removeSubscriber('message', callback, scope);
549
- return channel.countSubscribers('message') === 0;
550
- },
551
-
552
- distributeMessage: function(message) {
553
- var channels = this.glob(message.channel);
554
- Faye.each(channels, function(channel) {
555
- channel.publishEvent('message', message.data);
556
- });
557
- }
558
- })
559
- });
560
-
561
-
562
- Faye.Subscription = Faye.Class({
563
- initialize: function(client, channels, callback, scope) {
564
- this._client = client;
565
- this._channels = channels;
566
- this._callback = callback;
567
- this._scope = scope;
568
- this._cancelled = false;
569
- },
570
-
571
- cancel: function() {
572
- if (this._cancelled) return;
573
- this._client.unsubscribe(this._channels, this._callback, this._scope);
574
- this._cancelled = true;
575
- },
576
-
577
- unsubscribe: function() {
578
- this.cancel();
579
- }
580
- });
581
-
582
-
583
- Faye.Client = Faye.Class({
584
- UNCONNECTED: 1,
585
- CONNECTING: 2,
586
- CONNECTED: 3,
587
- DISCONNECTED: 4,
588
-
589
- HANDSHAKE: 'handshake',
590
- RETRY: 'retry',
591
- NONE: 'none',
592
-
593
- CONNECTION_TIMEOUT: 60.0,
594
-
595
- DEFAULT_ENDPOINT: '/bayeux',
596
- MAX_DELAY: 0.001,
597
- INTERVAL: 0.0,
598
-
599
- initialize: function(endpoint, options) {
600
- this.info('New client created for ?', endpoint);
601
-
602
- this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
603
- this._options = options || {};
604
-
605
- this._transport = Faye.Transport.get(this, Faye.MANDATORY_CONNECTION_TYPES);
606
- this._state = this.UNCONNECTED;
607
- this._outbox = [];
608
- this._channels = new Faye.Channel.Tree();
609
-
610
- this._namespace = new Faye.Namespace();
611
- this._responseCallbacks = {};
612
-
613
- this._advice = {
614
- reconnect: this.RETRY,
615
- interval: 1000 * (this._options.interval || this.INTERVAL),
616
- timeout: 1000 * (this._options.timeout || this.CONNECTION_TIMEOUT)
617
- };
618
-
619
- if (Faye.Event) Faye.Event.on(Faye.ENV, 'beforeunload',
620
- this.disconnect, this);
621
- },
622
-
623
- // Request
624
- // MUST include: * channel
625
- // * version
626
- // * supportedConnectionTypes
627
- // MAY include: * minimumVersion
628
- // * ext
629
- // * id
630
- //
631
- // Success Response Failed Response
632
- // MUST include: * channel MUST include: * channel
633
- // * version * successful
634
- // * supportedConnectionTypes * error
635
- // * clientId MAY include: * supportedConnectionTypes
636
- // * successful * advice
637
- // MAY include: * minimumVersion * version
638
- // * advice * minimumVersion
639
- // * ext * ext
640
- // * id * id
641
- // * authSuccessful
642
- handshake: function(callback, scope) {
643
- if (this._advice.reconnect === this.NONE) return;
644
- if (this._state !== this.UNCONNECTED) return;
645
-
646
- this._state = this.CONNECTING;
647
- var self = this;
648
-
649
- this.info('Initiating handshake with ?', this._endpoint);
650
-
651
- this._send({
652
- channel: Faye.Channel.HANDSHAKE,
653
- version: Faye.BAYEUX_VERSION,
654
- supportedConnectionTypes: [this._transport.connectionType]
655
-
656
- }, function(response) {
657
-
658
- if (response.successful) {
659
- this._state = this.CONNECTED;
660
- this._clientId = response.clientId;
661
- this._transport = Faye.Transport.get(this, response.supportedConnectionTypes);
662
-
663
- this.info('Handshake successful: ?', this._clientId);
664
-
665
- this.subscribe(this._channels.getKeys());
666
- if (callback) callback.call(scope);
667
-
668
- } else {
669
- this.info('Handshake unsuccessful');
670
- setTimeout(function() { self.handshake(callback, scope) }, this._advice.interval);
671
- this._state = this.UNCONNECTED;
672
- }
673
- }, this);
674
- },
675
-
676
- // Request Response
677
- // MUST include: * channel MUST include: * channel
678
- // * clientId * successful
679
- // * connectionType * clientId
680
- // MAY include: * ext MAY include: * error
681
- // * id * advice
682
- // * ext
683
- // * id
684
- // * timestamp
685
- connect: function(callback, scope) {
686
- if (this._advice.reconnect === this.NONE) return;
687
- if (this._state === this.DISCONNECTED) return;
688
-
689
- if (this._state === this.UNCONNECTED)
690
- return this.handshake(function() { this.connect(callback, scope) }, this);
691
-
692
- this.callback(callback, scope);
693
- if (this._state !== this.CONNECTED) return;
694
-
695
- this.info('Calling deferred actions for ?', this._clientId);
696
- this.setDeferredStatus('succeeded');
697
- this.setDeferredStatus('deferred');
698
-
699
- if (this._connectRequest) return;
700
- this._connectRequest = true;
701
-
702
- this.info('Initiating connection for ?', this._clientId);
703
-
704
- this._send({
705
- channel: Faye.Channel.CONNECT,
706
- clientId: this._clientId,
707
- connectionType: this._transport.connectionType
708
-
709
- }, this._cycleConnection, this);
710
- },
711
-
712
- // Request Response
713
- // MUST include: * channel MUST include: * channel
714
- // * clientId * successful
715
- // MAY include: * ext * clientId
716
- // * id MAY include: * error
717
- // * ext
718
- // * id
719
- disconnect: function() {
720
- if (this._state !== this.CONNECTED) return;
721
- this._state = this.DISCONNECTED;
722
-
723
- this.info('Disconnecting ?', this._clientId);
724
-
725
- this._send({
726
- channel: Faye.Channel.DISCONNECT,
727
- clientId: this._clientId
728
- });
729
-
730
- this.info('Clearing channel listeners for ?', this._clientId);
731
- this._channels = new Faye.Channel.Tree();
732
- },
733
-
734
- // Request Response
735
- // MUST include: * channel MUST include: * channel
736
- // * clientId * successful
737
- // * subscription * clientId
738
- // MAY include: * ext * subscription
739
- // * id MAY include: * error
740
- // * advice
741
- // * ext
742
- // * id
743
- // * timestamp
744
- subscribe: function(channels, callback, scope) {
745
- if (channels instanceof Array)
746
- return Faye.each(channels, function(channel) {
747
- this.subscribe(channel, callback, scope);
748
- }, this);
749
-
750
- this._validateChannel(channels);
751
-
752
- this.connect(function() {
753
- this.info('Client ? attempting to subscribe to ?', this._clientId, channels);
754
-
755
- this._send({
756
- channel: Faye.Channel.SUBSCRIBE,
757
- clientId: this._clientId,
758
- subscription: channels
759
-
760
- }, function(response) {
761
- if (!response.successful) return;
762
-
763
- var channels = [].concat(response.subscription);
764
- this.info('Subscription acknowledged for ? to ?', this._clientId, channels);
765
- this._channels.subscribe(channels, callback, scope);
766
- }, this);
767
-
768
- }, this);
769
-
770
- return new Faye.Subscription(this, channels, callback, scope);
771
- },
772
-
773
- // Request Response
774
- // MUST include: * channel MUST include: * channel
775
- // * clientId * successful
776
- // * subscription * clientId
777
- // MAY include: * ext * subscription
778
- // * id MAY include: * error
779
- // * advice
780
- // * ext
781
- // * id
782
- // * timestamp
783
- unsubscribe: function(channels, callback, scope) {
784
- if (channels instanceof Array)
785
- return Faye.each(channels, function(channel) {
786
- this.unsubscribe(channel, callback, scope);
787
- }, this);
788
-
789
- this._validateChannel(channels);
790
-
791
- var dead = this._channels.unsubscribe(channels, callback, scope);
792
- if (!dead) return;
793
-
794
- this.connect(function() {
795
- this.info('Client ? attempting to unsubscribe from ?', this._clientId, channels);
796
-
797
- this._send({
798
- channel: Faye.Channel.UNSUBSCRIBE,
799
- clientId: this._clientId,
800
- subscription: channels
801
-
802
- }, function(response) {
803
- if (!response.successful) return;
804
-
805
- var channels = [].concat(response.subscription);
806
- this.info('Unsubscription acknowledged for ? from ?', this._clientId, channels);
807
- }, this);
808
-
809
- }, this);
810
- },
811
-
812
- // Request Response
813
- // MUST include: * channel MUST include: * channel
814
- // * data * successful
815
- // MAY include: * clientId MAY include: * id
816
- // * id * error
817
- // * ext * ext
818
- publish: function(channel, data) {
819
- this._validateChannel(channel);
820
-
821
- this.connect(function() {
822
- this.info('Client ? queueing published message to ?: ?', this._clientId, channel, data);
823
-
824
- this._send({
825
- channel: channel,
826
- data: data,
827
- clientId: this._clientId
828
- });
829
- }, this);
830
- },
831
-
832
- receiveMessage: function(message) {
833
- this.pipeThroughExtensions('incoming', message, function(message) {
834
- if (!message) return;
835
-
836
- if (message.advice) this._handleAdvice(message.advice);
837
-
838
- var callback = this._responseCallbacks[message.id];
839
- if (callback) {
840
- delete this._responseCallbacks[message.id];
841
- callback[0].call(callback[1], message);
842
- }
843
-
844
- this._deliverMessage(message);
845
- }, this);
846
- },
847
-
848
- _handleAdvice: function(advice) {
849
- Faye.extend(this._advice, advice);
850
-
851
- if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
852
- this._state = this.UNCONNECTED;
853
- this._clientId = null;
854
- this._cycleConnection();
855
- }
856
- },
857
-
858
- _deliverMessage: function(message) {
859
- if (!message.channel || !message.data) return;
860
- this.info('Client ? calling listeners for ? with ?', this._clientId, message.channel, message.data);
861
- this._channels.distributeMessage(message);
862
- },
863
-
864
- _teardownConnection: function() {
865
- if (!this._connectRequest) return;
866
- this._connectRequest = null;
867
- this.info('Closed connection for ?', this._clientId);
868
- },
869
-
870
- _cycleConnection: function() {
871
- this._teardownConnection();
872
- var self = this;
873
- setTimeout(function() { self.connect() }, this._advice.interval);
874
- },
875
-
876
- _send: function(message, callback, scope) {
877
- message.id = this._namespace.generate();
878
- if (callback) this._responseCallbacks[message.id] = [callback, scope];
879
-
880
- this.pipeThroughExtensions('outgoing', message, function(message) {
881
- if (!message) return;
882
-
883
- if (message.channel === Faye.Channel.HANDSHAKE)
884
- return this._transport.send(message, this._advice.timeout / 1000);
885
-
886
- this._outbox.push(message);
887
-
888
- if (message.channel === Faye.Channel.CONNECT)
889
- this._connectMessage = message;
890
-
891
- this.addTimeout('publish', this.MAX_DELAY, this._flush, this);
892
- }, this);
893
- },
894
-
895
- _flush: function() {
896
- this.removeTimeout('publish');
897
-
898
- if (this._outbox.length > 1 && this._connectMessage)
899
- this._connectMessage.advice = {timeout: 0};
900
-
901
- this._connectMessage = null;
902
-
903
- this._transport.send(this._outbox, this._advice.timeout / 1000);
904
- this._outbox = [];
905
- },
906
-
907
- _validateChannel: function(channel) {
908
- if (!Faye.Channel.isValid(channel))
909
- throw '"' + channel + '" is not a valid channel name';
910
- if (!Faye.Channel.isSubscribable(channel))
911
- throw 'Clients may not subscribe to channel "' + channel + '"';
912
- }
913
- });
914
-
915
- Faye.extend(Faye.Client.prototype, Faye.Deferrable);
916
- Faye.extend(Faye.Client.prototype, Faye.Timeouts);
917
- Faye.extend(Faye.Client.prototype, Faye.Logging);
918
- Faye.extend(Faye.Client.prototype, Faye.Extensible);
919
-
920
-
921
- Faye.Transport = Faye.extend(Faye.Class({
922
- initialize: function(client, endpoint) {
923
- this.debug('Created new ? transport for ?', this.connectionType, endpoint);
924
- this._client = client;
925
- this._endpoint = endpoint;
926
- },
927
-
928
- send: function(messages, timeout) {
929
- messages = [].concat(messages);
930
-
931
- this.debug('Client ? sending message to ?: ?',
932
- this._client._clientId, this._endpoint, messages);
933
-
934
- return this.request(messages, timeout);
935
- },
936
-
937
- receive: function(responses) {
938
- this.debug('Client ? received from ?: ?',
939
- this._client._clientId, this._endpoint, responses);
940
-
941
- Faye.each(responses, this._client.receiveMessage, this._client);
942
- },
943
-
944
- retry: function(message, timeout) {
945
- var self = this;
946
- return function() {
947
- setTimeout(function() { self.request(message, 2 * timeout) }, 1000 * timeout);
948
- };
949
- }
950
-
951
- }), {
952
- get: function(client, connectionTypes) {
953
- var endpoint = client._endpoint;
954
- if (connectionTypes === undefined) connectionTypes = this.supportedConnectionTypes();
955
-
956
- var candidateClass = null;
957
- Faye.each(this._transports, function(pair) {
958
- var connType = pair[0], klass = pair[1];
959
- if (Faye.indexOf(connectionTypes, connType) < 0) return;
960
- if (candidateClass) return;
961
- if (klass.isUsable(endpoint)) candidateClass = klass;
962
- });
963
-
964
- if (!candidateClass) throw 'Could not find a usable connection type for ' + endpoint;
965
-
966
- return new candidateClass(client, endpoint);
967
- },
968
-
969
- register: function(type, klass) {
970
- this._transports.push([type, klass]);
971
- klass.prototype.connectionType = type;
972
- },
973
-
974
- _transports: [],
975
-
976
- supportedConnectionTypes: function() {
977
- return Faye.map(this._transports, function(pair) { return pair[0] });
978
- }
979
- });
980
-
981
- Faye.extend(Faye.Transport.prototype, Faye.Logging);
982
-
983
-
984
- Faye.Set = Faye.Class({
985
- initialize: function() {
986
- this._index = {};
987
- },
988
-
989
- add: function(item) {
990
- var key = (item.id !== undefined) ? item.id : item;
991
- if (this._index.hasOwnProperty(key)) return false;
992
- this._index[key] = item;
993
- return true;
994
- },
995
-
996
- forEach: function(block, scope) {
997
- for (var key in this._index) {
998
- if (this._index.hasOwnProperty(key))
999
- block.call(scope, this._index[key]);
1000
- }
1001
- },
1002
-
1003
- isEmpty: function() {
1004
- for (var key in this._index) {
1005
- if (this._index.hasOwnProperty(key)) return false;
1006
- }
1007
- return true;
1008
- },
1009
-
1010
- member: function(item) {
1011
- for (var key in this._index) {
1012
- if (this._index[key] === item) return true;
1013
- }
1014
- return false;
1015
- },
1016
-
1017
- remove: function(item) {
1018
- var key = (item.id !== undefined) ? item.id : item;
1019
- delete this._index[key];
1020
- },
1021
-
1022
- toArray: function() {
1023
- var array = [];
1024
- this.forEach(function(item) { array.push(item) });
1025
- return array;
1026
- }
1027
- });
1028
-
1029
-
1030
- /**
1031
- * Generic WebSocket implementation for Node
1032
- * -----------------------------------------
1033
- *
1034
- * Though primarily here to support WebSockets as a network
1035
- * transport in Faye, it would be nice for this class to
1036
- * implement the same interface as the client-side WebSocket
1037
- * for ease of use.
1038
- *
1039
- * For implementation reference:
1040
- * http://dev.w3.org/html5/websockets/
1041
- * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
1042
- * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
1043
- * http://www.w3.org/TR/DOM-Level-2-Events/events.html
1044
- **/
1045
-
1046
- var Buffer = require('buffer').Buffer,
1047
- crypto = require('crypto');
1048
-
1049
- Faye.WebSocket = Faye.Class({
1050
- onopen: null,
1051
- onmessage: null,
1052
- onerror: null,
1053
- onclose: null,
1054
-
1055
- initialize: function(request, head) {
1056
- this._request = request;
1057
- this._head = head;
1058
- this._stream = request.socket;
1059
-
1060
- this.url = 'ws://' + request.headers.host + request.url;
1061
- this.readyState = Faye.WebSocket.CONNECTING;
1062
- this.bufferedAmount = 0;
1063
-
1064
- this._handler = Faye.WebSocket.getHandler(request);
1065
- this._handler.handshake(this.url, this._request, this._head, this._stream);
1066
- this.readyState = Faye.WebSocket.OPEN;
1067
-
1068
- var event = new Faye.WebSocket.Event();
1069
- event.initEvent('open', false, false);
1070
- this.dispatchEvent(event);
1071
-
1072
- this._buffer = [];
1073
- this._buffering = false;
1074
-
1075
- var self = this;
1076
-
1077
- this._stream.addListener('data', function(data) {
1078
- for (var i = 0, n = data.length; i < n; i++)
1079
- self._handleChar(data[i]);
1080
- });
1081
- },
1082
-
1083
- send: function(data) {
1084
- this._handler.send(this._stream, data);
1085
- return true;
1086
- },
1087
-
1088
- close: function() {},
1089
-
1090
- addEventListener: function(type, listener, useCapture) {
1091
- this.addSubscriber(type, listener);
1092
- },
1093
-
1094
- removeEventListener: function(type, listener, useCapture) {
1095
- this.removeSubscriber(type, listener);
1096
- },
1097
-
1098
- dispatchEvent: function(event) {
1099
- event.target = event.currentTarget = this;
1100
- event.eventPhase = Faye.WebSocket.Event.AT_TARGET;
1101
-
1102
- this.publishEvent(event.type, event);
1103
- if (this['on' + event.type])
1104
- this['on' + event.type](event);
1105
- },
1106
-
1107
- _handleChar: function(data) {
1108
- switch (data) {
1109
- case 0x00:
1110
- this._buffering = true;
1111
- break;
1112
-
1113
- case 0xFF:
1114
- this._buffer = new Buffer(this._buffer);
1115
-
1116
- var event = new Faye.WebSocket.Event();
1117
- event.initEvent('message', false, false);
1118
- event.data = this._buffer.toString('utf8', 0, this._buffer.length);
1119
-
1120
- this.dispatchEvent(event);
1121
-
1122
- this._buffer = [];
1123
- this._buffering = false;
1124
- break;
1125
-
1126
- default:
1127
- if (this._buffering) this._buffer.push(data);
1128
- }
1129
- }
1130
- });
1131
-
1132
- Faye.extend(Faye.WebSocket.prototype, Faye.Publisher);
1133
-
1134
- Faye.extend(Faye.WebSocket, {
1135
- CONNECTING: 0,
1136
- OPEN: 1,
1137
- CLOSING: 2,
1138
- CLOSED: 3,
1139
-
1140
- Event: Faye.extend(Faye.Class({
1141
- initEvent: function(eventType, canBubble, cancelable) {
1142
- this.type = eventType;
1143
- this.bubbles = canBubble;
1144
- this.cancelable = cancelable;
1145
- },
1146
-
1147
- stopPropagation: function() {},
1148
- preventDefault: function() {}
1149
-
1150
- }), {
1151
- CAPTURING_PHASE: 1,
1152
- AT_TARGET: 2,
1153
- BUBBLING_PHASE: 3
1154
- }),
1155
-
1156
- getHandler: function(request) {
1157
- var headers = request.headers;
1158
- return (headers['sec-websocket-key1'] && headers['sec-websocket-key2'])
1159
- ? this.Protocol76
1160
- : this.Protocol75;
1161
- }
1162
- });
1163
-
1164
- (function() {
1165
- var byteToChar = function(value) {
1166
- if (typeof value === 'string') value = parseInt(value, 16);
1167
- return String.fromCharCode(value);
1168
- };
1169
-
1170
- var numberFromKey = function(key) {
1171
- return parseInt(key.match(/[0-9]/g).join(''), 10);
1172
- };
1173
-
1174
- var spacesInKey = function(key) {
1175
- return key.match(/ /g).length;
1176
- };
1177
-
1178
- var bigEndian = function(number) {
1179
- var string = '';
1180
- Faye.each([24,16,8,0], function(offset) {
1181
- string += String.fromCharCode(number >> offset & 0xFF);
1182
- });
1183
- return string;
1184
- };
1185
-
1186
- var writeToSocket = function(socket, message) {
1187
- try {
1188
- socket.write(FRAME_START, 'binary');
1189
- socket.write(message, 'utf8');
1190
- socket.write(FRAME_END, 'binary');
1191
- } catch (e) {
1192
- // socket closed while writing
1193
- }
1194
- };
1195
-
1196
- var FRAME_START = byteToChar('00'),
1197
- FRAME_END = byteToChar('FF');
1198
-
1199
- Faye.WebSocket.Protocol75 = {
1200
- handshake: function(url, request, head, socket) {
1201
- socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n');
1202
- socket.write('Upgrade: WebSocket\r\n');
1203
- socket.write('Connection: Upgrade\r\n');
1204
- socket.write('WebSocket-Origin: ' + request.headers.origin + '\r\n');
1205
- socket.write('WebSocket-Location: ' + url + '\r\n');
1206
- socket.write('\r\n');
1207
- },
1208
-
1209
- send: function(socket, message) {
1210
- writeToSocket(socket, message);
1211
- }
1212
- };
1213
-
1214
- Faye.WebSocket.Protocol76 = {
1215
- handshake: function(url, request, head, socket) {
1216
- var key1 = request.headers['sec-websocket-key1'],
1217
- value1 = numberFromKey(key1) / spacesInKey(key1),
1218
-
1219
- key2 = request.headers['sec-websocket-key2'],
1220
- value2 = numberFromKey(key2) / spacesInKey(key2),
1221
-
1222
- MD5 = crypto.createHash('md5');
1223
-
1224
- MD5.update(bigEndian(value1));
1225
- MD5.update(bigEndian(value2));
1226
- MD5.update(head.toString('binary'));
1227
-
1228
- socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n', 'binary');
1229
- socket.write('Upgrade: WebSocket\r\n', 'binary');
1230
- socket.write('Connection: Upgrade\r\n', 'binary');
1231
- socket.write('Sec-WebSocket-Origin: ' + request.headers.origin + '\r\n', 'binary');
1232
- socket.write('Sec-WebSocket-Location: ' + url + '\r\n', 'binary');
1233
- socket.write('\r\n', 'binary');
1234
- socket.write(MD5.digest('binary'), 'binary');
1235
- },
1236
-
1237
- send: function(socket, message) {
1238
- writeToSocket(socket, message);
1239
- }
1240
- }
1241
- })();
1242
-
1243
-
1244
- Faye.Error = Faye.Class({
1245
- initialize: function(code, args, message) {
1246
- this.code = code;
1247
- this.args = Array.prototype.slice.call(args);
1248
- this.message = message;
1249
- },
1250
-
1251
- toString: function() {
1252
- return this.code + ':' +
1253
- this.args.join(',') + ':' +
1254
- this.message;
1255
- }
1256
- });
1257
-
1258
-
1259
- Faye.Error.versionMismatch = function() {
1260
- return new this(300, arguments, "Version mismatch").toString();
1261
- };
1262
-
1263
- Faye.Error.conntypeMismatch = function() {
1264
- return new this(301, arguments, "Connection types not supported").toString();
1265
- };
1266
-
1267
- Faye.Error.extMismatch = function() {
1268
- return new this(302, arguments, "Extension mismatch").toString();
1269
- };
1270
-
1271
- Faye.Error.badRequest = function() {
1272
- return new this(400, arguments, "Bad request").toString();
1273
- };
1274
-
1275
- Faye.Error.clientUnknown = function() {
1276
- return new this(401, arguments, "Unknown client").toString();
1277
- };
1278
-
1279
- Faye.Error.parameterMissing = function() {
1280
- return new this(402, arguments, "Missing required parameter").toString();
1281
- };
1282
-
1283
- Faye.Error.channelForbidden = function() {
1284
- return new this(403, arguments, "Forbidden channel").toString();
1285
- };
1286
-
1287
- Faye.Error.channelUnknown = function() {
1288
- return new this(404, arguments, "Unknown channel").toString();
1289
- };
1290
-
1291
- Faye.Error.channelInvalid = function() {
1292
- return new this(405, arguments, "Invalid channel").toString();
1293
- };
1294
-
1295
- Faye.Error.extUnknown = function() {
1296
- return new this(406, arguments, "Unknown extension").toString();
1297
- };
1298
-
1299
- Faye.Error.publishFailed = function() {
1300
- return new this(407, arguments, "Failed to publish").toString();
1301
- };
1302
-
1303
- Faye.Error.serverError = function() {
1304
- return new this(500, arguments, "Internal server error").toString();
1305
- };
1306
-
1307
-
1308
-
1309
- Faye.Server = Faye.Class({
1310
- initialize: function(options) {
1311
- this.info('New server created');
1312
- this._options = options || {};
1313
- this._channels = new Faye.Channel.Tree();
1314
- this._connections = {};
1315
- this._namespace = new Faye.Namespace();
1316
- },
1317
-
1318
- clientIds: function() {
1319
- return Faye.map(this._connections, function(key, value) { return key });
1320
- },
1321
-
1322
- process: function(messages, localOrRemote, callback, scope) {
1323
- var socket = (localOrRemote instanceof Faye.WebSocket) ? localOrRemote : null,
1324
- local = (localOrRemote === true);
1325
-
1326
- this.debug('Processing messages from ? client', local ? 'LOCAL' : 'REMOTE');
1327
-
1328
- messages = [].concat(messages);
1329
- var processed = 0, responses = [];
1330
-
1331
- var gatherReplies = function(replies) {
1332
- responses = responses.concat(replies);
1333
- processed += 1;
1334
- if (processed < messages.length) return;
1335
-
1336
- var n = responses.length;
1337
- while (n--) {
1338
- if (!responses[n]) responses.splice(n,1);
1339
- }
1340
- callback.call(scope, responses);
1341
- };
1342
-
1343
- var handleReply = function(replies) {
1344
- var extended = 0, expected = replies.length;
1345
- if (expected === 0) gatherReplies(replies);
1346
-
1347
- Faye.each(replies, function(reply, i) {
1348
- this.pipeThroughExtensions('outgoing', reply, function(message) {
1349
- replies[i] = message;
1350
- extended += 1;
1351
- if (extended === expected) gatherReplies(replies);
1352
- });
1353
- }, this);
1354
- };
1355
-
1356
- Faye.each(messages, function(message) {
1357
- this.pipeThroughExtensions('incoming', message, function(pipedMessage) {
1358
- this._handle(pipedMessage, socket, local, handleReply, this);
1359
- }, this);
1360
- }, this);
1361
- },
1362
-
1363
- flushConnection: function(messages) {
1364
- messages = [].concat(messages);
1365
- Faye.each(messages, function(message) {
1366
- var connection = this._connections[message.clientId];
1367
- if (connection) connection.flush();
1368
- }, this);
1369
- },
1370
-
1371
- _connection: function(id) {
1372
- if (this._connections.hasOwnProperty(id)) return this._connections[id];
1373
- var connection = new Faye.Connection(id, this._options);
1374
- connection.addSubscriber('staleConnection', this._destroyConnection, this);
1375
- return this._connections[id] = connection;
1376
- },
1377
-
1378
- _destroyConnection: function(connection) {
1379
- connection.disconnect();
1380
- connection.removeSubscriber('staleConnection', this._destroyConnection, this);
1381
- delete this._connections[connection.id];
1382
- },
1383
-
1384
- _makeResponse: function(message) {
1385
- var response = {};
1386
- Faye.each(['id', 'clientId', 'channel', 'error'], function(field) {
1387
- if (message[field]) response[field] = message[field];
1388
- });
1389
- response.successful = !response.error;
1390
- return response;
1391
- },
1392
-
1393
- _distributeMessage: function(message) {
1394
- Faye.each(this._channels.glob(message.channel), function(channel) {
1395
- channel.push(message);
1396
- this.info('Publishing message ? from client ? to ?', message.data, message.clientId, channel.name);
1397
- }, this);
1398
- },
1399
-
1400
- _handle: function(message, socket, local, callback, scope) {
1401
- if (!message) return callback.call(scope, []);
1402
- if (message.error) return callback.call(scope, [this._makeResponse(message)]);
1403
-
1404
- this._distributeMessage(message);
1405
- var channelName = message.channel, response;
1406
-
1407
- if (Faye.Channel.isMeta(channelName)) {
1408
- this._handleMeta(message, socket, local, callback, scope);
1409
- } else if (!message.clientId) {
1410
- callback.call(scope, []);
1411
- } else {
1412
- response = this._makeResponse(message);
1413
- response.successful = true;
1414
- callback.call(scope, [response]);
1415
- }
1416
- },
1417
-
1418
- _handleMeta: function(message, socket, local, callback, scope) {
1419
- var response = this[Faye.Channel.parse(message.channel)[1]](message, local);
1420
-
1421
- this._advize(response);
1422
-
1423
- if (response.channel === Faye.Channel.CONNECT && response.successful === true)
1424
- return this._acceptConnection(message.advice, response, socket, callback, scope);
1425
-
1426
- callback.call(scope, [response]);
1427
- },
1428
-
1429
- _acceptConnection: function(options, response, socket, callback, scope) {
1430
- this.info('Accepting connection from ?', response.clientId);
1431
-
1432
- var connection = this._connection(response.clientId);
1433
-
1434
- // Disabled because CometD doesn't like messages not being
1435
- // delivered as part of a /meta/* response
1436
- // if (socket) return connection.setSocket(socket);
1437
-
1438
- connection.connect(options, function(events) {
1439
- this.info('Sending event messages to ?', response.clientId);
1440
- this.debug('Events for ?: ?', response.clientId, events);
1441
- callback.call(scope, [response].concat(events));
1442
- }, this);
1443
- },
1444
-
1445
- _advize: function(response) {
1446
- var connection = this._connections[response.clientId];
1447
-
1448
- response.advice = response.advice || {};
1449
- if (connection) {
1450
- Faye.extend(response.advice, {
1451
- reconnect: 'retry',
1452
- interval: Math.floor(connection.interval * 1000),
1453
- timeout: Math.floor(connection.timeout * 1000)
1454
- }, false);
1455
- } else {
1456
- Faye.extend(response.advice, {
1457
- reconnect: 'handshake'
1458
- }, false);
1459
- }
1460
- },
1461
-
1462
- // MUST contain * version
1463
- // * supportedConnectionTypes
1464
- // MAY contain * minimumVersion
1465
- // * ext
1466
- // * id
1467
- handshake: function(message, local) {
1468
- var response = this._makeResponse(message);
1469
- response.version = Faye.BAYEUX_VERSION;
1470
-
1471
- if (!message.version)
1472
- response.error = Faye.Error.parameterMissing('version');
1473
-
1474
- var clientConns = message.supportedConnectionTypes,
1475
- commonConns;
1476
-
1477
- if (!local) {
1478
- response.supportedConnectionTypes = Faye.CONNECTION_TYPES;
1479
-
1480
- if (clientConns) {
1481
- commonConns = Faye.filter(clientConns, function(conn) {
1482
- return Faye.indexOf(Faye.CONNECTION_TYPES, conn) !== -1;
1483
- });
1484
- if (commonConns.length === 0)
1485
- response.error = Faye.Error.conntypeMismatch(clientConns);
1486
- } else {
1487
- response.error = Faye.Error.parameterMissing('supportedConnectionTypes');
1488
- }
1489
- }
1490
-
1491
- response.successful = !response.error;
1492
- if (!response.successful) return response;
1493
-
1494
- var clientId = this._namespace.generate();
1495
- response.clientId = this._connection(clientId).id;
1496
- this.info('Accepting handshake from client ?', response.clientId);
1497
- return response;
1498
- },
1499
-
1500
- // MUST contain * clientId
1501
- // * connectionType
1502
- // MAY contain * ext
1503
- // * id
1504
- connect: function(message, local) {
1505
- var response = this._makeResponse(message);
1506
-
1507
- var clientId = message.clientId,
1508
- connection = clientId ? this._connections[clientId] : null,
1509
- connectionType = message.connectionType;
1510
-
1511
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1512
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1513
- if (!connectionType) response.error = Faye.Error.parameterMissing('connectionType');
1514
-
1515
- response.successful = !response.error;
1516
- if (!response.successful) delete response.clientId;
1517
- if (!response.successful) return response;
1518
-
1519
- response.clientId = connection.id;
1520
- return response;
1521
- },
1522
-
1523
- // MUST contain * clientId
1524
- // MAY contain * ext
1525
- // * id
1526
- disconnect: function(message, local) {
1527
- var response = this._makeResponse(message);
1528
-
1529
- var clientId = message.clientId,
1530
- connection = clientId ? this._connections[clientId] : null;
1531
-
1532
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1533
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1534
-
1535
- response.successful = !response.error;
1536
- if (!response.successful) delete response.clientId;
1537
- if (!response.successful) return response;
1538
-
1539
- this._destroyConnection(connection);
1540
-
1541
- this.info('Disconnected client: ?', clientId);
1542
- response.clientId = clientId;
1543
- return response;
1544
- },
1545
-
1546
- // MUST contain * clientId
1547
- // * subscription
1548
- // MAY contain * ext
1549
- // * id
1550
- subscribe: function(message, local) {
1551
- var response = this._makeResponse(message);
1552
-
1553
- var clientId = message.clientId,
1554
- connection = clientId ? this._connections[clientId] : null,
1555
- subscription = message.subscription;
1556
-
1557
- subscription = [].concat(subscription);
1558
-
1559
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1560
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1561
- if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
1562
-
1563
- response.subscription = subscription;
1564
-
1565
- Faye.each(subscription, function(channel) {
1566
- if (response.error) return;
1567
- if (!local && !Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
1568
- if (!Faye.Channel.isValid(channel)) response.error = Faye.Error.channelInvalid(channel);
1569
-
1570
- if (response.error) return;
1571
- channel = this._channels.findOrCreate(channel);
1572
-
1573
- this.info('Subscribing client ? to ?', clientId, channel.name);
1574
- connection.subscribe(channel);
1575
- }, this);
1576
-
1577
- response.successful = !response.error;
1578
- return response;
1579
- },
1580
-
1581
- // MUST contain * clientId
1582
- // * subscription
1583
- // MAY contain * ext
1584
- // * id
1585
- unsubscribe: function(message, local) {
1586
- var response = this._makeResponse(message);
1587
-
1588
- var clientId = message.clientId,
1589
- connection = clientId ? this._connections[clientId] : null,
1590
- subscription = message.subscription;
1591
-
1592
- subscription = [].concat(subscription);
1593
-
1594
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1595
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1596
- if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
1597
-
1598
- response.subscription = subscription;
1599
-
1600
- Faye.each(subscription, function(channel) {
1601
- if (response.error) return;
1602
-
1603
- if (!Faye.Channel.isValid(channel))
1604
- return response.error = Faye.Error.channelInvalid(channel);
1605
-
1606
- channel = this._channels.get(channel);
1607
- if (!channel) return;
1608
-
1609
- this.info('Unsubscribing client ? from ?', clientId, channel.name);
1610
- connection.unsubscribe(channel);
1611
- }, this);
1612
-
1613
- response.successful = !response.error;
1614
- return response;
1615
- }
1616
- });
1617
-
1618
- Faye.extend(Faye.Server.prototype, Faye.Logging);
1619
- Faye.extend(Faye.Server.prototype, Faye.Extensible);
1620
-
1621
-
1622
- Faye.Connection = Faye.Class({
1623
- MAX_DELAY: 0.001,
1624
- INTERVAL: 0.0,
1625
- TIMEOUT: 60.0,
1626
-
1627
- initialize: function(id, options) {
1628
- this.id = id;
1629
- this._options = options;
1630
- this.interval = this._options.interval || this.INTERVAL;
1631
- this.timeout = this._options.timeout || this.TIMEOUT;
1632
- this._channels = new Faye.Set();
1633
- this._inbox = new Faye.Set();
1634
- this._connected = false;
1635
-
1636
- this._beginDeletionTimeout();
1637
- },
1638
-
1639
- setSocket: function(socket) {
1640
- this._connected = true;
1641
- this._socket = socket;
1642
- },
1643
-
1644
- _onMessage: function(event) {
1645
- if (!this._inbox.add(event)) return;
1646
- if (this._socket) this._socket.send(Faye.toJSON(event));
1647
- this._beginDeliveryTimeout();
1648
- },
1649
-
1650
- subscribe: function(channel) {
1651
- if (!this._channels.add(channel)) return;
1652
- channel.addSubscriber('message', this._onMessage, this);
1653
- },
1654
-
1655
- unsubscribe: function(channel) {
1656
- if (channel === 'all') return this._channels.forEach(this.unsubscribe, this);
1657
- if (!this._channels.member(channel)) return;
1658
- this._channels.remove(channel);
1659
- channel.removeSubscriber('message', this._onMessage, this);
1660
- },
1661
-
1662
- connect: function(options, callback, scope) {
1663
- options = options || {};
1664
- var timeout = (options.timeout !== undefined) ? options.timeout / 1000 : this.timeout;
1665
-
1666
- this.setDeferredStatus('deferred');
1667
-
1668
- this.callback(callback, scope);
1669
- if (this._connected) return;
1670
-
1671
- this._connected = true;
1672
- this.removeTimeout('deletion');
1673
-
1674
- this._beginDeliveryTimeout();
1675
- this._beginConnectionTimeout(timeout);
1676
- },
1677
-
1678
- flush: function() {
1679
- if (!this._connected) return;
1680
- this._releaseConnection();
1681
-
1682
- var events = this._inbox.toArray();
1683
- this._inbox = new Faye.Set();
1684
-
1685
- this.setDeferredStatus('succeeded', events);
1686
- this.setDeferredStatus('deferred');
1687
- },
1688
-
1689
- disconnect: function() {
1690
- this.unsubscribe('all');
1691
- this.flush();
1692
- },
1693
-
1694
- _releaseConnection: function() {
1695
- if (this._socket) return;
1696
-
1697
- this.removeTimeout('connection');
1698
- this.removeTimeout('delivery');
1699
- this._connected = false;
1700
-
1701
- this._beginDeletionTimeout();
1702
- },
1703
-
1704
- _beginDeliveryTimeout: function() {
1705
- if (!this._connected || this._inbox.isEmpty()) return;
1706
- this.addTimeout('delivery', this.MAX_DELAY, this.flush, this);
1707
- },
1708
-
1709
- _beginConnectionTimeout: function(timeout) {
1710
- if (!this._connected) return;
1711
- this.addTimeout('connection', timeout, this.flush, this);
1712
- },
1713
-
1714
- _beginDeletionTimeout: function() {
1715
- if (this._connected) return;
1716
- this.addTimeout('deletion', this.TIMEOUT + 10 * this.timeout, function() {
1717
- this.publishEvent('staleConnection', this);
1718
- }, this);
1719
- }
1720
- });
1721
-
1722
- Faye.extend(Faye.Connection.prototype, Faye.Deferrable);
1723
- Faye.extend(Faye.Connection.prototype, Faye.Publisher);
1724
- Faye.extend(Faye.Connection.prototype, Faye.Timeouts);
1725
-
1726
-
1727
- Faye.NodeHttpTransport = Faye.Class(Faye.Transport, {
1728
- request: function(message, timeout) {
1729
- var uri = url.parse(this._endpoint),
1730
- secure = (uri.protocol === 'https:'),
1731
- client = http.createClient(uri.port, uri.hostname, secure),
1732
- content = JSON.stringify(message),
1733
- response = null,
1734
- retry = this.retry(message, timeout),
1735
- self = this;
1736
-
1737
- client.addListener('error', retry);
1738
-
1739
- client.addListener('end', function() {
1740
- if (!response) retry();
1741
- });
1742
-
1743
- var request = client.request('POST', uri.pathname, {
1744
- 'Content-Type': 'application/json',
1745
- 'Host': uri.hostname,
1746
- 'Content-Length': content.length
1747
- });
1748
-
1749
- request.addListener('response', function(stream) {
1750
- response = stream;
1751
- Faye.withDataFor(response, function(data) {
1752
- try {
1753
- self.receive(JSON.parse(data));
1754
- } catch (e) {
1755
- retry();
1756
- }
1757
- });
1758
- });
1759
-
1760
- request.write(content);
1761
- request.end();
1762
- }
1763
- });
1764
-
1765
- Faye.NodeHttpTransport.isUsable = function(endpoint) {
1766
- return typeof endpoint === 'string';
1767
- };
1768
-
1769
- Faye.Transport.register('long-polling', Faye.NodeHttpTransport);
1770
-
1771
- Faye.NodeLocalTransport = Faye.Class(Faye.Transport, {
1772
- request: function(message, timeout) {
1773
- this._endpoint.process(message, true, this.receive, this);
1774
- }
1775
- });
1776
-
1777
- Faye.NodeLocalTransport.isUsable = function(endpoint) {
1778
- return endpoint instanceof Faye.Server;
1779
- };
1780
-
1781
- Faye.Transport.register('in-process', Faye.NodeLocalTransport);
1782
-
1783
-
1784
- var path = require('path'),
1785
- fs = require('fs'),
1786
- sys = require('sys'),
1787
- url = require('url'),
1788
- http = require('http'),
1789
- querystring = require('querystring');
1790
-
1791
- Faye.logger = function(message) {
1792
- sys.puts(message);
1793
- };
1794
-
1795
- Faye.withDataFor = function(transport, callback, scope) {
1796
- var data = '';
1797
- transport.addListener('data', function(chunk) { data += chunk });
1798
- transport.addListener('end', function() {
1799
- callback.call(scope, data);
1800
- });
1801
- };
1802
-
1803
- Faye.NodeAdapter = Faye.Class({
1804
- DEFAULT_ENDPOINT: '/bayeux',
1805
- SCRIPT_PATH: path.dirname(__filename) + '/faye-browser-min.js',
1806
-
1807
- TYPE_JSON: {'Content-Type': 'application/json'},
1808
- TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
1809
- TYPE_TEXT: {'Content-Type': 'text/plain'},
1810
-
1811
- initialize: function(options) {
1812
- this._options = options || {};
1813
- this._endpoint = this._options.mount || this.DEFAULT_ENDPOINT;
1814
- this._endpointRe = new RegExp('^' + this._endpoint + '(/[^/]*)*(\\.js)?$');
1815
- this._server = new Faye.Server(this._options);
1816
- },
1817
-
1818
- addExtension: function(extension) {
1819
- return this._server.addExtension(extension);
1820
- },
1821
-
1822
- removeExtension: function(extension) {
1823
- return this._server.removeExtension(extension);
1824
- },
1825
-
1826
- getClient: function() {
1827
- return this._client = this._client || new Faye.Client(this._server);
1828
- },
1829
-
1830
- listen: function(port) {
1831
- var httpServer = http.createServer(function() {});
1832
- this.attach(httpServer);
1833
- httpServer.listen(port);
1834
- },
1835
-
1836
- attach: function(httpServer) {
1837
- this._overrideListeners(httpServer, 'request', 'handle');
1838
- this._overrideListeners(httpServer, 'upgrade', 'handleUpgrade');
1839
- },
1840
-
1841
- _overrideListeners: function(httpServer, event, method) {
1842
- var listeners = httpServer.listeners(event),
1843
- self = this;
1844
-
1845
- httpServer.removeAllListeners(event);
1846
-
1847
- httpServer.addListener(event, function(request) {
1848
- if (self.check(request)) return self[method].apply(self, arguments);
1849
-
1850
- for (var i = 0, n = listeners.length; i < n; i++)
1851
- listeners[i].apply(this, arguments);
1852
- });
1853
- },
1854
-
1855
- check: function(request) {
1856
- var path = url.parse(request.url, true).pathname;
1857
- return !!this._endpointRe.test(path);
1858
- },
1859
-
1860
- handle: function(request, response) {
1861
- var requestUrl = url.parse(request.url, true),
1862
- self = this, data;
1863
-
1864
- if (/\.js$/.test(requestUrl.pathname)) {
1865
- fs.readFile(this.SCRIPT_PATH, function(err, content) {
1866
- response.writeHead(200, self.TYPE_SCRIPT);
1867
- response.write(content);
1868
- response.end();
1869
- });
1870
-
1871
- } else {
1872
- var isGet = (request.method === 'GET');
1873
-
1874
- if (isGet)
1875
- this._callWithParams(request, response, requestUrl.query);
1876
-
1877
- else
1878
- Faye.withDataFor(request, function(data) {
1879
- self._callWithParams(request, response, {message: data});
1880
- });
1881
- }
1882
- return true;
1883
- },
1884
-
1885
- handleUpgrade: function(request, socket, head) {
1886
- var socket = new Faye.WebSocket(request, head),
1887
- self = this;
1888
-
1889
- socket.onmessage = function(message) {
1890
- try {
1891
- var message = JSON.parse(message.data);
1892
- self._server.process(message, socket, function(replies) {
1893
- socket.send(JSON.stringify(replies));
1894
- });
1895
- } catch (e) {}
1896
- };
1897
- },
1898
-
1899
- _callWithParams: function(request, response, params) {
1900
- try {
1901
- var message = JSON.parse(params.message),
1902
- jsonp = params.jsonp || Faye.JSONP_CALLBACK,
1903
- isGet = (request.method === 'GET'),
1904
- type = isGet ? this.TYPE_SCRIPT : this.TYPE_JSON;
1905
-
1906
- if (isGet) this._server.flushConnection(message);
1907
-
1908
- this._server.process(message, false, function(replies) {
1909
- var body = JSON.stringify(replies);
1910
- if (isGet) body = jsonp + '(' + body + ');';
1911
- response.writeHead(200, type);
1912
- response.write(body);
1913
- response.end();
1914
- });
1915
- } catch (e) {
1916
- response.writeHead(400, this.TYPE_TEXT);
1917
- response.write('Bad request');
1918
- response.end();
1919
- }
1920
- }
1921
- });
1922
-
1923
- exports.NodeAdapter = Faye.NodeAdapter;
1924
- exports.Client = Faye.Client;
1925
- exports.Logging = Faye.Logging;