While messing about with my (fab) game today, I notice that the chat system is completely broken. Sigh.
By completely broken, when I POST a chat message, I get an "empty" response from the fab.js backend:
cstrom@whitefall:~/repos/my_fab_game$ curl http://localhost:4011/chat -i -d '{"id":"foo", "say":"hi"}'
curl: (52) Empty reply from serverLooking at the backend, I find that it has crashed completely:...Like I said...
cstrom@whitefall:~/repos/my_fab_game$ ./game.js
/home/cstrom/repos/my_fab_game/game.js:34
broadcast(comet_player_say(obj.body.substr(0,100)));
^
TypeError: Object {"id":"foo", "say":"hi"} has no method 'substr'
at listener (/home/cstrom/repos/my_fab_game/game.js:34:49)
at IncomingMessage.<anonymous> (/home/cstrom/.node_libraries/fab/apps/fab.nodejs.js:29:36)
at IncomingMessage.emit (events:25:26)
at HTTPParser.onBody (http:98:23)
at Stream.ondata (http:745:22)
at IOWatcher.callback (net:373:31)
at node.js:204:9
Sigh.
I added the
substr to limit the chat message to 100 characters, but didn't notice that that the body of the message was a JSON string rather than the chat message itself. Since it is a JSON string, I need to parse the JSON into a Javascript object, limit the chat message in that object to 100 characters, then re-stringify it to be broadcast to the game:( /chat/ )Sadly, when I restart and POST to the chat resource, I still get an empty resource:
( function() {
var out = this;
return function listener( obj ) {
if ( !obj ) out();
else if ( obj.body ) {
var msg = JSON.parse(obj.body);
msg.body = msg.say.substr(0,100);
broadcast(comet_player_say(JSON.stringify(msg)));
}
return listener;
};
} )
cstrom@whitefall:~/repos/my_fab_game$ curl http://localhost:4011/chat -i -d '{"id":"foo", "say":"hi"}'
curl: (52) Empty reply from serverThe backend is still crashing, this time with a different message:cstrom@whitefall:~/repos/my_fab_game$ ./game.jsHunh? I am not even sure what that means there is not even an error message. Let's have a look at the
/home/cstrom/repos/my_fab_game/game.js:34
var msg = JSON.parse(obj.body);
^
obj.body just before it crashes://...After I crash the server, I find this in the output:
else if ( obj.body ) {
for (var prop in obj.body) {
puts(prop + ": " + obj.body[prop]);
}
var msg = JSON.parse(obj.body);
msg.body = msg.say.substr(0,100);
broadcast(comet_player_say(JSON.stringify(msg)));
}
//...
cstrom@whitefall:~/repos/my_fab_game$ ./game.jsOh man! That is a Javascript
0: 123
1: 34
2: 105
3: 100
4: 34
...
22: 34
23: 125
length: 24
binarySlice: function binarySlice() { [native code] }
asciiSlice: function asciiSlice() { [native code] }
...
toString: function (encoding, start, stop) {
encoding = (encoding || 'utf8').toLowerCase();
...
String object, not a string literal. Happily, there is a toString() method in that list of properties. I can use that to resolve the problem:( /chat/ )Indeed that does resolve the problem. I now have my chat system working again.
( function() {
var out = this;
return function listener( obj ) {
if ( !obj ) out();
else if ( obj.body ) {
var msg = JSON.parse(obj.body.toString());
msg.body = msg.say.substr(0,100);
broadcast(comet_player_say(JSON.stringify(msg)));
}
return listener;
};
} )
That Javascript
String object has me a bit worried, though. I know that the fab.js source uses typeof obj == "string" checks in places. Those will fail for String objects (typeof would return "object").To test this out, I convert the fab app upstream of the chat resource into a binary app. Then, I can delegate the responsibility of converting the supplied JSON string into a JSON object to the built-in
fab.parse app:( /chat/ )When I access the chat resource now, I get an error similar to the unary version of the chat fab app:
(
function(app) {
return function() {
var out = this;
return app.call( function listener( obj ) {
if ( !obj ) out();
else if ( obj.body ) {
var msg = {
id: obj.body.id,
say: obj.body.say.substr(0,100)
};
broadcast(comet_player_say(JSON.stringify(msg)));
}
return listener;
});
};
} )
(fab.parse)
(fab.echo)
cstrom@whitefall:~/repos/my_fab_game$ ./game.jsIf I alter the
/home/cstrom/repos/my_fab_game/game.js:38
say: obj.body.say.substr(0,100)
^
TypeError: Cannot call method 'substr' of undefined
at listener (/home/cstrom/repos/my_fab_game/game.js:38:35)
at listener (/home/cstrom/.node_libraries/fab/apps/fab.map.js:11:19)
at IncomingMessage.<anonymous> (/home/cstrom/.node_libraries/fab/apps/fab.nodejs.js:29:36)
at IncomingMessage.emit (events:25:26)
at HTTPParser.onBody (http:98:23)
at Stream.ondata (http:745:22)
at IOWatcher.callback (net:373:31)
at node.js:204:9
fab.parse.js app from:exports.app = fab.map( function( obj ) {
var body = obj.body;
if ( typeof body == "string" ) obj.body = JSON.parse( body );
return obj;
})To make use of toString() (which works on string literals and String objects):exports.app = fab.map( function( obj ) {
var body = obj.body;
if ( body && body.toString ) obj.body = JSON.parse( body.toString() );
return obj;
})Then my chat server works again.I suspect that recent node.js changes have started sending
String objects and string literals interchangeably. I will investigate a bit more tomorrow then address the issue in the remaining built-in fab apps.Day #128
No comments:
Post a Comment