]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/server/tileserver-mapnik/server.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / server / tileserver-mapnik / server.js
1 #!/usr/bin/env node
2 "use strict";
3
4 // increase the libuv threadpool size to 1.5x the number of logical CPUs.
5 process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || Math.ceil(Math.max(4, require('os').cpus().length * 1.5));
6
7 var fs = require("fs"),
8     path = require("path");
9
10 var async = require("async"),
11     cors = require("cors"),
12     debug = require("debug"),
13     express = require("express"),
14     morgan = require("morgan"),
15     responseTime = require("response-time");
16
17 var serve = require("./lib/app"),
18     tessera = require("./lib/index");
19
20 debug = debug("tessera");
21
22 module.exports = function(opts, callback) {
23   var app = express().disable("x-powered-by"),
24       tilelive = require("tilelive-cache")(require("tilelive"), {
25         size: process.env.CACHE_SIZE || opts.cacheSize,
26         sources: process.env.SOURCE_CACHE_SIZE || opts.sourceCacheSize
27       });
28
29   app.enable('trust proxy');
30
31   callback = callback || function() {};
32
33   // load and register tilelive modules
34   require("tilelive-modules/loader")(tilelive, opts);
35
36   if (process.env.NODE_ENV !== "production") {
37     // TODO configurable logging per-style
38     app.use(morgan("dev"));
39   }
40
41   if (opts.uri) {
42     app.use(responseTime());
43     app.use(cors());
44     app.use(express.static(path.join(__dirname, "public")));
45     app.use(express.static(path.join(__dirname, "bower_components")));
46     app.use(serve(tilelive, opts.uri));
47
48     tilelive.load(opts.uri, function(err, src) {
49       if (err) {
50         throw err;
51       }
52
53       return tessera.getInfo(src, function(err, info) {
54         if (err) {
55           debug(err.stack);
56           return;
57         }
58
59         if (info.format === "pbf") {
60           app.use("/_", serve(tilelive, "xray+" + opts.uri));
61           app.use("/_", express.static(path.join(__dirname, "public")));
62           app.use("/_", express.static(path.join(__dirname, "bower_components")));
63         }
64       });
65     });
66   }
67
68   if (opts.config) {
69     var configPath = path.resolve(opts.config),
70         stats = fs.statSync(configPath),
71         config = {};
72
73     if (stats.isFile()) {
74       config = require(configPath);
75     } else if (stats.isDirectory()) {
76       config = fs.readdirSync(configPath)
77         .filter(function(filename) {
78           return path.extname(filename) === ".json";
79         })
80         .reduce(function(config, filename) {
81           var localConfig = require(path.join(configPath, filename));
82
83           return Object.keys(localConfig).reduce(function(config, k) {
84             config[k] = localConfig[k];
85
86             return config;
87           }, config);
88         }, config);
89     }
90
91     Object.keys(config).forEach(function(prefix) {
92       if (config[prefix].timing !== false) {
93         app.use(prefix, responseTime());
94       }
95
96       if (config[prefix].cors !== false) {
97         app.use(prefix, cors());
98       }
99
100       //app.use(prefix, express.static(path.join(__dirname, "public")));
101       //app.use(prefix, express.static(path.join(__dirname, "bower_components")));
102       app.use(prefix, serve(tilelive, config[prefix]));
103     });
104
105     // serve index.html even on the root
106     app.use("/", express.static(path.join(__dirname, "public")));
107     app.use("/", express.static(path.join(__dirname, "bower_components")));
108
109     // aggregate index.json on root for multiple sources
110     app.get("/index.json", function(req, res, next) {
111       var queue = [];
112       Object.keys(config).forEach(function(prefix) {
113         queue.push(function(callback) {
114           var url = config[prefix].source || config[prefix];
115           tilelive.load(url, function(err, source) {
116             if (err) {
117               throw err;
118             }
119
120             tessera.getInfo(source, function(err, info) {
121               if (err) {
122                 throw err;
123               }
124
125               var domains = [],
126                   tilePath = config[prefix].tilePath || "/{z}/{x}/{y}.{format}";
127
128               if (config[prefix].domains && config[prefix].domains.length > 0) {
129                 domains = config[prefix].domains.split(',');
130               }
131
132               if (prefix.length > 1) {
133                 info.basename = prefix.substr(1);
134               }
135
136               info.tiles = serve.getTileUrls(domains, req.headers.host, prefix,
137                                              tilePath, info.format,
138                                              req.query.key, req.protocol);
139               info.tilejson = "2.0.0";
140
141               callback(null, info);
142             });
143           });
144         });
145       });
146       return async.parallel(queue, function(err, results) {
147         return res.send(results);
148       });
149     });
150   }
151
152   app.listen(process.env.PORT || opts.port, function() {
153     console.log("Listening at http://%s:%d/", this.address().address, this.address().port);
154
155     return callback();
156   });
157 };