Thursday, May 13, 2010

Refactoring a fab.js unary into a binary

‹prev | My Chain | next›

I still have a few problems in my (fab) game. When new players join the room, they do not see the existing players and when players quit (by closing the browser), they are not removed from room. To resolve this, I am going to need to add a bit more state into my fab.js backend.

I already retain a list of clients listening to comet broadcasts:
  ( /^\/comet_view/ )
( function() {
listeners.push( this );
this({headers: { "content-type": "text/html"},
body: "<html><body>\n"});

// Some padding to get Chrome initialized
} )
Unfortunately, I do not associate those listeners with players (so I can remove them from the player list) or collect the initial locations of those players.

Since comet is being served over an iframe, the request needs to be an HTTP GET. This means that the web client cannot send data in the request body. Thus I am stuck sending any player information in query parameters. To capture that information, I build a unary (fab) app:
function player_from_querystring() {
var out = this;
return function(head) {
if (head.url.search) {
var search = head.url.search.substring(1);
var q = require('querystring').parse(search);
var app = out({ body: {id: q.id, x: q.x || 0, y: q.y || 0} });
if ( app ) app();
}
else {
out();
}
};
}
This is a quick adaptation of some query string parsing I did when I was first learning fab.js.

Since this is fab.js and I have collected this in a unary app (upstream / farthest from the web client), I need to convert my comet function to middleware (or a binary app in fab.js speak). I am getting pretty good at doing this now. I just need to wrap the comet (fab) app above with a function that takes a single argument—the upstream app, player_from_query_string. To make the flow a bit clearer, I break the comet view into a named function:
function init_comet (app) {
return function () {
var out = this;

return app.call( function listener(obj) {
if (obj && obj.body) {
players.push(out);
out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })
// More code here to initialize comet in Chrome
}
return listener;
});
};
}
With that, the main flow of my (fab) game becomes quite readable:
  ( /^\/comet_view/ )
( init_comet )
( player_from_querystring )
At this point, I have changed no functionality in the game. Everything still responds like it did before—bugs and all. But tomorrow, I will be able to user the obj.body in comet_view(), which is being built from the iframe's query string in player_from_querystring, to build a list of players, their positions in the room and the associated clients.

(commit)

Day #102

No comments:

Post a Comment