#!/usr/bin/env python """ This is a simple vector tile server that returns a PBF tile for /tiles/{z}/{x}/{y}.pbf requests Use these environment variables to configure PostgreSQL access: POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DB, POSTGRES_PASSWORD Usage: server [--fname ] [--port ] server --help server --version SQL file generated by generate-sqltomvt script with the --prepared flag Options: --fname= Name of the generated function [default: gettile] -p --port= Serve on this port [default: 8080] --help Show this screen. --version Show version. """ import logging import tornado.ioloop import tornado.web import io import os from docopt import docopt import psycopg2 class GetTile(tornado.web.RequestHandler): def initialize(self, fname, connection, query): self.fname = fname self.db_connection = connection self.db_query = query def get(self, z, x, y): z, x, y = int(z), int(x), int(y) cursor = self.db_connection.cursor() try: cursor.execute(self.db_query, (z, x, y)) result = cursor.fetchall() if result: self.set_header("Content-Type", "application/x-protobuf") self.set_header("Content-Disposition", "attachment") self.set_header("Access-Control-Allow-Origin", "*") value = io.BytesIO(result[0][0]).getvalue() self.write(value) print('{0}({1},{2},{3}) --> {4:,} bytes'.format(self.fname, z, x, y, len(value))) else: self.clear() self.set_status(404) print('{0}({1},{2},{3}) is EMPTY'.format(self.fname, z, x, y)) except Exception as err: print('{0}({1},{2},{3}) threw an exception'.format(self.fname, z, x, y, err)) raise finally: cursor.close() def main(args): pgdb = os.getenv('POSTGRES_DB', 'openmaptiles') pghost = os.getenv('POSTGRES_HOST', 'localhost') pgport = os.getenv('POSTGRES_PORT', '5432') print('Connecting to PostgreSQL at {0}:{1}, db={2}...'.format(pghost, pgport, pgdb)) connection = psycopg2.connect( dbname=pgdb, host=pghost, port=pgport, user=os.getenv('POSTGRES_USER', 'openmaptiles'), password=os.getenv('POSTGRES_PASSWORD', 'openmaptiles'), ) sqlfile = args[''] with open(sqlfile, 'r') as stream: prepared = stream.read() print('Using prepared SQL:\n\n-------\n\n' + prepared + '\n\n-------\n\n') cursor = connection.cursor() try: cursor.execute(prepared) finally: cursor.close() fname = args['--fname'] query = "EXECUTE {0}(%s, %s, %s)".format(fname) print('Loaded {0}\nWill use "{1}" to get vector tiles.'.format(sqlfile, query)) tornado.log.access_log.setLevel(logging.ERROR) port = int(args['--port']) application = tornado.web.Application([( r"/tiles/([0-9]+)/([0-9]+)/([0-9]+).pbf", GetTile, dict(fname=fname, connection=connection, query=query) )]) application.listen(port) print("Postserve started, listening on 0.0.0.0:{0}".format(port)) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main(docopt(__doc__, version="1.0"))