Permalink
Browse files

Major overhaul after much testing.

Notable changes:
 - The example server is now a more complete demo, allowing connections to the server via any of the implemented transports.

 - Flash WebSocket support added (via gimite/web-socket-js).

 - The plain TCP client handling is now disabled by default. Plain TCP client handling on the same port could currently present a problem with the addition of Flash WebSocket support.

 - A grappler server's origins option can now either be a "*:*"-type string, or an array of such strings.

 - Connections now only add themselves to the server's connection hash if they plan on sticking around for awhile.

 - Long polling is now implemented such that a persistent connection is emulated.

 - Removed unnecessary code.
  • Loading branch information...
mscdex committed Jul 19, 2010
1 parent 435e465 commit 411377386366d15b0cf8f76b22eab719ce12a379
Showing with 649 additions and 199 deletions.
  1. +14 −7 README.md
  2. BIN example/WebSocketMain.swf
  3. +44 −0 example/flashws.js
  4. +75 −23 example/server.js
  5. +267 −0 example/test.htm
  6. +75 −71 lib/grappler.js
  7. +174 −98 lib/http.client.js
View
@@ -1,22 +1,29 @@
Grappler
========
-Grappler is a minimalistic server for hanging TCP/HTTP connections. It supports the following transports:
+Grappler is a minimalistic server for hanging ("comet") TCP/HTTP connections that exposes a single, consistent API across all transports.
+It supports the following transports:
- WebSockets (with Flash policy support)
- XHR Long Polling
- XHR Multipart Streaming
- Server-Sent Events
-- Plain TCP connections
+- Plain TCP connections (Not yet implemented)
Requirements
-------------
+============
- Tested with Node v0.1.100+
- A client supporting one of the aforementioned transports.
-- For HTTP (not websocket) clients, cookies must be enabled for clients ONLY if they are going to send messages (i.e. via POST) to the server.
+- For HTTP (non-WebSocket) clients, cookies must be enabled for clients ONLY if they are going to send messages (i.e. via POST) to the server.
-Notes
------
+Example
+=======
-Grappler is currently very much a WIP.
+Run example/server.js.
+Visit the example server's test page in your browser: http://serverip:8080/test
+
+API
+===
+
+TODO :-)
View
Binary file not shown.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -1,20 +1,71 @@
-var sys=require('sys'), grappler=require('../lib/grappler');
+var sys = require('sys'),
+ fs = require('fs'),
+ grappler = require('../lib/grappler'),
+ testPage, jsFlashWS, swf, address = "", port = 8080;
-var server = new grappler.Server({
+// Load the demo page
+try {
+ testPage = fs.readFileSync('test.htm');
+} catch (err) {
+ sys.puts('An error occurred while reading \'test.htm\': ' + err);
+ process.exit(1);
+}
+
+// Load the minified javascript needed to add support for Flash WebSockets
+try {
+ jsFlashWS = fs.readFileSync('flashws.js');
+} catch (err) {
+ sys.puts('An error occurred while reading \'flashws.js\': ' + err);
+ process.exit(1);
+}
+
+// Load the Flash WebSocket file itself
+try {
+ swf = fs.readFileSync('WebSocketMain.swf');
+} catch (err) {
+ sys.puts('An error occurred while reading \'WebSocketMain.swf\': ' + err);
+ process.exit(1);
+}
+
+// Create a new instance of a grappler server
+var echoServer = new grappler.Server({
logger: function(msg, level) {
+ if (level == grappler.LOG.INFO)
+ msg = 'INFO: ' + msg;
+ else if (level == grappler.LOG.WARN)
+ msg = 'WARN: ' + msg;
+ else
+ msg = 'ERROR: ' + msg;
sys.debug(msg);
}
-}, function(req, res) {
- if (req.url.indexOf("/favicon.ico") == 0) {
- res.writeHead(404);
- res.end();
- } else if (req.url.indexOf("/site") == 0) {
- res.writeHead(200, { 'Content-Type': 'text/plain' });
- res.end('Handling /site/* from the grappler HTTP handler callback!');
+}, function(req, res) { // HTTP override function that lets us decide to handle requests instead of grappler
+ // Lazily determine the server's reachable IP address and port
+ if (address.length == 0) {
+ address = req.headers.host;
+ testPage = testPage.toString().replace(/__address__/g, address);
+ }
+ switch (req.url) {
+ case "/test":
+ res.writeHead(200, { 'Connection': 'close', 'Content-Type': 'text/html', 'Content-Length': testPage.length });
+ res.end(testPage);
+ break;
+ case "/flashws.js":
+ res.writeHead(200, { 'Connection': 'close', 'Content-Type': 'text/javascript', 'Content-Length': jsFlashWS.length });
+ res.end(jsFlashWS);
+ break;
+ case "/WebSocketMain.swf":
+ res.writeHead(200, { 'Connection': 'close', 'Content-Type': 'application/x-shockwave-flash', 'Content-Length': swf.length });
+ res.end(swf);
+ break;
+ case "/favicon.ico":
+ res.writeHead(404, { 'Connection': 'close' });
+ res.end();
+ break;
}
});
-server.addListener('connection', function(client) {
+// Listen for an incoming connection
+echoServer.addListener('connection', function(client) {
var type;
if (client.state & grappler.STATE.PROTO_WEBSOCKET)
type = "WebSocket";
@@ -24,20 +75,21 @@ server.addListener('connection', function(client) {
type = "TCP";
else
type = "Unknown";
- sys.puts(type + ' client connected from ' + client.socket.remoteAddress);
- client.addListener('data', function(buffer) {
- sys.puts('Received the following from ' + type + ' client @ ' + client.socket.remoteAddress + ': ' + buffer.toString());
+
+ sys.puts(type + ' client connected from ' + client.remoteAddress);
+
+ client.addListener('data', function(buffer, from) {
+ sys.puts('Received the following from client @ ' + from.remoteAddress + ': ' + buffer.toString());
});
- client.addListener('disconnect', function() {
- sys.puts(type + ' client disconnected from ' + client.socket.remoteAddress);
+ client.addListener('close', function() {
+ sys.puts(type + ' client disconnected from ' + client.remoteAddress);
});
- if (type == "HTTP") { // test non-websocket connection (long poll, etc)
- setTimeout(function() {
- client.write('Hello from grappler!');
- client.disconnect();
- }, 5000);
- }
+});
+echoServer.addListener('data', function(buffer, client) {
+ sys.puts('Received the following from client @ ' + client.remoteAddress + ': ' + buffer.toString());
+ // Echo back to the user
+ client.write(buffer);
});
-server.listen(8080);
-sys.puts('Server started.');
+echoServer.listen(port);
+sys.puts('Echo server started on port ' + port + '.');
Oops, something went wrong.

0 comments on commit 4113773

Please sign in to comment.