mirror of
https://github.com/rastapasta/mapscii.git
synced 2024-11-21 23:53:08 +01:00
Decaffeinate TileSource
This commit is contained in:
parent
d27e086758
commit
29b5b3ccb1
@ -1,133 +0,0 @@
|
||||
###
|
||||
termap - Terminal Map Viewer
|
||||
by Michael Strassburger <codepoet@cpan.org>
|
||||
|
||||
Source for VectorTiles - supports
|
||||
* remote TileServer
|
||||
* local MBTiles and VectorTiles
|
||||
###
|
||||
|
||||
Promise = require 'bluebird'
|
||||
userhome = require 'userhome'
|
||||
fetch = require 'node-fetch'
|
||||
fs = require 'fs'
|
||||
|
||||
Tile = require './Tile'
|
||||
config = require './config'
|
||||
|
||||
# https://github.com/mapbox/node-mbtiles has native build dependencies (sqlite3)
|
||||
# To maximize mapscii's compatibility, MBTiles support must be manually added via
|
||||
# $> npm install -g mbtiles
|
||||
MBTiles = try
|
||||
require 'mbtiles'
|
||||
catch
|
||||
null
|
||||
|
||||
module.exports = class TileSource
|
||||
cache: {}
|
||||
cacheSize: 16
|
||||
cached: []
|
||||
|
||||
modes:
|
||||
MBTiles: 1
|
||||
VectorTile: 2
|
||||
HTTP: 3
|
||||
|
||||
mode: null
|
||||
mbtiles: null
|
||||
styler: null
|
||||
|
||||
init: (@source) ->
|
||||
if @source.startsWith "http"
|
||||
@_initPersistence() if config.persistDownloadedTiles
|
||||
|
||||
@mode = @modes.HTTP
|
||||
|
||||
else if @source.endsWith ".mbtiles"
|
||||
unless MBTiles
|
||||
throw new Error "MBTiles support must be installed with following command: 'npm install -g mbtiles'"
|
||||
|
||||
@mode = @modes.MBTiles
|
||||
@loadMBtils source
|
||||
|
||||
else
|
||||
throw new Error "source type isn't supported yet"
|
||||
|
||||
loadMBtils: (source) ->
|
||||
new Promise (resolve, reject) =>
|
||||
new MBTiles source, (err, @mbtiles) =>
|
||||
if err then reject err
|
||||
else resolve()
|
||||
|
||||
useStyler: (@styler) ->
|
||||
|
||||
getTile: (z, x, y) ->
|
||||
unless @mode
|
||||
throw new Error "no TileSource defined"
|
||||
|
||||
z = Math.max 0, Math.floor z
|
||||
|
||||
if cached = @cache[[z,x,y].join("-")]
|
||||
return Promise.resolve cached
|
||||
|
||||
if @cached.length > @cacheSize
|
||||
for tile in @cached.splice 0, Math.abs(@cacheSize-@cached.length)
|
||||
delete @cache[tile]
|
||||
|
||||
switch @mode
|
||||
when @modes.MBTiles then @_getMBTile z, x, y
|
||||
when @modes.HTTP then @_getHTTP z, x, y
|
||||
|
||||
_getHTTP: (z, x, y) ->
|
||||
promise =
|
||||
if config.persistDownloadedTiles and tile = @_getPersited z, x, y
|
||||
Promise.resolve tile
|
||||
else
|
||||
fetch @source+[z,x,y].join("/")+".pbf"
|
||||
.then (res) => res.buffer()
|
||||
.then (buffer) =>
|
||||
@_persistTile z, x, y, buffer if config.persistDownloadedTiles
|
||||
buffer
|
||||
|
||||
promise
|
||||
.then (buffer) =>
|
||||
@_createTile z, x, y, buffer
|
||||
|
||||
_getMBTile: (z, x, y) ->
|
||||
new Promise (resolve, reject) =>
|
||||
@mbtiles.getTile z, x, y, (err, buffer) =>
|
||||
return reject err if err
|
||||
resolve @_createTile z, x, y, buffer
|
||||
|
||||
_createTile: (z, x, y, buffer) ->
|
||||
name = [z,x,y].join("-")
|
||||
@cached.push name
|
||||
|
||||
tile = @cache[name] = new Tile @styler
|
||||
tile.load buffer
|
||||
|
||||
_initPersistence: ->
|
||||
try
|
||||
@_createFolder userhome ".mapscii"
|
||||
@_createFolder userhome ".mapscii", "cache"
|
||||
catch error
|
||||
config.persistDownloadedTiles = false
|
||||
return
|
||||
|
||||
_persistTile: (z, x, y, buffer) ->
|
||||
zoom = z.toString()
|
||||
@_createFolder userhome ".mapscii", "cache", zoom
|
||||
fs.writeFile userhome(".mapscii", "cache", zoom, "#{x}-#{y}.pbf"), buffer, -> null
|
||||
|
||||
_getPersited: (z, x, y) ->
|
||||
try
|
||||
fs.readFileSync userhome ".mapscii", "cache", z.toString(), "#{x}-#{y}.pbf"
|
||||
catch error
|
||||
false
|
||||
|
||||
_createFolder: (path) ->
|
||||
try
|
||||
fs.mkdirSync path
|
||||
true
|
||||
catch e
|
||||
e.code is "EEXIST"
|
180
src/TileSource.js
Normal file
180
src/TileSource.js
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
termap - Terminal Map Viewer
|
||||
by Michael Strassburger <codepoet@cpan.org>
|
||||
|
||||
Source for VectorTiles - supports
|
||||
* remote TileServer
|
||||
* local MBTiles and VectorTiles
|
||||
*/
|
||||
'use strict';
|
||||
const userhome = require('userhome');
|
||||
const fetch = require('node-fetch');
|
||||
const fs = require('fs');
|
||||
|
||||
const Tile = require('./Tile');
|
||||
const config = require('./config');
|
||||
|
||||
// https://github.com/mapbox/node-mbtiles has native build dependencies (sqlite3)
|
||||
// To maximize mapscii's compatibility, MBTiles support must be manually added via
|
||||
// $> npm install -g mbtiles
|
||||
let MBTiles = null;
|
||||
try {
|
||||
MBTiles = require('mbtiles');
|
||||
} catch (err) {}
|
||||
|
||||
const cache = {};
|
||||
const cacheSize = 16;
|
||||
const cached = [];
|
||||
|
||||
const modes = {
|
||||
MBTiles: 1,
|
||||
VectorTile: 2,
|
||||
HTTP: 3,
|
||||
};
|
||||
|
||||
class TileSource {
|
||||
init(source) {
|
||||
this.source = source;
|
||||
|
||||
this.cache = {};
|
||||
this.cacheSize = 16;
|
||||
this.cached = [];
|
||||
|
||||
this.mode = null;
|
||||
this.mbtiles = null;
|
||||
this.styler = null;
|
||||
|
||||
if (this.source.startsWith('http')) {
|
||||
if (config.persistDownloadedTiles) {
|
||||
this._initPersistence();
|
||||
}
|
||||
|
||||
this.mode = modes.HTTP;
|
||||
|
||||
} else if (this.source.endsWith('.mbtiles')) {
|
||||
if (!MBTiles) {
|
||||
throw new Error("MBTiles support must be installed with following command: 'npm install -g mbtiles'");
|
||||
}
|
||||
|
||||
this.mode = modes.MBTiles;
|
||||
this.loadMBtils(source);
|
||||
} else {
|
||||
throw new Error("source type isn't supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
loadMBtils(source) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new MBTiles(source, (err, mbtiles) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
this.mbtiles = mbtiles;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
useStyler(styler) {
|
||||
this.styler = styler;
|
||||
}
|
||||
|
||||
getTile(z, x, y) {
|
||||
if (!this.mode) {
|
||||
throw new Error("no TileSource defined");
|
||||
}
|
||||
|
||||
const cached = this.cache[[z, x, y].join("-")];
|
||||
if (cached) {
|
||||
return Promise.resolve(cached);
|
||||
}
|
||||
|
||||
if (this.cached.length > this.cacheSize) {
|
||||
const overflow = Math.abs(this.cacheSize - this.cache.length);
|
||||
for (const tile in this.cached.splice(0, overflow)) {
|
||||
delete this.cache[tile];
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.mode) {
|
||||
case modes.MBTiles:
|
||||
return this._getMBTile(z, x, y);
|
||||
case modes.HTTP:
|
||||
return this._getHTTP(z, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
_getHTTP(z, x, y) {
|
||||
let promise;
|
||||
const persistedTile = this._getPersited(z, x, y);
|
||||
if (config.persistDownloadedTiles && persistedTile) {
|
||||
promise = Promise.resolve(persistedTile);
|
||||
} else {
|
||||
promise = fetch(this.source + [z,x,y].join('/') + '.pbf')
|
||||
.then((res) => res.buffer())
|
||||
.then((buffer) => {
|
||||
if (config.persistDownloadedTiles) {
|
||||
this._persistTile(z, x, y, buffer);
|
||||
return buffer;
|
||||
}
|
||||
});
|
||||
}
|
||||
return promise.then((buffer) => {
|
||||
return this._createTile(z, x, y, buffer);
|
||||
});
|
||||
}
|
||||
|
||||
_getMBTile(z, x, y) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.mbtiles.getTile(z, x, y, (err, buffer) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(this._createTile(z, x, y, buffer));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_createTile(z, x, y, buffer) {
|
||||
const name = [z, x, y].join('-');
|
||||
this.cached.push(name);
|
||||
|
||||
const tile = this.cache[name] = new Tile(this.styler);
|
||||
return tile.load(buffer);
|
||||
}
|
||||
|
||||
_initPersistence() {
|
||||
try {
|
||||
this._createFolder(userhome('.mapscii'));
|
||||
this._createFolder(userhome('.mapscii', 'cache'));
|
||||
} catch (error) {
|
||||
config.persistDownloadedTiles = false;
|
||||
}
|
||||
}
|
||||
|
||||
_persistTile(z, x, y, buffer) {
|
||||
const zoom = z.toString();
|
||||
this._createFolder(userhome('.mapscii', 'cache', zoom));
|
||||
const filePath = userhome('.mapscii', 'cache', zoom, `${x}-${y}.pbf`);
|
||||
return fs.writeFile(filePath, buffer, () => null);
|
||||
}
|
||||
|
||||
_getPersited(z, x, y) {
|
||||
try {
|
||||
return fs.readFileSync(userhome('.mapscii', 'cache', z.toString(), `${x}-${y}.pbf`));
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_createFolder(path) {
|
||||
try {
|
||||
fs.mkdirSync(path);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return error.code === "EEXIST";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TileSource;
|
Loading…
Reference in New Issue
Block a user