]> gerrit.simantics Code Review - simantics/district.git/blobdiff - 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
diff --git a/org.simantics.maps.server/server/tileserver-mapnik/server.js b/org.simantics.maps.server/server/tileserver-mapnik/server.js
new file mode 100644 (file)
index 0000000..4013c6d
--- /dev/null
@@ -0,0 +1,157 @@
+#!/usr/bin/env node
+"use strict";
+
+// increase the libuv threadpool size to 1.5x the number of logical CPUs.
+process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE || Math.ceil(Math.max(4, require('os').cpus().length * 1.5));
+
+var fs = require("fs"),
+    path = require("path");
+
+var async = require("async"),
+    cors = require("cors"),
+    debug = require("debug"),
+    express = require("express"),
+    morgan = require("morgan"),
+    responseTime = require("response-time");
+
+var serve = require("./lib/app"),
+    tessera = require("./lib/index");
+
+debug = debug("tessera");
+
+module.exports = function(opts, callback) {
+  var app = express().disable("x-powered-by"),
+      tilelive = require("tilelive-cache")(require("tilelive"), {
+        size: process.env.CACHE_SIZE || opts.cacheSize,
+        sources: process.env.SOURCE_CACHE_SIZE || opts.sourceCacheSize
+      });
+
+  app.enable('trust proxy');
+
+  callback = callback || function() {};
+
+  // load and register tilelive modules
+  require("tilelive-modules/loader")(tilelive, opts);
+
+  if (process.env.NODE_ENV !== "production") {
+    // TODO configurable logging per-style
+    app.use(morgan("dev"));
+  }
+
+  if (opts.uri) {
+    app.use(responseTime());
+    app.use(cors());
+    app.use(express.static(path.join(__dirname, "public")));
+    app.use(express.static(path.join(__dirname, "bower_components")));
+    app.use(serve(tilelive, opts.uri));
+
+    tilelive.load(opts.uri, function(err, src) {
+      if (err) {
+        throw err;
+      }
+
+      return tessera.getInfo(src, function(err, info) {
+        if (err) {
+          debug(err.stack);
+          return;
+        }
+
+        if (info.format === "pbf") {
+          app.use("/_", serve(tilelive, "xray+" + opts.uri));
+          app.use("/_", express.static(path.join(__dirname, "public")));
+          app.use("/_", express.static(path.join(__dirname, "bower_components")));
+        }
+      });
+    });
+  }
+
+  if (opts.config) {
+    var configPath = path.resolve(opts.config),
+        stats = fs.statSync(configPath),
+        config = {};
+
+    if (stats.isFile()) {
+      config = require(configPath);
+    } else if (stats.isDirectory()) {
+      config = fs.readdirSync(configPath)
+        .filter(function(filename) {
+          return path.extname(filename) === ".json";
+        })
+        .reduce(function(config, filename) {
+          var localConfig = require(path.join(configPath, filename));
+
+          return Object.keys(localConfig).reduce(function(config, k) {
+            config[k] = localConfig[k];
+
+            return config;
+          }, config);
+        }, config);
+    }
+
+    Object.keys(config).forEach(function(prefix) {
+      if (config[prefix].timing !== false) {
+        app.use(prefix, responseTime());
+      }
+
+      if (config[prefix].cors !== false) {
+        app.use(prefix, cors());
+      }
+
+      //app.use(prefix, express.static(path.join(__dirname, "public")));
+      //app.use(prefix, express.static(path.join(__dirname, "bower_components")));
+      app.use(prefix, serve(tilelive, config[prefix]));
+    });
+
+    // serve index.html even on the root
+    app.use("/", express.static(path.join(__dirname, "public")));
+    app.use("/", express.static(path.join(__dirname, "bower_components")));
+
+    // aggregate index.json on root for multiple sources
+    app.get("/index.json", function(req, res, next) {
+      var queue = [];
+      Object.keys(config).forEach(function(prefix) {
+        queue.push(function(callback) {
+          var url = config[prefix].source || config[prefix];
+          tilelive.load(url, function(err, source) {
+            if (err) {
+              throw err;
+            }
+
+            tessera.getInfo(source, function(err, info) {
+              if (err) {
+                throw err;
+              }
+
+              var domains = [],
+                  tilePath = config[prefix].tilePath || "/{z}/{x}/{y}.{format}";
+
+              if (config[prefix].domains && config[prefix].domains.length > 0) {
+                domains = config[prefix].domains.split(',');
+              }
+
+              if (prefix.length > 1) {
+                info.basename = prefix.substr(1);
+              }
+
+              info.tiles = serve.getTileUrls(domains, req.headers.host, prefix,
+                                             tilePath, info.format,
+                                             req.query.key, req.protocol);
+              info.tilejson = "2.0.0";
+
+              callback(null, info);
+            });
+          });
+        });
+      });
+      return async.parallel(queue, function(err, results) {
+        return res.send(results);
+      });
+    });
+  }
+
+  app.listen(process.env.PORT || opts.port, function() {
+    console.log("Listening at http://%s:%d/", this.address().address, this.address().port);
+
+    return callback();
+  });
+};