Improved font serving

This commit is contained in:
Petr Sloup 2016-12-09 13:19:34 +01:00
parent bbc14abb4a
commit 509d32da68
4 changed files with 71 additions and 18 deletions

View file

@ -1,7 +1,9 @@
'use strict'; 'use strict';
var clone = require('clone'), var clone = require('clone'),
express = require('express'); express = require('express'),
fs = require('fs'),
path = require('path');
var utils = require('./utils'); var utils = require('./utils');
@ -12,14 +14,29 @@ module.exports = function(options, allowedFonts) {
var fontPath = options.paths.fonts; var fontPath = options.paths.fonts;
var existingFonts = {};
fs.readdir(options.paths.fonts, function(err, files) {
files.forEach(function(file) {
fs.stat(path.join(fontPath, file), function(err, stats) {
if (!err) {
if (stats.isDirectory()) {
existingFonts[path.basename(file)] = true;
}
}
});
});
});
app.get('/:fontstack/:range([\\d]+-[\\d]+).pbf', app.get('/:fontstack/:range([\\d]+-[\\d]+).pbf',
function(req, res, next) { function(req, res, next) {
var fontstack = decodeURI(req.params.fontstack); var fontstack = decodeURI(req.params.fontstack);
var range = req.params.range; var range = req.params.range;
return utils.getFontsPbf(allowedFonts, fontPath, fontstack, range, return utils.getFontsPbf(allowedFonts, fontPath, fontstack, range, existingFonts,
function(err, concated) { function(err, concated) {
if (err || concated.length === 0) { if (err || concated.length === 0) {
console.log(err);
console.log(concated.length);
return res.status(400).send(''); return res.status(400).send('');
} else { } else {
res.header('Content-type', 'application/x-protobuf'); res.header('Content-type', 'application/x-protobuf');

View file

@ -49,6 +49,19 @@ module.exports = function(options, repo, params, id, dataResolver) {
sources: {} sources: {}
}; };
var existingFonts = {};
fs.readdir(options.paths.fonts, function(err, files) {
files.forEach(function(file) {
fs.stat(path.join(options.paths.fonts, file), function(err, stats) {
if (!err) {
if (stats.isDirectory()) {
existingFonts[path.basename(file)] = true;
}
}
});
});
});
var styleJSON; var styleJSON;
var createPool = function(ratio, min, max) { var createPool = function(ratio, min, max) {
var createRenderer = function(ratio, createCallback) { var createRenderer = function(ratio, createCallback) {
@ -67,7 +80,7 @@ module.exports = function(options, repo, params, id, dataResolver) {
var parts = req.url.split('/'); var parts = req.url.split('/');
var fontstack = unescape(parts[2]); var fontstack = unescape(parts[2]);
var range = parts[3].split('.')[0]; var range = parts[3].split('.')[0];
utils.getFontsPbf(null, options.paths[protocol], fontstack, range, utils.getFontsPbf(null, options.paths[protocol], fontstack, range, existingFonts,
function(err, concated) { function(err, concated) {
callback(err, {data: concated}); callback(err, {data: concated});
}); });
@ -148,13 +161,13 @@ module.exports = function(options, repo, params, id, dataResolver) {
styleJSON = clone(require(styleJSONPath)); styleJSON = clone(require(styleJSONPath));
var httpTester = /^(http(s)?:)?\/\//; var httpTester = /^(http(s)?:)?\/\//;
if (!httpTester.test(styleJSON.sprite)) { if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
styleJSON.sprite = 'sprites://' + styleJSON.sprite = 'sprites://' +
styleJSON.sprite styleJSON.sprite
.replace('{style}', path.basename(styleFile, '.json')) .replace('{style}', path.basename(styleFile, '.json'))
.replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath))); .replace('{styleJsonFolder}', path.relative(options.paths.sprites, path.dirname(styleJSONPath)));
} }
if (!httpTester.test(styleJSON.glyphs)) { if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
styleJSON.glyphs = 'fonts://' + styleJSON.glyphs; styleJSON.glyphs = 'fonts://' + styleJSON.glyphs;
} }
@ -204,6 +217,9 @@ module.exports = function(options, repo, params, id, dataResolver) {
} }
map.sources[name] = new mbtiles(mbtilesFile, function(err) { map.sources[name] = new mbtiles(mbtilesFile, function(err) {
map.sources[name].getInfo(function(err, info) { map.sources[name].getInfo(function(err, info) {
if (err) {
console.error(err);
}
var type = source.type; var type = source.type;
Object.assign(source, info); Object.assign(source, info);
source.type = type; source.type = type;

View file

@ -46,7 +46,7 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
var spritePath; var spritePath;
var httpTester = /^(http(s)?:)?\/\//; var httpTester = /^(http(s)?:)?\/\//;
if (!httpTester.test(styleJSON.sprite)) { if (styleJSON.sprite && !httpTester.test(styleJSON.sprite)) {
spritePath = path.join(options.paths.sprites, spritePath = path.join(options.paths.sprites,
styleJSON.sprite styleJSON.sprite
.replace('{style}', path.basename(styleFile, '.json')) .replace('{style}', path.basename(styleFile, '.json'))
@ -54,20 +54,23 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
); );
styleJSON.sprite = 'local://styles/' + id + '/sprite'; styleJSON.sprite = 'local://styles/' + id + '/sprite';
} }
if (!httpTester.test(styleJSON.glyphs)) { if (styleJSON.glyphs && !httpTester.test(styleJSON.glyphs)) {
styleJSON.glyphs = 'local://fonts/{fontstack}/{range}.pbf'; styleJSON.glyphs = 'local://fonts/{fontstack}/{range}.pbf';
} }
repo[id] = styleJSON; repo[id] = styleJSON;
app.get('/' + id + '.json', function(req, res, next) { app.get('/' + id + '.json', function(req, res, next) {
var fixUrl = function(url, opt_nokey) { var fixUrl = function(url, opt_nokey, opt_nostyle) {
var queryParams = ['style=' + id]; var queryParams = [];
if (!opt_nostyle) {
queryParams.push('style=' + id);
}
if (!opt_nokey && req.query.key) { if (!opt_nokey && req.query.key) {
queryParams.unshift('key=' + req.query.key); queryParams.unshift('key=' + req.query.key);
} }
var query = ''; var query = '';
if (!opt_nokey) { if (queryParams.length) {
query = '?' + queryParams.join('&'); query = '?' + queryParams.join('&');
} }
return url.replace( return url.replace(
@ -80,8 +83,12 @@ module.exports = function(options, repo, params, id, reportTiles, reportFont) {
source.url = fixUrl(source.url); source.url = fixUrl(source.url);
}); });
// mapbox-gl-js viewer cannot handle sprite urls with query // mapbox-gl-js viewer cannot handle sprite urls with query
styleJSON_.sprite = fixUrl(styleJSON_.sprite, true); if (styleJSON_.sprite) {
styleJSON_.glyphs = fixUrl(styleJSON_.glyphs); styleJSON_.sprite = fixUrl(styleJSON_.sprite, true, true);
}
if (styleJSON_.glyphs) {
styleJSON_.glyphs = fixUrl(styleJSON_.glyphs, false, true);
}
return res.send(styleJSON_); return res.send(styleJSON_);
}); });

View file

@ -4,7 +4,8 @@ var async = require('async'),
path = require('path'), path = require('path'),
fs = require('fs'); fs = require('fs');
var glyphCompose = require('glyph-pbf-composite'); var clone = require('clone'),
glyphCompose = require('glyph-pbf-composite');
module.exports.getTileUrls = function(req, domains, path, format) { module.exports.getTileUrls = function(req, domains, path, format) {
@ -51,13 +52,25 @@ module.exports.fixTileJSONCenter = function(tileJSON) {
} }
}; };
module.exports.getFontsPbf = function(allowedFonts, fontPath, names, range, callback) { module.exports.getFontsPbf = function(allowedFonts, fontPath, names, range, fallbacks, callback) {
var getFontPbf = function(name, range, callback) { var getFontPbf = function(allowedFonts, name, range, callback, fallbacks) {
if (!allowedFonts || allowedFonts[name]) { if (!allowedFonts || (allowedFonts[name] && fallbacks)) {
var filename = path.join(fontPath, name, range + '.pbf'); var filename = path.join(fontPath, name, range + '.pbf');
if (!fallbacks) {
fallbacks = clone(allowedFonts || {});
}
delete fallbacks[name];
return fs.readFile(filename, function(err, data) { return fs.readFile(filename, function(err, data) {
if (err) { if (err) {
return callback(new Error('Font load error: ' + name)); console.error('ERROR: Font not found:', name);
if (fallbacks && Object.keys(fallbacks).length) {
var fallbackName = Object.keys(fallbacks)[0];
console.error('ERROR: Trying to use', fallbackName, 'as a fallback');
delete fallbacks[fallbackName];
return getFontPbf(null, fallbackName, range, callback, fallbacks);
} else {
return callback(new Error('Font load error: ' + name));
}
} else { } else {
return callback(null, data); return callback(null, data);
} }
@ -71,7 +84,7 @@ module.exports.getFontsPbf = function(allowedFonts, fontPath, names, range, call
var queue = []; var queue = [];
fonts.forEach(function(font) { fonts.forEach(function(font) {
queue.push(function(callback) { queue.push(function(callback) {
getFontPbf(font, range, callback); getFontPbf(allowedFonts, font, range, callback, clone(allowedFonts || fallbacks));
}); });
}); });