Friday, August 20, 2010

Ugly Hack to Extend Fab.js Faye

‹prev | My Chain | next›

Tonight, I continue my efforts to ensure that player movement messages in my (fab) game can only come from the faye client that originally added the player to the game. In other words, if I enter the room as player Bob, I should not be able to broadcast to the game that player Fred quit.

The trouble facing me is that the faye server is established inside my custom fab.js app, listen_with_faye (a send-up of the built-into-fabjs listen function):
with ( require( "fab" ) )

( fab )

// Listen on the FAB port and establish the faye server
( listen_with_faye, 0xFAB )

...
If the faye server is completely encapsulated in that function, how can I add an extension to it?

Hmmm.... If I export that faye server from the listen_with_faye (fab) app, that ought to do the trick. I export that (using the commonjs convention) in the fab app:
var _faye_server = new faye.NodeAdapter({
mount: '/faye',
timeout: 45
});

exports.faye_server = _faye_server;
Then, in the my (fab) game backend, I import it:
faye_server = require( "fab/apps/fab.nodejs.listen_with_faye" ).faye_server;

var serverTap = {
incoming: function(message, callback) {
puts("here2");
return callback(message);
}
};

faye_server.addExtension(serverTap);
Nice and easy. Except it does not work—there is no output whatsoever from the backend when faye messages are published. Hmmmm...

What if I add my serverTap extension directly in the (fab) app?
exports.app = function( port ) {
var extension;
port.call( function( obj ){ port = obj.body; } );

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

_faye_server.attach(server);

server.listen(port);

var serverTap = {
incoming: function(message, callback) {
puts("here1");
return callback(message);
}
};
_faye_server.addExtension(serverTap);


return app;
};
};
That works as expected. When faye messages are published, I now see:
here1
here1
here1
here1
here1
After much head scratching, I eventually realize that my import in the backend:
    faye_server = require( "fab/apps/fab.nodejs.listen_with_faye" ).faye_server;
...is pulling in a separate instance of the faye server than is being used to actually connect to the fabjs server.

Ick.

I briefly toy with the idea of fiddling with singletons, but I have no idea if that can work in commonjs land. Besides: singleton.

Instead, I implement a completely different kind of bad hack. Along with the port number, I also allow the faye extension to be supplied in the listen_with_faye app:
exports.app = function( port ) {
var extension;
port.call( function( obj ){
if (typeof obj.body === 'number') {
port = obj.body;
}
else {
port = obj.body.port;
extension = obj.body.extension;
}

} );

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

_faye_server.attach(server);

server.listen(port);

if (extension) addExtension(extension);

return app;
};
};
Bleck. Well, that is a bit much, but it does work. When I start up my server as:
var serverTap = {
incoming: function(message, callback) {
puts("here2");
return callback(message);
}
};


with ( require( "fab" ) )

( fab )

// Listen on the FAB port and establish the faye server
( listen_with_faye, { port: 0xFAB, extension: serverTap } )

...
Moving around a bit, I find that I am finally hitting my serverTap extension:
cstrom@whitefall:~/repos/my_fab_game$ ./game.js
here2
here2
here2
...
At this point, my brain is pretty well fried, so I am hard pressed to come with a better way to accomplish this. If nothing else, the listen_with_faye (fab) app with an object is serviceable. I may leave this as-is for a bit so that I can get on with the business of securing my messages.

But first, sleep.


Day #201

No comments:

Post a Comment