Up today, a quick refactoring that has been a long time coming in the fab.js backend of my (fab) game:
// TODO: test and/or shrinkThe reason that this function is so long is that it is doing two things: adding players to a local store and broadcasting existing players to the new game player. So I break out the local store into a second (fab) app:
function broadcast_new (app) {
return function () {
var out = this;
return app.call( function listener(obj) {
if (obj && obj.body && obj.body.id) {
for (var id in players) {
out({body: comet_new_player(JSON.stringify(players[id].status))});
}
var new_id = obj.body.id;
if (!players[new_id]) {
puts("[broadcast_new] adding: " + new_id);
add_player(obj.body, out);
idle_watch(new_id);
setTimeout(function(){keepalive(new_id);}, 30*1000);
}
else if (players[new_id].uniq_id == obj.body.uniq_id) {
puts("[broadcast_new] refreshing session: " + new_id);
add_player(obj.body, out);
}
else {
out();
}
}
else {
out(obj);
}
return listener;
});
};
}
( /^\/comet_view/ )I define
( broadcast_new )
( store_player )
( init_comet )
( player_from_querystring )
store_player
as:function store_player (app) {Reading along, if there is a body (a player from the upstream app
return function () {
var out = this;
return app.call( function listener(obj) {
if (obj && obj.body && obj.body.id) {
var new_id = obj.body.id;
if (!players[new_id]) {
puts("[store_player] adding: " + new_id);
add_player(obj.body, out);
idle_watch(new_id);
setTimeout(function(){keepalive(new_id);}, 30*1000);
}
else if (players[new_id].uniq_id == obj.body.uniq_id) {
puts("[store_player] refreshing session: " + new_id);
add_player(obj.body, out);
}
else {
out();
}
}
out(obj);
return listener;
});
};
}
player_from_query_string
), then we check to see if the player is already playing. If no, then add the player to a local store. If the player is already in the local store, then refresh the session—as long as the player is not impersonating someone else (as evidenced by the uniq_id
). If the player is not new, and is attempting to impersonate someone else, terminate the connection immediately by calling the downstream out()
with no arguments.Finally, if there is no player id in the body, then send the output directly downstream. This allows the
init_comet
middleware to send comet initialization back to the browser.That could be simpler, but it is much better that what I had before—this and code trying to broadcast the whereabouts of existing game players to new player. Speaking of that bit of functionality, it is now much simpler:
function broadcast_new (app) {Similar to
return function () {
var out = this;
return app.call( function listener(obj) {
if (obj && obj.body && obj.body.id) {
for (var id in players) {
out({body: comet_new_player(JSON.stringify(players[id].status))});
}
}
else {
out(obj);
}
return listener;
});
};
}
store_player
, I send the upstream data back downstream to the browser (via out(obj)
), unless there is a new player ID in the body (again, this would be set by player_from_querystring
). In that case, I walk through each player in the local store and send back downstream the current status of each player.I am duplicating the logic of performing an action when player data is present in these two (fab) apps. Tomorrow I really ought to DRY that up.
Day #150