subduino 0.3.1 → 0.5.0

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.
@@ -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;