-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
112 lines (98 loc) · 2.79 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"use strict";
const geojsonVt = require("geojson-vt");
const vtPbf = require("vt-pbf");
const request = require("requestretry");
const zlib = require("zlib");
const NodeCache = require("node-cache" );
const _ = require("lodash");
const url = process.env.BUS_POSITIONS_URL || "https://raw.githubusercontent.com/stadtnavi/tilelive-bus-positions/main/geojson/bus-positions.geojson";
const getGeoJson = (url, callback) => {
request(
{
url: url,
maxAttempts: 20,
retryDelay: 30000,
retryStrategy: (err, response) =>
request.RetryStrategies.HTTPOrNetworkError(err, response) ||
(response && 202 === response.statusCode)
},
function(err, res, body) {
if (err) {
console.log(`Error when downloading GeoJSON data from ${url}: ${err} ${res} ${body}`);
callback(err);
return;
}
callback(null, stringifyArrays(JSON.parse(body)));
}
);
};
const stringifyArrays = (geoJson) => {
geoJson.features.forEach( feature => {
Object.keys(feature.properties).forEach(key => {
const value = feature.properties[key];
if(_.isArray(value)) {
feature.properties[key] = value.join(",");
}
});
});
return geoJson;
}
class BusSource {
constructor(uri, callback) {
this.cacheKey = "tileindex";
this.cache = new NodeCache({ stdTTL: 15, useClones: false });
this.url = url;
callback(null, this);
}
fetchGeoJson(callback){
getGeoJson(this.url, (err, geojson) => {
if (err) {
callback(err);
return;
}
callback(geojson);
});
}
getTile(z, x, y, callback) {
if(this.cache.get(this.cacheKey)) {
const geojson = this.cache.get(this.cacheKey);
this.computeTile(geojson, z, x, y, callback);
} else {
this.fetchGeoJson((geojson) => {
this.cache.set(this.cacheKey, geojson);
this.computeTile(geojson, z, x, y, callback);
});
}
}
computeTile(geoJson, z, x, y, callback) {
const tileIndex = geojsonVt(geoJson, { maxZoom: 20, buffer: 512 });
let tile = tileIndex.getTile(z, x, y);
if (tile === null) {
tile = { features: [] };
}
const data = Buffer.from(vtPbf.fromGeojsonVt({ buspositions: tile }));
zlib.gzip(data, function(err, buffer) {
if (err) {
callback(err);
return;
}
callback(null, buffer, { "content-encoding": "gzip", "cache-control": "public,max-age=15" });
});
}
getInfo(callback) {
callback(null, {
format: "pbf",
maxzoom: 20,
vector_layers: [
{
description: "Bus position data retrieved from a GeoJSON source",
id: "buspositions"
}
]
});
}
}
module.exports = BusSource;
module.exports.registerProtocols = tilelive => {
tilelive.protocols["buspositions:"] = BusSource;
};