From 363a1933cfc744e28b16b61464c428b831cad93f Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Sat, 31 Oct 2015 15:25:55 -0400 Subject: [PATCH 1/8] Sketch of generating zxy streams from S3 sources. --- lib/index.js | 8 +++++++ lib/zxystream.js | 52 ++++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ test/zxystream.test.js | 44 +++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 lib/zxystream.js create mode 100644 test/zxystream.test.js diff --git a/lib/index.js b/lib/index.js index eaf4142..b2d9ac2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -576,3 +576,11 @@ S3.prototype.getIndexableDocs = function(pointer, callback) { callback(null, docs, pointer); }); }; + +// Create a readable ZXY list stream. +S3.prototype.createZXYStream = function(options) { + if (!this.data) return callback(new Error('Tilesource not loaded')); + if (!this.data.tiles) return callback(new Error('No "tiles" key')); + return new ZXYStream(this.data.tiles[0], options); +}; + diff --git a/lib/zxystream.js b/lib/zxystream.js new file mode 100644 index 0000000..708477c --- /dev/null +++ b/lib/zxystream.js @@ -0,0 +1,52 @@ +var util = require('util'); +var split = require('split'); +var s3scan = require('s3scan'); +var s3urls = require('s3urls'); +var StreamConcat = require('stream-concat'); + +module.exports = ZXYStream; +module.exports.config = config; + +function ZXYStream(tilesUrl) { + var conf = config(tilesUrl); + var current = 0; + return new StreamConcat(function() { + if (!conf.toList[current]) return null; + return s3scan.List(conf.toList[current++], {}) + }).pipe(split(function(line) { + var matches = line.match(conf.tokenPattern); + if (!matches || matches.length < 4) return undefined; + return matches[conf.tokenMap[0]] + '/' + + matches[conf.tokenMap[1]] + '/' + + matches[conf.tokenMap[2]]; + })); +} + +function config(tilesUrl) { + var conf = {}; + conf.toList = []; + if ((/{prefix}/).test(tilesUrl)) { + conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0]); + } else { + conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0]); + } + + var matches = s3urls.fromUrl(tilesUrl).Key.match(/{(z|x|y)}/g); + if (matches.length !== 3) throw new Error('Could not find {z}, {x} and {y} tokens in url: ' + tilesUrl); + + conf.tokenMap = matches.reduce(function(memo, token, i) { + if (token === '{z}') { + memo[i] = 1; + } else if (token === '{x}') { + memo[i] = 2; + } else if (token === '{y}') { + memo[i] = 3; + } + return memo; + }, []); + + conf.tokenPattern = new RegExp(s3urls.fromUrl(tilesUrl).Key.replace(/{(z|x|y)}/g, '([0-9]+)')); + + return conf; +} + diff --git a/package.json b/package.json index fc81cab..d581ef0 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "aws-sdk": "^2.1.44", "nan": "^1.8.4", "node-pre-gyp": "~0.6.7", + "s3scan": "0.1.0", "s3urls": "^1.3.0", + "stream-concat": "0.1.0", "tiletype": "0.1.x" }, "bundledDependencies": [ diff --git a/test/zxystream.test.js b/test/zxystream.test.js new file mode 100644 index 0000000..977c70a --- /dev/null +++ b/test/zxystream.test.js @@ -0,0 +1,44 @@ +var AWS = require('aws-sdk'); +var awss3 = new AWS.S3(); +var fs = require('fs'); +var tape = require('tape'); +var ZXYStream = require('../lib/zxystream'); + +[ '0/0/0', '1/0/0', '1/0/1', '1/1/0', '1/1/1' ].forEach(function(zxy) { + tape('setup tile ' + zxy, function(assert) { + var png = fs.readFileSync(__dirname + '/fixtures/tile.png'); + awss3.putObject({ + Bucket: 'mapbox', + Key: 'tilelive-s3/test/zxystream-unprefixed/' + zxy, + Body: png + }, assert.end); + }); +}); + +tape('ZXYStream', function(assert) { + var stream = ZXYStream('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{z}/{x}/{y}'); + var lines = []; + stream.on('data', function(line) { + lines.push(line); + }); + stream.on('end', function() { + assert.deepEqual(lines, [ + '0/0/0', + '1/0/0', + '1/0/1', + '1/1/0', + '1/1/1' + ]); + assert.end(); + }); +}); + +tape('config', function(assert) { + assert.deepEqual(ZXYStream.config('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{z}/{x}/{y}'), { + toList: [ 's3://mapbox/tilelive-s3/test/zxystream-unprefixed/' ], + tokenMap: [ 1, 2, 3 ], + tokenPattern: /tilelive-s3\/test\/zxystream-unprefixed\/([0-9]+)\/([0-9]+)\/([0-9]+)/ + }); + assert.end(); +}); + From 94c612176b231cc53cb783b2867dcbed314aa30f Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Mon, 2 Nov 2015 14:03:06 -0500 Subject: [PATCH 2/8] Add support + tests for {prefix} token --- lib/zxystream.js | 11 +- test/zxystream.test.js | 313 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 314 insertions(+), 10 deletions(-) diff --git a/lib/zxystream.js b/lib/zxystream.js index 708477c..0a79d60 100644 --- a/lib/zxystream.js +++ b/lib/zxystream.js @@ -26,9 +26,12 @@ function config(tilesUrl) { var conf = {}; conf.toList = []; if ((/{prefix}/).test(tilesUrl)) { - conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0]); + for (var i = 0; i < 256; i++) { + var prefix = i < 16 ? '0' + i.toString(16) : i.toString(16); + conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0].replace(/{prefix}/g,prefix)); + } } else { - conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0]); + conf.toList.push(s3urls.convert(tilesUrl, 's3').split(/{(z|x|y)}/)[0]); } var matches = s3urls.fromUrl(tilesUrl).Key.match(/{(z|x|y)}/g); @@ -45,7 +48,9 @@ function config(tilesUrl) { return memo; }, []); - conf.tokenPattern = new RegExp(s3urls.fromUrl(tilesUrl).Key.replace(/{(z|x|y)}/g, '([0-9]+)')); + conf.tokenPattern = new RegExp(s3urls.fromUrl(tilesUrl).Key + .replace(/{prefix}/g, '[0-f]{2}') + .replace(/{(z|x|y)}/g, '([0-9]+)')); return conf; } diff --git a/test/zxystream.test.js b/test/zxystream.test.js index 977c70a..897e840 100644 --- a/test/zxystream.test.js +++ b/test/zxystream.test.js @@ -4,6 +4,283 @@ var fs = require('fs'); var tape = require('tape'); var ZXYStream = require('../lib/zxystream'); +tape('config', function(assert) { + assert.deepEqual(ZXYStream.config('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{z}/{x}/{y}'), { + toList: [ 's3://mapbox/tilelive-s3/test/zxystream-unprefixed/' ], + tokenMap: [ 1, 2, 3 ], + tokenPattern: /tilelive-s3\/test\/zxystream-unprefixed\/([0-9]+)\/([0-9]+)\/([0-9]+)/ + }, 'z/x/y order'); + assert.deepEqual(ZXYStream.config('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{x}/{z}/{y}'), { + toList: [ 's3://mapbox/tilelive-s3/test/zxystream-unprefixed/' ], + tokenMap: [ 2, 1, 3 ], + tokenPattern: /tilelive-s3\/test\/zxystream-unprefixed\/([0-9]+)\/([0-9]+)\/([0-9]+)/ + }, 'x/y/z order'); + assert.deepEqual(ZXYStream.config('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-prefixed/{prefix}/{z}/{x}/{y}'), { + toList: [ + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/00/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/01/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/02/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/03/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/04/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/05/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/06/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/07/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/08/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/09/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/0f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/10/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/11/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/12/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/13/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/14/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/15/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/16/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/17/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/18/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/19/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/1f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/20/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/21/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/22/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/23/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/24/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/25/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/26/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/27/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/28/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/29/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/2f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/30/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/31/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/32/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/33/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/34/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/35/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/36/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/37/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/38/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/39/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/3f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/40/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/41/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/42/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/43/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/44/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/45/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/46/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/47/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/48/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/49/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/4f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/50/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/51/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/52/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/53/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/54/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/55/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/56/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/57/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/58/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/59/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/5f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/60/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/61/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/62/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/63/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/64/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/65/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/66/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/67/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/68/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/69/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/6f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/70/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/71/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/72/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/73/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/74/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/75/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/76/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/77/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/78/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/79/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/7f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/80/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/81/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/82/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/83/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/84/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/85/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/86/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/87/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/88/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/89/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/8f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/90/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/91/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/92/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/93/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/94/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/95/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/96/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/97/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/98/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/99/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9a/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9b/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9c/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9d/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9e/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/9f/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/a9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/aa/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ab/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ac/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ad/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ae/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/af/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/b9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ba/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/bb/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/bc/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/bd/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/be/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/bf/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/c9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ca/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/cb/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/cc/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/cd/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ce/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/cf/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/d9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/da/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/db/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/dc/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/dd/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/de/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/df/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/e9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ea/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/eb/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ec/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ed/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ee/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ef/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f0/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f1/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f2/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f3/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f4/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f5/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f6/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f7/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f8/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/f9/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/fa/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/fb/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/fc/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/fd/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/fe/', + 's3://mapbox/tilelive-s3/test/zxystream-prefixed/ff/' + ], + tokenMap: [ 1, 2, 3 ], + tokenPattern: /tilelive-s3\/test\/zxystream-unprefixed\/([0-9]+)\/([0-9]+)\/([0-9]+)/ + }); + assert.end(); +}); + + [ '0/0/0', '1/0/0', '1/0/1', '1/1/0', '1/1/1' ].forEach(function(zxy) { tape('setup tile ' + zxy, function(assert) { var png = fs.readFileSync(__dirname + '/fixtures/tile.png'); @@ -15,7 +292,18 @@ var ZXYStream = require('../lib/zxystream'); }); }); -tape('ZXYStream', function(assert) { +[ '00/8/0/0', '10/8/1/0', '01/8/0/1', '11/8/1/1', '21/8/2/1', '22/8/2/2', 'ff/8/15/15' ].forEach(function(prefixed) { + tape('setup tile ' + prefixed, function(assert) { + var png = fs.readFileSync(__dirname + '/fixtures/tile.png'); + awss3.putObject({ + Bucket: 'mapbox', + Key: 'tilelive-s3/test/zxystream-prefixed/' + prefixed, + Body: png + }, assert.end); + }); +}); + +tape('ZXYStream (unprefixed)', function(assert) { var stream = ZXYStream('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{z}/{x}/{y}'); var lines = []; stream.on('data', function(line) { @@ -33,12 +321,23 @@ tape('ZXYStream', function(assert) { }); }); -tape('config', function(assert) { - assert.deepEqual(ZXYStream.config('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-unprefixed/{z}/{x}/{y}'), { - toList: [ 's3://mapbox/tilelive-s3/test/zxystream-unprefixed/' ], - tokenMap: [ 1, 2, 3 ], - tokenPattern: /tilelive-s3\/test\/zxystream-unprefixed\/([0-9]+)\/([0-9]+)\/([0-9]+)/ +tape('ZXYStream (prefixed)', function(assert) { + var stream = ZXYStream('http://mapbox.s3.amazonaws.com/tilelive-s3/test/zxystream-prefixed/{prefix}/{z}/{x}/{y}'); + var lines = []; + stream.on('data', function(line) { + lines.push(line); + }); + stream.on('end', function() { + assert.deepEqual(lines, [ + '8/0/0', + '8/0/1', + '8/1/0', + '8/1/1', + '8/2/1', + '8/2/2', + '8/15/15' + ]); + assert.end(); }); - assert.end(); }); From 5669c6555cdbf918b0703e38ef294a841d7717db Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Mon, 2 Nov 2015 14:57:14 -0500 Subject: [PATCH 3/8] Drop unused options arg. --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index b2d9ac2..83d6abe 100644 --- a/lib/index.js +++ b/lib/index.js @@ -578,9 +578,9 @@ S3.prototype.getIndexableDocs = function(pointer, callback) { }; // Create a readable ZXY list stream. -S3.prototype.createZXYStream = function(options) { +S3.prototype.createZXYStream = function() { if (!this.data) return callback(new Error('Tilesource not loaded')); if (!this.data.tiles) return callback(new Error('No "tiles" key')); - return new ZXYStream(this.data.tiles[0], options); + return new ZXYStream(this.data.tiles[0]); }; From 70c041df7c6efe46e94cc18164cd66933b8c8fd1 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Mon, 2 Nov 2015 15:49:56 -0500 Subject: [PATCH 4/8] Test + fix createZXYStream --- lib/index.js | 1 + test/s3.test.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/lib/index.js b/lib/index.js index 83d6abe..014b18e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -15,6 +15,7 @@ var AgentKeepAlive = require('agentkeepalive'); var s3urls = require('s3urls'); var utils = require('util'); var Emitter = require('events').EventEmitter; +var ZXYStream = require('./zxystream'); module.exports = S3; diff --git a/test/s3.test.js b/test/s3.test.js index 9c0a13a..dea0c67 100644 --- a/test/s3.test.js +++ b/test/s3.test.js @@ -621,3 +621,12 @@ tape('source load error should fail gracefully', function(assert) { }); }); })(); + +tape('createZXYStream', function(assert) { + new S3(url.parse('s3://mapbox/tilelive-s3/test/{z}/{x}/{y}.png'), function(err, source) { + assert.ifError(err, 'success'); + var zxyStream = source.createZXYStream(); + assert.equal(zxyStream.readable, true, 'returns readable stream'); + assert.end(); + }); +}); From 4bbadbc251372c068d5bcf2993e50666cd35833a Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Mon, 2 Nov 2015 15:56:13 -0500 Subject: [PATCH 5/8] Deps are very important. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index d581ef0..666df10 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "aws-sdk": "^2.1.44", "nan": "^1.8.4", "node-pre-gyp": "~0.6.7", + "split": "~1.0.0", "s3scan": "0.1.0", "s3urls": "^1.3.0", "stream-concat": "0.1.0", From a2a7580e937760e31abd73846b1bc3228ba7ac72 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Mon, 2 Nov 2015 16:57:31 -0500 Subject: [PATCH 6/8] Keep things line-delimited. --- lib/zxystream.js | 2 +- test/zxystream.test.js | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/zxystream.js b/lib/zxystream.js index 0a79d60..c73d146 100644 --- a/lib/zxystream.js +++ b/lib/zxystream.js @@ -18,7 +18,7 @@ function ZXYStream(tilesUrl) { if (!matches || matches.length < 4) return undefined; return matches[conf.tokenMap[0]] + '/' + matches[conf.tokenMap[1]] + '/' + - matches[conf.tokenMap[2]]; + matches[conf.tokenMap[2]] + '\n'; })); } diff --git a/test/zxystream.test.js b/test/zxystream.test.js index 897e840..e3c8a5b 100644 --- a/test/zxystream.test.js +++ b/test/zxystream.test.js @@ -311,11 +311,11 @@ tape('ZXYStream (unprefixed)', function(assert) { }); stream.on('end', function() { assert.deepEqual(lines, [ - '0/0/0', - '1/0/0', - '1/0/1', - '1/1/0', - '1/1/1' + '0/0/0\n', + '1/0/0\n', + '1/0/1\n', + '1/1/0\n', + '1/1/1\n' ]); assert.end(); }); @@ -329,13 +329,13 @@ tape('ZXYStream (prefixed)', function(assert) { }); stream.on('end', function() { assert.deepEqual(lines, [ - '8/0/0', - '8/0/1', - '8/1/0', - '8/1/1', - '8/2/1', - '8/2/2', - '8/15/15' + '8/0/0\n', + '8/0/1\n', + '8/1/0\n', + '8/1/1\n', + '8/2/1\n', + '8/2/2\n', + '8/15/15\n' ]); assert.end(); }); From 110c927b0f0056e459dc0193276d7ac9b1e17c3b Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 5 Nov 2015 18:20:03 -0500 Subject: [PATCH 7/8] Move travis template. --- test/travis-resources.template => cloudformation/travis.template | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/travis-resources.template => cloudformation/travis.template (100%) diff --git a/test/travis-resources.template b/cloudformation/travis.template similarity index 100% rename from test/travis-resources.template rename to cloudformation/travis.template From 9c76424d179b9a5993badd8825ae81ad3394f51b Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 5 Nov 2015 18:27:01 -0500 Subject: [PATCH 8/8] Add list permissions for tilelive-s3 prefix. --- cloudformation/travis.template | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/cloudformation/travis.template b/cloudformation/travis.template index 0f209ad..c6ce1d4 100644 --- a/cloudformation/travis.template +++ b/cloudformation/travis.template @@ -42,6 +42,29 @@ ] } }, + { + "PolicyName": "testList", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mapbox" + ], + "Condition": { + "StringLike": { + "s3:prefix": [ + "tilelive-s3/*" + ] + } + } + } + ] + } + }, { "PolicyName": "test", "PolicyDocument": {