UNPKG

mongotiles

Version:

mongotiles is a tilelive backend plug-in for MongoDB GridFS

380 lines (344 loc) 11.2 kB
// Generated by CoffeeScript 1.10.0 /* * * Copyright (C) 2013-2016 by Vaughn Iverson * * mongotiles * * With this you can use MongoDB GridFS as a "tilelive.js" source or sink for * map tile / grid / tilejson data. * * See: https://github.com/mapbox/tilelive.js * * This project is free software released under the MIT/X11 license. * See LICENSE file for more information. * */ (function() { var Lock, LockCollection, Tilemongo, default_root, fs, get_mime_type, grid_name, mongodb, path, protocol, querystring, tile_name, tilejson_name, url; path = require('path'); fs = require('fs'); url = require('url'); querystring = require('querystring'); mongodb = require('mongodb'); LockCollection = require('gridfs-locks').LockCollection; Lock = require('gridfs-locks').Lock; protocol = 'mongotiles'; default_root = 'fs'; tile_name = function(z, x, y) { var name; if ((x != null) && (y != null) && (z != null)) { return name = "tile_" + z + "_" + x + "_" + y; } else { return name = 'tile_{z}_{x}_{y}'; } }; grid_name = function(z, x, y) { var name; if ((x != null) && (y != null) && (z != null)) { return name = "grid_" + z + "_" + x + "_" + y; } else { return name = 'grid_{z}_{x}_{y}'; } }; tilejson_name = "tilejson.json"; get_mime_type = function(bytes) { if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4E && bytes[3] === 0x47 && bytes[4] === 0x0D && bytes[5] === 0x0A && bytes[6] === 0x1A && bytes[7] === 0x0A) { return 'image/png'; } else if (bytes[0] === 0xFF && bytes[1] === 0xD8 && bytes[bytes.length - 2] === 0xFF && bytes[bytes.length - 1] === 0xD9) { return 'image/jpeg'; } else if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38 && (bytes[4] === 0x39 || bytes[4] === 0x37) && bytes[5] === 0x61) { return 'image/gif'; } else { console.warn(protocol + ": Image data with unknown MIME type in putTile call to get_mime_type."); return 'application/octet-stream'; } }; Tilemongo = (function() { Tilemongo.prototype._file_exists = function(fn, cb) { return this.files.findOne({ filename: fn }, { _id: 1 }, (function(_this) { return function(err, doc) { return cb(err, doc); }; })(this)); }; Tilemongo.prototype._write_buffer = function(fn, type, buffer, metadata, cb) { var write_it; write_it = (function(_this) { return function(_id, l) { var gs; gs = new mongodb.GridStore(_this.db, _id, fn, 'w', { w: 1, root: _this.grid_root, content_type: type, metadata: metadata }); return gs.open(function(err, gs) { if (err) { return cb(err); } return gs.write(buffer, function(err, gs) { if (err) { return cb(err); } return gs.close(function(err) { if (l) { l.releaseLock(); } return cb(err); }); }); }); }; })(this); return this._file_exists(fn, (function(_this) { return function(err, doc) { var lock; if (err) { return cb(err); } if (!doc) { doc = { _id: new mongodb.ObjectID() }; } if (_this.lockColl) { lock = Lock(doc._id, _this.lockColl, {}).obtainWriteLock(); lock.on('timed-out', function() { return cb(new Error("Timed out waiting for write lock")); }); lock.on('error', function(err) { return cb(err); }); return lock.on('locked', function(ld) { return write_it(doc._id, lock); }); } else { return write_it(doc._id); } }; })(this)); }; Tilemongo.prototype._read_buffer = function(fn, cb) { var read_it; read_it = (function(_this) { return function(_id, l) { var gs; gs = new mongodb.GridStore(_this.db, _id, 'r', { root: _this.grid_root }); return gs.open(function(err, gs) { if (err) { return cb(err); } return gs.read(function(err, buffer) { if (err) { return cb(err); } return gs.close(function(err) { if (l) { l.releaseLock(); } return cb(err, buffer); }); }); }); }; })(this); return this._file_exists(fn, (function(_this) { return function(err, doc) { var lock; if (err) { return cb(err); } if (!doc) { return cb(null, null); } if (_this.lockColl) { lock = Lock(doc._id, _this.lockColl, {}).obtainReadLock(); lock.on('timed-out', function() { return cb(new Error("Timed out waiting for write lock")); }); lock.on('error', function(err) { return cb(err); }); return lock.on('locked', function(ld) { return read_it(doc._id, lock); }); } else { return read_it(doc._id); } }; })(this)); }; Tilemongo.registerProtocols = function(tilelive) { return tilelive.protocols[protocol + ":"] = this; }; Tilemongo.list = function(filepath, callback) { return callback(new Error(".list not implemented for " + protocol)); }; Tilemongo.findID = function(filepath, id, callback) { return callback(new Error(".findID not implemented for " + protocol)); }; function Tilemongo(uri, callback) { var locking, ref, ref1, ref2, tilepath_match; this.starts = 0; if (typeof uri === 'string') { uri = url.parse(uri, true); } if (typeof uri.query === 'string') { uri.query = querystring.parse(uri.query); } if (uri.protocol !== (protocol + ":")) { return callback(new Error("Bad uri protocol '" + uri.protocol + "'. Must be " + protocol + ".")); } tilepath_match = uri.pathname.match(new RegExp("(/[^/]+)(/[^/]+)?")); if (!tilepath_match) { return callback(new Error("Bad tile url path '" + uri.pathname + "' for " + uri.protocol + ".")); } locking = (ref = (ref1 = uri.query) != null ? ref1.locking : void 0) != null ? ref : false; uri.query = ''; uri.search = ''; uri.hash = ''; uri.protocol = 'http:'; this.source = url.format(uri); this.db_name = tilepath_match[1].slice(1); this.grid_root = ((ref2 = tilepath_match[2]) != null ? ref2.slice(1) : void 0) || default_root; uri.path = this.db_name; uri.pathname = uri.path; uri.protocol = 'mongodb:'; this.server = url.format(uri); console.log("Server: " + this.server); mongodb.MongoClient.connect(this.server, (function(_this) { return function(err, db) { if (err) { return callback(err); } _this.db = db; console.log("GRID ROOT " + _this.grid_root); return _this.db.collection(_this.grid_root + ".files", { w: 1 }, function(err, coll) { if (err) { return callback(err); } _this.files = coll; if (!locking) { return callback(null, _this); } else { _this.lockColl = LockCollection(_this.db, { root: _this.grid_root, timeOut: 60, pollingInterval: 5, lockExpiration: 30 }); _this.lockColl.on('ready', function() { return callback(null, _this); }); return _this.lockColl.on('error', function(err) { return callback(err); }); } }); }; })(this)); } Tilemongo.prototype.close = function(callback) { return this.db.close(callback); }; Tilemongo.prototype.getInfo = function(callback) { return this._read_buffer(tilejson_name, (function(_this) { return function(err, info) { if (err) { return callback(err); } return callback(null, JSON.parse(info)); }; })(this)); }; Tilemongo.prototype.getTile = function(z, x, y, callback) { var tn; tn = tile_name(z, x, y); return this._read_buffer(tn, (function(_this) { return function(err, data) { if (err) { return callback(err); } else if (!data) { return callback(new Error('Tile does not exist')); } else { return callback(null, data); } }; })(this)); }; Tilemongo.prototype.getGrid = function(z, x, y, callback) { var gn; gn = grid_name(z, x, y); return this._read_buffer(gn, (function(_this) { return function(err, data) { if (err) { return callback(err); } else if (!data) { return callback(new Error('Grid does not exist')); } else { return callback(null, JSON.parse(data)); } }; })(this)); }; Tilemongo.prototype.startWriting = function(callback) { this.starts += 1; return callback(null); }; Tilemongo.prototype.stopWriting = function(callback) { this.starts -= 1; return callback(null); }; Tilemongo.prototype.putInfo = function(info, callback) { var gn, tn; if (!this.starts) { return callback(new Error("Error, writing not started.")); } tn = tile_name(); info.tiles = ["" + this.source + tn]; if (info.grids != null) { gn = grid_name(); info.grids = ["" + this.source + gn]; } return this._write_buffer(tilejson_name, 'application/json', JSON.stringify(info), null, callback); }; Tilemongo.prototype.putTile = function(z, x, y, tile, callback) { var tn, type; if (!this.starts) { return callback(new Error("Error, writing not started.")); } tn = tile_name(z, x, y); type = get_mime_type(tile); return this._write_buffer(tn, type, tile, { type: "tile", x: x, y: y, z: z }, callback); }; Tilemongo.prototype.putGrid = function(z, x, y, grid, callback) { var gn; if (!this.starts) { return callback(new Error("Error, writing not started.")); } gn = grid_name(z, x, y); return this._write_buffer(gn, 'application/json', JSON.stringify(grid), { type: "grid", x: x, y: y, z: z }, callback); }; return Tilemongo; })(); module.exports = Tilemongo; }).call(this);