Wednesday, April 28, 2010

Sidebar Chain: Chatting with Fab.js

‹prev | My Chain | next›

My kids are obsessed with building an online "game" in which characters move around a screen and interact with others on the screen (mostly chatting). I have no real intention of building a MMORPG for them, but perhaps I can use my current exploration of fab.js to help out the kids.

Ultimately, I will give them a <canvas> element on which they can move their character around and watch others move their characters around (again, no intention of doing this for real, so I will not bother to support Internet Explorer). First up, I need to report location to a fab.js server so that it can broadcast this information to all connected listeners.

As usual, I start with a skeleton fab.js app:
var puts = require( "sys" ).puts;

with ( require( ".." ) )

( fab )

( listen, 0xFAB )

( 404 );
I will take a small step tonight and try to gather and report a single location:
var puts = require( "sys" ).puts;

with ( require( ".." ) )

( fab )

( listen, 0xFAB )

( /^\/location/ )

(
function() {
var out = this;
out({body: "location info here"});
}
)


( 404 );
To actually get the location information, say from query parameters passed into the URL, I need to return a listener to the downstream (fab) app which expects to be passed the header information:
    (
function() {
var out = this;
return function( head ) {
// process header information
var app = out({ body: "location info here" });
if ( app ) app();
};
}
)
Once I send the downstream app the location info, I tell it that I am done by calling it with no arguments. This is all very basic fab.js stuff. But how to process the header information?

The query parameters are easily accessed from the head.url.search property, which then needs a bit of parsing. Thankfully I do not have to roll my own, there is the query string module from node.js:
    (
function() {
var out = this;
return function( head ) {
var search = head.url.search.substring(1);
var q = require('querystring').parse(search);

var app = out({ body: "x: " +q.x });

if ( app ) app();
};
}
)
Accessing that with curl, I get:
curl http://localhost:4011/location?x=1 -i
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked

x: 1
Nice!

I would just as soon reply with JSON. Rather than building my own inside strings, I build a Javascript object then rely on fab.stringify to convert that to text:
    ( stringify )

(
function() {
var out = this;
return function( head ) {
var search = head.url.search.substring(1);
var q = require('querystring').parse(search);

var app = out({ body: {x: q.x } });
if ( app ) app();
};
}
)
Now when I access via curl I get a nice JSON response:
cstrom@whitefall:~/repos/fab$ curl http://localhost:4011/location?x=1 -i
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked

{"x":1}
I finish off by handling the y-coordinate and some defaults:
    ( stringify )

(
function() {
var out = this;
return function( head ) {
var search = head.url.search.substring(1);
var q = require('querystring').parse(search);

var app = out({ body: {x: q.x || 0, y: q.y || 0} });
if ( app ) app();
};
}
)
That will do for tonight. I will move onto broadcasting coordinates tomorrow. Fortunately, the fab.js code includes a very simple broadcast example. Unfortunately for me, this will likely involve me try to figure out what happens when you call() on an array, supplying a function for the execution context:
// from fab/examples/broadcast.js
function broadcast( listeners ) {
listeners.call( function( obj ){ listeners = obj.body } );

Mind: blown.

Day #87

No comments:

Post a Comment