105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
#!/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 <prepared-sql-file> [--fname <name>] [--port <port>]
|
|
server --help
|
|
server --version
|
|
|
|
<prepared-sql-file> SQL file generated by generate-sqltomvt script with the --prepared flag
|
|
|
|
Options:
|
|
--fname=<name> Name of the generated function [default: gettile]
|
|
-p --port=<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['<prepared-sql-file>']
|
|
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"))
|