Thursday, July 29, 2010

Fab Faye

‹prev | My Chain | next›

Communication from server to client in my (fab) game has been done, so far, over comet. Comet is really easy to do in fab.js, so it was a natural approach to take.

I am interested today in seeing if faye might be a better solution in some respects. The documentation says that faye is installable via npm, but when I try a simple install, I get:
cstrom@whitefall:~/repos/faye_test$ npm install faye
The "ini" module will be removed in future versions of Node, please extract it into your own code.
npm configfile /home/cstrom/.npmrc
npm sudo false
npm cli [ 'install', 'faye' ]
npm install pkg faye
npm fetch data faye
npm GET faye
npm install pkg faye

npm ! Error: Tag stable not found for package faye
at F (/home/cstrom/.node_libraries/.npm/npm/0.1.13/package/lib/install.js:136:19)
at /home/cstrom/.node_libraries/.npm/npm/0.1.13/package/lib/install.js:128:16
at IncomingMessage.<anonymous> (/home/cstrom/.node_libraries/.npm/npm/0.1.13/package/lib/utils/registry.js:149:7)
at IncomingMessage.emit (events:42:20)
at HTTPParser.onMessageComplete (http:110:23)
at Client.ondata (http:859:22)
at IOWatcher.callback (net:373:31)
at node.js:204:9

npm failure try running: 'npm help install'
npm failure Report this *entire* log at <http://github.com/isaacs/npm/issues>
npm failure or email it to <npm-@googlegroups.com>
Hmmm... It has been a while since I installed npm, so it could be an old version. Before installing a new version, though, I wonder if it is possible to install with an explicit version:
cstrom@whitefall:~/repos/faye_test$ npm install faye@0.5.1
The "ini" module will be removed in future versions of Node, please extract it into your own code.
npm configfile /home/cstrom/.npmrc
npm sudo false
npm cli [ 'install', 'faye@0.5.1' ]
npm install pkg faye@0.5.1
npm readJson /home/cstrom/.node_libraries/.npm/.cache/faye/0.5.1/package.json
npm GET faye/0.5.1
...
npm build Success: faye-0.5.1
npm ok
Cool. I will worry about npm versions another day, for now, I have faye installed.

Next up is trying to get faye working with fab.js. Since fab.js is built on top of node.js, I reckon it ought to easy to hack it in there. I reckon wrong.

After fiddling with paths for way too long, I give up and create a fab.nodejs.listen_with_faye (fab) app into fab itself. I base it on the built-in (fab) app fab.nodejs.listen, with a few tweaks added for faye:
exports.name      = "fab.nodejs.listen_with_faye";
exports.summary = "Starts a server listening on the port number from the first app, and mounts the second app on it.";
exports.requires = [ "fab.nodejs" ];

var fab = { nodejs: require( "./fab.nodejs" ).app };

var faye = require('faye');

exports.app = function( port ) {
port.call( function( obj ){ port = obj.body; } );

return function( app ) {
var server = require( "http" )
.createServer( fab.nodejs( app ) );

var bayeux = new faye.NodeAdapter({
mount: '/faye',
timeout: 45
});


bayeux.attach(server);

server.listen(port);

return app;
};
};
With that, I can write my standard (fab) skeleton that serves up CSS, Javascript, and static HTML from the stylesheets, javascript, and html directories, respectively:
#!/usr/bin/env node

var puts = require( "sys" ).puts;

with ( require( "fab" ) )

( fab )

( listen_with_faye, 0xFAB )

(/^\/(javascript|stylesheets)/)
(/^\/([-_\w]+)\.(js|css)$/)
(fab.nodejs.fs)
( fab.tmpl, "<%= this[0] %>/<%= this[1] %>.<%= this[2] %>" )
( fab.capture )
(404)

(/^\/([_\w]+)$/)
(fab.nodejs.fs)
( fab.tmpl, "html/<%= this %>.html" )
( fab.capture.at, 0 )

( 404 );
The only change that I make to my standard skeleton is the addition of the listen_with_faye call instead of the vanilla listen.

With that, I am ready to try out my service. First, from the node-repl command line, I subscribe to the "/foo" channel for updates:
cstrom@whitefall:~/repos/faye_test$ rlwrap node-repl
Welcome to the Node.js REPL.
Enter ECMAScript at the prompt.
Tip 1: Use 'rlwrap node-repl' for a better interface
Tip 2: Type Control-D to exit.
Type '.help' for options.
node> var faye = require('faye');
node> var client = new faye.Client('http://localhost:4011/faye');
node> var puts = require( "sys" ).puts;
node> client.subscribe('/foo', function(message) {puts(message)});
...
Then, in a separate node-repl session, I publish a message on that same channel:
node> cstrom@whitefall:~/repos/faye_test$ rlwrap node-repl
Welcome to the Node.js REPL.
Enter ECMAScript at the prompt.
Tip 1: Use 'rlwrap node-repl' for a better interface
Tip 2: Type Control-D to exit.
Type '.help' for options.
node> var faye = require('faye');
node> var client = new faye.Client('http://localhost:4011/faye');
node> client.publish('/foo', "boo");
And, back in my original node-repl, I see the message come through:
node> boo

Yay!

The last thing I try before calling it a night is this in a browser. All I want is the message to appear in the console:
<html>
<head>
<title>Testing Faye/Fab</title>
<script type="text/javascript" src="http://localhost:4011/faye.js"></script>
<script type="text/javascript">
var client = new Faye.Client('http://localhost:4011/faye');
client.subscribe('/foo', function(message) {console.debug(message)});

</script></head>

<body>
<h1>Testing Faye/Fab</h1>

</body>
</html>
What I find is that this works in Firefox, but not in Chrome (no errors, but the callback does not fire). There is no mention of browser compatibility on the faye site, so I am not sure of the cause. I will pick back up tomorrow.


Day #179

4 comments:

  1. This one works fine in Chrome 6.0.472.11 (Mac OS X): http://soderlind.no/archives/2010/06/30/node-js/

    ReplyDelete
  2. I'm running 6.0.472.11 on linux. My next step was going to be to write a pure nodejs / event machine server to see if that somehow made the problem go away. Now I don't have to -- I'll just use the client / server from that link :)

    Thanks!

    ReplyDelete
  3. Dang. I couldn't find the connect script (it wasn't installed via npm install connect) mentioned in that link.

    ReplyDelete
  4. connect has moved (extjs -> senchalabs name change): http://github.com/senchalabs/connect

    ReplyDelete