diff --git a/lib/directoryindex.js b/lib/directoryindex.js new file mode 100644 index 0000000..131432a --- /dev/null +++ b/lib/directoryindex.js @@ -0,0 +1,68 @@ +var _ = require('underscore'); +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var EventEmitter = require('events').EventEmitter; + +module.exports = DirectoryIndex; +util.inherits(DirectoryIndex, EventEmitter) +function DirectoryIndex(dir) { + this.filepath = dir; + + // Initialize and continually update the directory index. + this.update = _(this.update).bind(this); + process.nextTick(this.update) + fs.watchFile(dir, this.update); +} + +DirectoryIndex.prototype.getList = function(callback) { + if (!this.list) this.once('updated', done); + else done.call(this); + + function done() { + if (this.err) callback(this.err); + else callback(null, this.list); + } +}; + +DirectoryIndex.prototype.getID = function(id, callback) { + if (!this.list) this.once('updated', done); + else done.call(this); + + function done() { + if (this.err) callback(this.err); + else if (!this.list[id]) callback(new Error('Tileset not found')); + else callback(null, this.list[id]); + } +} + +DirectoryIndex.prototype.update = function() { + var index = this; + fs.readdir(index.filepath, function(err, files) { + index.err = err; + if (!err) { + for (var result = index.list = {}, i = 0; i < files.length; i++) { + var name = files[i].match(/^([\w-]+)\.mbtiles$/); + if (name) { + result[name[1]] = 'mbtiles://' + path.join(index.filepath, name[0]); + } + } + index.list = result; + } + index.emit('updated'); + }); +}; + +var cache = DirectoryIndex.cache = {}; +DirectoryIndex.create = function(filepath) { + if (!cache[filepath]) { + var oldpath = filepath; + filepath = path.resolve(filepath); + if (!cache[filepath]) { + cache[filepath] = new DirectoryIndex(filepath); + } + // Avoid path.resolve() calls. + cache[oldpath] = cache[filepath]; + } + return cache[filepath]; +}; diff --git a/lib/mbtiles.js b/lib/mbtiles.js index 8dfdcc9..2db214b 100644 --- a/lib/mbtiles.js +++ b/lib/mbtiles.js @@ -10,6 +10,9 @@ var _ = require('underscore'), sm = new (require('sphericalmercator')), sqlite3 = require('sqlite3'); +var DirectoryIndex = require('./directoryindex'); + + if (process.env.NODE_ENV === 'test') sqlite3.verbose(); function noop(err) { @@ -109,26 +112,13 @@ MBTiles.registerProtocols = function(tilelive) { // Finds all mbtiles file in the filepath and returns their tilesource URI. MBTiles.list = function(filepath, callback) { - filepath = path.resolve(filepath); - fs.readdir(filepath, function(err, files) { - if (err) return callback(err); - for (var result = {}, i = 0; i < files.length; i++) { - var name = files[i].match(/^([\w-]+)\.mbtiles$/); - if (name) result[name[1]] = 'mbtiles://' + path.join(filepath, name[0]); - } - return callback(null, result); - }); + DirectoryIndex.create(filepath).getList(callback); }; // Finds an mbtiles file with the given ID in the filepath and returns a // tilesource URI. MBTiles.findID = function(filepath, id, callback) { - filepath = path.resolve(filepath); - var file = path.join(filepath, id + '.mbtiles'); - fs.stat(file, function(err, stats) { - if (err) return callback(err); - else return callback(null, 'mbtiles://' + file); - }); + DirectoryIndex.create(filepath).getID(id, callback); }; // Retrieve the schema of the current mbtiles database and inform the caller of