From 14fc28896ecdd4d1636bf197409e83409903f2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 21 Jul 2011 23:12:10 +0200 Subject: [PATCH] move to tilelive 4 --- index.js | 5 ++ models/Datasource.server.bones | 87 +++++++++++++++++++--------------- models/Project.bones | 3 +- package.json | 7 +-- servers/App.bones | 3 +- servers/Tile.bones | 72 ++++++++++++++++++---------- 6 files changed, 108 insertions(+), 69 deletions(-) diff --git a/index.js b/index.js index e777f1976..c19074475 100755 --- a/index.js +++ b/index.js @@ -1,4 +1,9 @@ #!/usr/bin/env node process.title = 'tilemill'; + + +var tilelive_mapnik = require('tilelive-mapnik'); +tilelive_mapnik.registerProtocols(require('tilelive')); + require('bones').load(__dirname); !module.parent && require('bones').start(); diff --git a/models/Datasource.server.bones b/models/Datasource.server.bones index 843f554e1..df8874c52 100644 --- a/models/Datasource.server.bones +++ b/models/Datasource.server.bones @@ -1,7 +1,7 @@ var path = require('path'); +var url = require('url'); var fs = require('fs'); -var mapnik = require('tilelive-mapnik/node_modules/mapnik'); -var Map = require('tilelive-mapnik').Map; +var tilelive = require('tilelive'); var Step = require('step'); // @TODO this is rather messy atm - it caches the datasource to @@ -25,53 +25,66 @@ models.Datasource.prototype.sync = function(method, model, success, error) { Layer: [{ name: options.id, Datasource: _({ - file: options.url, + file: options.file, type: options.ds_type }).extend(options), srs: SRS }] }; - var env = { - data_dir: path.join(config.files, 'project', options.project), - local_data_dir: path.join(config.files, 'project', options.project) + + // We abuse tilelive-mapnik and use a faked MML object to localize data + // into the project directory. + var id = options.project; + var uri = { + protocol: 'mapnik:', + slashes: true, + pathname: path.join(config.files, 'project', id, id + '.mml'), + query: { + // Note: data_file is only used to force a different cache key. + data_file: options.file, + data_dir: path.join(config.files, 'project', options.project), + local_data_dir: path.join(config.files, 'project', options.project) + }, + data: mml }; - var map = new Map(mml, env); - var datasource; - Step(function() { - map.initialize(this); - }, - function(err) { + tilelive.load(uri, function(err, source) { if (err) return error(err); - var ds = map.mapnik.describe_data()[options.id]; - datasource = { - id: options.id, - project: options.project, - url: options.url, - fields: ds.fields, - features: options.features ? map.mapnik.features(0, 1000) : [], - type: ds.type, - geometry_type: ds.type === 'raster' ? 'raster' : ds.geometry_type - }; + // @TODO: We're accessing the internals of tilelive-mapnik. + // This may or may not be a good idea. + source._pool.acquire(function(err, map) { + if (err) return error(err); - // Process fields and calculate min/max values. - for (var f in datasource.fields) { - datasource.fields[f] = { - type: datasource.fields[f], - max: _(datasource.features).chain().pluck(f) - .max(function(v) { - return _(v).isString() ? v.length : v; - }).value(), - min: _(datasource.features).chain().pluck(f) - .min(function(v) { - return _(v).isString() ? v.length : v; - }).value() + var ds = map.describe_data()[options.id]; + var datasource = { + id: options.id, + project: options.project, + url: options.file, + fields: ds.fields, + features: options.features ? map.features(0, 1000) : [], + type: ds.type, + geometry_type: ds.type === 'raster' ? 'raster' : ds.geometry_type }; - } - map.destroy(); - success(datasource); + // Process fields and calculate min/max values. + for (var f in datasource.fields) { + datasource.fields[f] = { + type: datasource.fields[f], + max: _(datasource.features).chain().pluck(f) + .max(function(v) { + return _(v).isString() ? v.length : v; + }).value(), + min: _(datasource.features).chain().pluck(f) + .min(function(v) { + return _(v).isString() ? v.length : v; + }).value() + }; + } + + source._pool.release(map); + success(datasource); + }); }); }; diff --git a/models/Project.bones b/models/Project.bones index 3cc0af1db..8dd5e052e 100644 --- a/models/Project.bones +++ b/models/Project.bones @@ -188,8 +188,7 @@ model = Backbone.Model.extend({ if (!Bones.server) return options.success(this, null); var carto = require('carto'), - // var carto = require('tilelive-mapnik/node_modules/carto'), - mapnik = require('tilelive-mapnik/node_modules/mapnik'), + mapnik = require('mapnik'), stylesheets = this.get('Stylesheet'), env = { returnErrors: true, diff --git a/package.json b/package.json index 87c2b694f..e161036f9 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,13 @@ "bones": "1.3.x", "chrono": "~1.0.1", "JSV": "3.5.x", - "mbtiles": "0.0.x", + "mbtiles": "~0.1.1", "sax": "0.1.x", "request": "1.9.x", "step": "0.0.x", - "tilelive": "~ 3.0.3", - "tilelive-mapnik": "~ 0.0.6", + "tilelive": "4.0.x", + "mapnik": "0.4.x", + "tilelive-mapnik": "https://github.com/mapbox/tilelive-mapnik/tarball/tilelive-refactoring", "underscore": "1.1.x", "carto": "https://github.com/mapbox/carto/tarball/b84f22830336235aaf6fdaf64fb963a6f6a087b4", "wax": "https://github.com/mapbox/wax/tarball/abf06066575c63b84f952e658956d49ab8644d2a" diff --git a/servers/App.bones b/servers/App.bones index ef3faed75..ce7a1e640 100644 --- a/servers/App.bones +++ b/servers/App.bones @@ -1,10 +1,9 @@ -var mapnik = require('tilelive-mapnik/node_modules/mapnik'); +var mapnik = require('mapnik'); var path = require('path'); var env = process.env.NODE_ENV || 'development'; var abilities = { carto: require('carto').tree.Reference.data, - // carto: require('tilelive-mapnik/node_modules/carto').tree.Reference.data, fonts: mapnik.fonts(), datasources: mapnik.datasources(), exports: { diff --git a/servers/Tile.bones b/servers/Tile.bones index b7797c702..b71c0ed3f 100644 --- a/servers/Tile.bones +++ b/servers/Tile.bones @@ -1,47 +1,69 @@ var path = require('path'), - tilelive = new (require('tilelive').Server)(require('tilelive-mapnik')), + tilelive = require('tilelive'), settings = Bones.plugin.config; server = Bones.Server.extend({}); server.prototype.initialize = function() { - _.bindAll(this, 'load', 'layer', 'tile'); - this.get('/1.0.0/:id/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.tile); - this.get('/1.0.0/:id/:z/:x/:y.:format(grid.json)', this.load, this.tile); + _.bindAll(this, 'load', 'grid', 'layer', 'getArtifact'); + this.get('/1.0.0/:id/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.load, this.getArtifact); + this.get('/1.0.0/:id/:z/:x/:y.:format(grid.json)', this.load, this.grid, this.getArtifact); this.get('/1.0.0/:id/layer.json', this.load, this.layer); }; server.prototype.load = function(req, res, next) { res.project = new models.Project({id: req.param('id')}); res.project.fetch({ - success: function(model, resp) { next(); }, - error: function(model, resp) { next(resp); } + success: function(model, resp) { + res.projectMML = resp; + next(); + }, + error: function(model, resp) { + next(resp); + } }); }; -server.prototype.tile = function(req, res, next) { - req.params.datasource = path.join( - settings.files, - 'project', - req.param('id'), - req.param('id') + '.mml' - ); - if (req.params.format === 'grid.json' && res.project) { - if (!res.project.get('interactivity')) - return next(new Error.HTTP('Not found.', 404)); - - var interactivity = res.project.get('interactivity'); - req.params.layer = interactivity.layer; - req.params.fields = models.Project.fields(interactivity); - req.query.callback = 'grid'; // Force jsonp. - } - tilelive.serve(req.params, function(err, data) { +server.prototype.getArtifact = function(req, res, next) { + // This is the cache key in tilelive-mapnik, so make sure it + // contains the mtime with _updated. + var id = req.params.id; + var uri = { + protocol: 'mapnik:', + slashes: true, + pathname: path.join(settings.files, 'project', id, id + '.mml'), + search: '_updated=' + res.projectMML._updated, + data: res.projectMML + }; + + tilelive.load(uri, function(err, source) { if (err) return next(err); - data[1]['max-age'] = 3600; - res.send.apply(res, data); + + var z = req.params.z, x = +req.params.x, y = +req.params.y; + + // The interface is still TMS. + y = (1 << z) - 1 - y; + + var fn = req.params.format === 'grid.json' ? 'getGrid' : 'getTile'; + source[fn](z, x, y, function(err, tile, headers) { + if (err) return next(err); + headers['max-age'] = 3600; + res.send(tile, headers); + }); }); }; +server.prototype.grid = function(req, res, next) { + // Early exit. tilelive-mapnik would catch that too. + if (!res.project.get('interactivity')) { + return next(new Error.HTTP('Not found.', 404)); + } + + // Force jsonp. + req.query.callback = 'grid'; + next(); +}; + server.prototype.layer = function(req, res, next) { if (!res.project.get('formatter') && !res.project.get('legend')) { next(new Error.HTTP('Not found.', 404));