Files
CM95/web/cm95_web.py

141 lines
3.9 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from pathlib import Path
from urllib.parse import urlparse
def parse_args():
p = argparse.ArgumentParser(description="CM95 local PBF Web test server")
# This script is expected to live in:
# D:\React\cm93-mysql-importer-starter\web\
#
# Therefore the project root is automatically the parent directory.
p.add_argument(
"--release-id",
default="cm95-d1-62a85bd40d3a-6bc3c1352da3",
help="CM95 production release ID",
)
p.add_argument("--host", default="127.0.0.1")
p.add_argument("--port", type=int, default=8080)
return p.parse_args()
def main():
args = parse_args()
web_root = Path(__file__).resolve().parent
project_root = web_root.parent
release_dir = (
project_root
/ "build"
/ "releases"
/ args.release_id
)
pbf_root = release_dir / "pbf" / "delivery"
index_path = web_root / "index.html"
style_path = web_root / "style.json"
if not pbf_root.is_dir():
raise SystemExit(
"PBF directory not found:\n"
f"{pbf_root}\n\n"
"Expected project layout:\n"
f"{project_root}\\build\\releases\\{args.release_id}\\pbf\\delivery"
)
if not index_path.is_file():
raise SystemExit(f"index.html not found: {index_path}")
if not style_path.is_file():
raise SystemExit(f"style.json not found: {style_path}")
class Handler(BaseHTTPRequestHandler):
def send_bytes(self, data: bytes, content_type: str, status=200):
self.send_response(status)
self.send_header("Content-Type", content_type)
self.send_header("Content-Length", str(len(data)))
self.send_header("Cache-Control", "no-cache")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(data)
def do_GET(self):
path = urlparse(self.path).path
if path in ("/", "/index.html"):
self.send_bytes(
index_path.read_bytes(),
"text/html; charset=utf-8",
)
return
if path == "/style.json":
self.send_bytes(
style_path.read_bytes(),
"application/json; charset=utf-8",
)
return
if path.startswith("/pbf/") and path.endswith(".pbf"):
parts = path[len("/pbf/"):].split("/")
if len(parts) != 3:
self.send_error(404)
return
z, x, yfile = parts
y = yfile[:-4]
if not (z.isdigit() and x.isdigit() and y.isdigit()):
self.send_error(404)
return
pbf = pbf_root / z / x / yfile
if not pbf.is_file():
self.send_error(404, "PBF tile not found")
return
self.send_bytes(
pbf.read_bytes(),
"application/vnd.mapbox-vector-tile",
)
return
self.send_error(404)
def log_message(self, fmt, *args):
print(f"{self.address_string()} - {fmt % args}")
server = ThreadingHTTPServer((args.host, args.port), Handler)
print("")
print("CM95 Web Test")
print("=" * 70)
print(f"Project : {project_root}")
print(f"Web : {web_root}")
print(f"Release : {release_dir}")
print(f"PBF : {pbf_root}")
print(f"Style : {style_path}")
print(f"URL : http://{args.host}:{args.port}/")
print("")
print("Ctrl+C to stop.")
try:
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
server.server_close()
if __name__ == "__main__":
main()