Friday, August 27, 2010

Updating CouchDB from Node.js (It's asynchronous)

‹prev | My Chain | next›

Tonight, I would like to explore hooking up the player store in my (fab) game to CouchDB.

First up, I install node-couchdb (it is in npm as couchdb, not node-couchdb):
cstrom@whitefall:~/repos/my_fab_game$ npm install couchdb
npm it worked if it ends with ok
npm cli [ 'install', 'couchdb' ]
npm version 0.1.26
...

npm activate couchdb@1.0.0
npm build Success: couchdb@1.0.0
npm ok
With that, I can declare CouchDB variables in my (fab) game:
var express = require('express'),
http = require('http'),
faye = require('faye'),
puts = require( "sys" ).puts,
p = require( "sys" ).p,
couchdb = require('node-couchdb/lib/couchdb'),
client = couchdb.createClient(5984, 'localhost'),
db = client.db('my-fab-game');


...
When a player first enters the game room, I need to create a new record in the DB. The saveDoc method ought to do the trick:
  add_player: function(player) {
var new_id = player.id;
if (!this.get(new_id)) {
this._[new_id] = {token: player.authToken};
db.saveDoc(new_id, this._[new_id]);
}
delete(player['authToken']);

this.update_player_status(player);
}
Checking in the DB, I see the record created. Easy enough! Now I would like to be able to update that record as the payer moves around the room.

To accomplish this, I need to pull back the record from the DB, modify the data accordingly, then save it back. The getDoc() and saveDoc() methods sound about right:
  get: function(id) {
db.getDoc(id);
},

update_player_status: function(status) {
var player = this.get(status.id);
p(player);
if (player) {
puts("[update_player_status] " + status.id);
player.status = status;
db.saveDoc(player);
this.idle_watch(status.id);
}
else {
puts("[update_player_status] unknown player: " + status.id + "!");
}
}
But nothing happens. The initial record is created, but not updated. And, I'm seeing that "unknown player" message, so nothing is being returned from the get() method.

Ah! Nothing is getting returned because I have no return statement:
  get: function(id) {
return db.getDoc(id);
}
That should fix it. But of course it does not.

What the hell? Why is getDoc() not returning anything? Even in node-repl, there is nothing.

And then, I actually read the documentation.

The getDoc() method, like all methods that retrieve data in node-couchdb, does not return anything. It expects a callback to which it sends both errors and returned data.

I do not care about errors (if the player is not in the room, the message should be ignored), so I log the occurrence and send the response data onto the requesting function via a callback:
  _get: function(id, callback) {
puts("trying to get: " + id);
db.getDoc(id, function(err, res) {
if (err) {
puts(JSON.stringify(er));
}
callback(res);
});
}
Putting this to use in the update_player_status method requires almost no change to the original, other than wrapping it in a callback for the get method:
  update_player_status: function(status) {
var self = this;
this._get(status.id, function(player) {
p(player);
if (player) {
puts("[update_player_status] " + status.id);
player.status = status;
db.saveDoc(player);
self.idle_watch(status.id);
}
else {
puts("[update_player_status] unknown player: " + status.id + "!");
}
});
}
With that, I can move about the room and the player status is updated in CouchDB:



Nice! That is a fine stopping point for now. Tomorrow I will (hopefully) finish adapting the store to CouchDB with a stretch goal of trying to tap into the changes stream.


Day #208

1 comment:

  1. the 'couchdb' package on npm is no longer maintained and may not work
    try 'cradle'

    ReplyDelete