mirror of
https://github.com/systemed/tilemaker
synced 2025-02-21 13:24:09 +01:00

Rack::Handler is extracted to gem "rackup" from v3 ref: https://github.com/rack/rack/blob/main/CHANGELOG.md#removed Co-authored-by: Hsieh Chin Fan <pham@topo.tw>
120 lines
3.4 KiB
Ruby
Executable file
120 lines
3.4 KiB
Ruby
Executable file
#!/usr/bin/ruby
|
|
|
|
# Vector tile server
|
|
#
|
|
# This serves individual .pbf tiles from an .mbtiles file, plus
|
|
# any static files in the static/ directory. Use it for testing tilemaker output
|
|
# with a renderer such as Mapbox GL. (Your .mbtiles should be
|
|
# created with compression enabled.)
|
|
#
|
|
# Standalone syntax:
|
|
# ruby server.rb path_to.mbtiles
|
|
#
|
|
# It can also be run under Phusion Passenger.
|
|
|
|
require 'sqlite3'
|
|
require 'cgi'
|
|
require 'json'
|
|
|
|
begin; require 'glug' # Optional glug dependency
|
|
rescue LoadError; end # |
|
|
|
|
class MapServer
|
|
|
|
CONTENT_TYPES = {
|
|
json: "application/json",
|
|
png: "image/png",
|
|
pbf: "application/octet-stream",
|
|
css: "text/css",
|
|
js: "application/javascript"
|
|
}
|
|
|
|
EMPTY_TILE = ["1F8B0800FA78185E000393E2E3628F8F4FCD2D28A9D46850A86002006471443610000000"].pack('H*')
|
|
EMPTY_FONT = ["0A1F0A124D6574726F706F6C697320526567756C61721209313533362D31373931"].pack('H*')
|
|
|
|
def initialize(mbtiles, max_age=604800)
|
|
@@mbtiles = mbtiles
|
|
@@max_age = max_age
|
|
MapServer.connect
|
|
end
|
|
|
|
def self.connect
|
|
@@db = SQLite3::Database.new(@@mbtiles)
|
|
Dir.chdir("static") unless Dir.pwd.include?("static")
|
|
self
|
|
end
|
|
|
|
def read_metadata
|
|
md = {}
|
|
@@db.execute("SELECT name,value FROM metadata").each do |row|
|
|
k,v = row
|
|
md[k] = k=='json' ? JSON.parse(v) : v
|
|
end
|
|
md
|
|
end
|
|
|
|
def call(env)
|
|
path = CGI.unescape( (env['REQUEST_PATH'] || env['REQUEST_URI']).sub(/^\//,'') )
|
|
if path.empty? then path='index.html' end
|
|
|
|
if path =~ %r!^/?(\d+)/(\d+)/(\d+).*\.pbf!
|
|
# Serve .pbf tile from mbtiles
|
|
z,x,y = $1.to_i, $2.to_i, $3.to_i
|
|
tms_y = 2**z - y - 1
|
|
res = @@db.execute("SELECT tile_data FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?", [z, x, tms_y])
|
|
blob = res.length==0 ? EMPTY_TILE : res[0][0]
|
|
['200', {
|
|
'Content-Type' => 'application/x-protobuf',
|
|
'Content-Encoding'=> 'gzip',
|
|
'Content-Length' => blob.bytesize.to_s,
|
|
'Cache-Control' => "max-age=#{@@max_age}",
|
|
'Access-Control-Allow-Origin' => '*'
|
|
}, [blob]]
|
|
|
|
elsif path=='metadata'
|
|
# Serve mbtiles metadata
|
|
['200', {'Content-Type' => 'application/json', 'Cache-Control' => "max-age=#{@@max_age}", 'Access-Control-Allow-Origin' => '*' }, [read_metadata.to_json]]
|
|
|
|
# elsif ARGV.include?(path.sub(/\.json$/,'.glug'))
|
|
# # Convert .glug style to .json
|
|
# # ****** fixme
|
|
# glug = Glug::Stylesheet.new { instance_eval(File.read( path.sub(/\.json$/,'.glug') )) }.to_json
|
|
# ['200', {'Content-Type' => 'application/json' }, [glug] ]
|
|
|
|
elsif File.exist?(path)
|
|
# Serve static file
|
|
ct = path.match(/\.(\w+)$/) ? (CONTENT_TYPES[$1.to_sym] || 'text/html') : 'text/html'
|
|
['200', {'Content-Type' => ct, 'Cache-Control' => "max-age=#{@@max_age}", 'Access-Control-Allow-Origin' => '*'}, [File.read(path)]]
|
|
|
|
elsif path=~/font.+\.pbf/
|
|
# Font not found so send dummy file
|
|
['200', {
|
|
'Content-Type' => 'application/x-protobuf',
|
|
'Content-Length' => EMPTY_FONT.bytesize.to_s,
|
|
'Access-Control-Allow-Origin' => '*'
|
|
}, [EMPTY_FONT]]
|
|
|
|
else
|
|
# Not found
|
|
puts "Couldn't find #{path}"
|
|
['404', {'Content-Type' => 'text/html'}, ["Resource at #{path} not found"]]
|
|
end
|
|
end
|
|
|
|
# Start server
|
|
|
|
if defined?(PhusionPassenger)
|
|
puts "Starting Passenger server"
|
|
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
if forked then MapServer.connect end
|
|
end
|
|
|
|
else
|
|
puts "Starting local server"
|
|
require 'rackup'
|
|
|
|
server = MapServer.new(ARGV[0],0)
|
|
app = Proc.new { |env| server.call(env) }
|
|
Rackup::Handler::WEBrick.run(app)
|
|
end
|
|
end
|