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"}'Looking at the backend, I find that it has crashed completely:
curl: (52) Empty reply from server
...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"}'The backend is still crashing, this time with a different message:
curl: (52) Empty reply from server
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 ) {To make use of
var body = obj.body;
if ( typeof body == "string" ) obj.body = JSON.parse( body );
return obj;
})
toString()
(which works on string literals and String
objects):exports.app = fab.map( function( obj ) {Then my chat server works again.
var body = obj.body;
if ( body && body.toString ) obj.body = JSON.parse( body.toString() );
return obj;
})
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