Saturday, August 28, 2010

More Callbacks with node-couchdb

‹prev | My Chain | next›

Yesterday, I was able to get player updates in my (fab) game stored in a CouchDB backend thanks to node-couchdb. Today, I hope to move the entire store over to CouchDB.

First up, I need to be able to drop players:
  drop_player: function(id) {
Logger.info("players.drop_player " + id);
this.faye.publish("/players/drop", id);

this.get(id, function(player) {
Logger.debug("[players.drop_player] " + inspect(player));
if (player) db.removeDoc(id, player._rev);
});

}
To delete in CouchDB, I need the current revision of the document. I use the get() method from last night to grab the current document, then remove it immediately. I could keep the revision ID in the local store to get around the lookup/then delete. I will worry about doing that when this proves to be a bottleneck.

Up next, I need to rework the idle timeout code a bit. I had been storing the idle timeout directly on the player objects in the local store (this._):
  idle_watch: function(id) {
if (this._[id].idle_timeout) {
clearTimeout(this._[id]].idle_timeout);
}

var self = this;
this._[id].idle_timeout = setTimeout(function() {
Logger.info("timeout " + id +"!");
self.drop_player(id);
}, 30*60*1000);


this._[id].idle_watch_started = "" + (new Date());
}
Since I am no longer storing data locally, I need to create a new local store for these timeouts. Easy enough:
  timeouts: { },

idle_watch: function(id) {
if (this.timeouts[id])
clearTimeout(this.timeouts[id]);

var self = this;
this.timeouts[id] = setTimeout(function() {
Logger.info("timeout " + id +"!");
self.drop_player(id);
}, 30*60*1000);

}
The timeouts are now stored in the timeouts attribute in my players object, which leaves very little still relying on the old local store. After replacing a couple more individual gets from the local store, I am left with only one more local store reference—a lookup of all players in a faye subscription:
     this.faye.subscribe("/players/query", function(q) {
var ret = [];
for (var id in self._) {
ret.push(self._[id].status);
}

self.faye.publish("/players/all", ret);
});
As with everything else in node-couchdb, a lookup of all documents in CouchDB is done via callback:
  all: function(callback) {
return db.allDocs({include_docs:true}, function(err, docs) {
callback(docs.rows.map(function(row) {return row.doc;}));
});
}
I use {include_docs:true} to pull back the player documents rather than just the meta data that is normally returned. Similarly, I map those results to return just the player documents (no meta data). With that, I need to convert the faye subscription to use the callback:
  all: function(callback) {
return db.allDocs({include_docs:true}, function(err, docs) {
callback(docs.rows.map(function(row) {return row.doc;}));
});
}
And finally, I can remove the local store entirely. I am still storing timeouts locally, but that is a code timeout, so there is really no choice in the matter. Now that I think about it, I ought to be able to save the timeout time in the CouchDB store. If I do that, I could restore the software timeout after a server restart. I will pick back up with that tomorrow.


Day #209

No comments:

Post a Comment