require "sinatra/base" require "sinatra/json" require_relative "lib/maptool/gpx" require_relative "lib/maptool/gpx_store" module Maptool class App < Sinatra::Base set :public_folder, File.join(__dir__, "public") set :views, File.join(__dir__, "views") OFFLINE_PMTILES_PATH = File.join(__dir__, "data", "offline.pmtiles") GPX_STORE = GpxStore.new(File.join(__dir__, "data", "gpx")) get "/" do erb :index end get "/api/health" do json status: "ok" end get "/api/offline-tiles" do json available: File.exist?(OFFLINE_PMTILES_PATH) end # Served as a plain range-request-capable file, not decoded server-side: # pmtiles.js reads the archive's directory and fetches only the byte # ranges it needs for the tiles currently on screen. get "/tiles/offline.pmtiles" do halt 404 unless File.exist?(OFFLINE_PMTILES_PATH) send_file OFFLINE_PMTILES_PATH, type: "application/octet-stream" end get "/api/gpx/tree" do json GPX_STORE.tree end post "/api/gpx" do file = params[:file] halt 400, json(error: "file is required") unless file && file[:tempfile] begin path = GPX_STORE.save(folder: params[:folder].to_s, filename: file[:filename], io: file[:tempfile]) rescue GpxStore::InvalidPath halt 400, json(error: "invalid folder") end json path: path, tree: GPX_STORE.tree end get "/api/gpx/file/*" do begin path = GPX_STORE.resolve_file(params[:splat].first) rescue GpxStore::InvalidPath halt 400 end halt 404 unless File.file?(path) begin json Gpx.to_geojson(path) rescue Gpx::ParseError halt 422, json(error: "could not parse GPX file") end end post "/api/gpx/folder" do begin GPX_STORE.create_folder(params[:path].to_s) rescue GpxStore::InvalidPath halt 400, json(error: "invalid path") end json tree: GPX_STORE.tree end delete "/api/gpx/file/*" do begin GPX_STORE.delete_file(params[:splat].first) rescue GpxStore::InvalidPath halt 400 rescue Errno::ENOENT halt 404 end json tree: GPX_STORE.tree end delete "/api/gpx/folder/*" do begin GPX_STORE.delete_folder(params[:splat].first) rescue GpxStore::InvalidPath halt 400 rescue Errno::ENOENT halt 404 end json tree: GPX_STORE.tree end post "/api/gpx/move" do begin path = GPX_STORE.move(from: params[:from].to_s, to_folder: params[:to_folder].to_s) rescue GpxStore::InvalidPath halt 400, json(error: "invalid path") rescue Errno::ENOENT halt 404 end json path: path, tree: GPX_STORE.tree end end end