106 lines
4.6 KiB
Python
Executable File
106 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse
|
|
|
|
def parse_args():
|
|
p=argparse.ArgumentParser(description="CM95 MySQL vs PostgreSQL PBF comparison server")
|
|
p.add_argument("--host",default="0.0.0.0")
|
|
p.add_argument("--port",type=int,default=18889)
|
|
p.add_argument("--mysql-pbf-root",required=True)
|
|
p.add_argument("--postgres-pbf-root",required=True)
|
|
p.add_argument("--mysql-release",default="mysql-current")
|
|
p.add_argument("--postgres-release",default="postgres-current")
|
|
return p.parse_args()
|
|
|
|
def sha256(path: Path) -> str:
|
|
h=hashlib.sha256()
|
|
with path.open("rb") as f:
|
|
for b in iter(lambda:f.read(1024*1024),b""):
|
|
h.update(b)
|
|
return h.hexdigest()
|
|
|
|
def pbf_inventory(root: Path):
|
|
return {str(p.relative_to(root)):p for p in root.rglob("*.pbf") if p.is_file()}
|
|
|
|
def main():
|
|
args=parse_args()
|
|
web=Path(__file__).resolve().parent
|
|
mysql_root=Path(args.mysql_pbf_root).resolve()
|
|
pg_root=Path(args.postgres_pbf_root).resolve()
|
|
html=web/"mysql_postgresql_compare_north_kyushu.html"
|
|
style=web/"resources/style.s52.json"
|
|
assets=web/"assets"
|
|
resources=web/"resources"
|
|
for p in [mysql_root,pg_root,html,style,assets/"maplibre-gl.js",assets/"maplibre-gl.css",resources/"sprite.json",resources/"sprite.png"]:
|
|
if not p.exists():
|
|
raise SystemExit(f"missing: {p}")
|
|
mi=pbf_inventory(mysql_root)
|
|
pi=pbf_inventory(pg_root)
|
|
common=sorted(set(mi)&set(pi))
|
|
identical=0
|
|
different=[]
|
|
for rel in common:
|
|
if mi[rel].stat().st_size==pi[rel].stat().st_size and sha256(mi[rel])==sha256(pi[rel]):
|
|
identical+=1
|
|
elif len(different)<50:
|
|
different.append(rel)
|
|
info={
|
|
"mysql":{"release":args.mysql_release,"files":len(mi),"root":str(mysql_root)},
|
|
"postgresql":{"release":args.postgres_release,"files":len(pi),"root":str(pg_root)},
|
|
"compare":{"common":len(common),"identical":identical,"different":len(common)-identical,"different_examples":different},
|
|
}
|
|
|
|
class Handler(BaseHTTPRequestHandler):
|
|
def send(self,data:bytes,ctype:str,status=200):
|
|
self.send_response(status)
|
|
self.send_header("Content-Type",ctype)
|
|
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 serve_file(self,path:Path,ctype:str):
|
|
if not path.is_file():
|
|
self.send_error(404)
|
|
return
|
|
self.send(path.read_bytes(),ctype)
|
|
def do_GET(self):
|
|
path=urlparse(self.path).path
|
|
if path in ("/","/index.html","/compare"):
|
|
return self.serve_file(html,"text/html; charset=utf-8")
|
|
if path=="/api/info":
|
|
return self.send(json.dumps(info,ensure_ascii=False,indent=2).encode(),"application/json; charset=utf-8")
|
|
if path=="/style.json":
|
|
return self.serve_file(style,"application/json; charset=utf-8")
|
|
if path in ("/assets/maplibre-gl.js","/assets/maplibre-gl.css"):
|
|
fn=path.rsplit("/",1)[-1]
|
|
ct="application/javascript; charset=utf-8" if fn.endswith(".js") else "text/css; charset=utf-8"
|
|
return self.serve_file(assets/fn,ct)
|
|
if path in ("/sprite.json","/sprite.png","/sprite@2x.json","/sprite@2x.png"):
|
|
fn=path[1:]
|
|
ct="application/json; charset=utf-8" if fn.endswith(".json") else "image/png"
|
|
return self.serve_file(resources/fn,ct)
|
|
for prefix,root in (("/mysql/",mysql_root),("/postgres/",pg_root)):
|
|
if path.startswith(prefix) and path.endswith(".pbf"):
|
|
rel=path[len(prefix):]
|
|
parts=rel.split("/")
|
|
if len(parts)!=3 or not all(x.isdigit() for x in [parts[0],parts[1],parts[2][:-4]]):
|
|
self.send_error(404); return
|
|
return self.serve_file(root/rel,"application/vnd.mapbox-vector-tile")
|
|
self.send_error(404)
|
|
def log_message(self,fmt,*args):
|
|
pass
|
|
|
|
print(json.dumps(info,ensure_ascii=False,indent=2))
|
|
print(f"Compare: http://{args.host}:{args.port}/")
|
|
ThreadingHTTPServer((args.host,args.port),Handler).serve_forever()
|
|
|
|
if __name__=="__main__":
|
|
main()
|