1+ import os
2+ import json
3+ import asyncio
4+ from rapida .connectivity .runcli import run_cli
5+ from valhalla import get_config
6+ from valhalla .config import _sanitize_config , default_config
7+ from typing import Union
8+ from pathlib import Path
9+
10+
11+ def get_config_fixed (
12+ tile_extract : Union [str , Path ] = "valhalla_tiles.tar" ,
13+ tile_dir : Union [str , Path ] = "valhalla_tiles" ,
14+ verbose : bool = False ,
15+ ) -> dict :
16+ """
17+ Returns a default Valhalla configuration.
18+
19+ :param tile_extract: The file path (with .tar extension) of the tile extract (mjolnir.tile_extract), if present. Preferred over tile_dir.
20+ :param tile_dir: The directory path where the graph tiles are stored (mjolnir.tile_dir), if present.
21+ :param verbose: Whether you want to see Valhalla's logs on stdout (mjolnir.logging). Default False.
22+ """
23+
24+ config = _sanitize_config (default_config .copy ())
25+
26+ config ["mjolnir" ]["tile_dir" ] = (
27+ ""
28+ if isinstance (tile_dir , str ) and not str (tile_dir )
29+ else str (Path (tile_dir ).resolve (strict = True ))
30+ )
31+ config ["mjolnir" ]["tile_extract" ] = (
32+ ""
33+ if isinstance (tile_extract , str ) and not str (tile_extract )
34+ else str (Path (tile_extract ).resolve ())
35+ )
36+
37+ config ["logging" ]["type" ] = "std_out" if verbose else ""
38+
39+ return config
40+
41+
42+ async def compile_valhalla_graph (pbf_path : str , dst_dir : str , progress = None ) -> str :
43+ """
44+ Compiles the raw OSM PBF into a highly optimized Valhalla routing DAG.
45+ Offloads the C++ execution to a background thread to keep uvloop unblocked.
46+ """
47+ os .makedirs (dst_dir , exist_ok = True )
48+ tile_dir = os .path .join (dst_dir , "valhalla_tiles" )
49+ os .makedirs (tile_dir , exist_ok = True )
50+ tar_path = os .path .join (dst_dir , "valhalla_tiles.tar" )
51+ #os.makedirs(tar_path, exist_ok=True)
52+ config_path = os .path .join (dst_dir , "valhalla.json" )
53+
54+ # 1. Generate the Valhalla JSON configuration natively
55+ if progress :
56+ progress .console .print ("[cyan]Generating Valhalla engine configuration...[/cyan]" )
57+
58+ try :
59+ valhalla_conf = get_config (
60+ tile_dir = tile_dir ,
61+ tile_extract = tar_path ,
62+ verbose = False
63+ )
64+ except Exception :
65+ valhalla_conf = get_config_fixed (
66+ tile_dir = tile_dir ,
67+ tile_extract = tar_path ,
68+ verbose = False
69+ )
70+ # ---------------------------------------------------------
71+ # INJECT CUSTOM LIMITS BEFORE SAVING THE BUILD CONFIG
72+ # ---------------------------------------------------------
73+ if "service_limits" not in valhalla_conf :
74+ valhalla_conf ["service_limits" ] = {}
75+ if "isochrone" not in valhalla_conf ["service_limits" ]:
76+ valhalla_conf ["service_limits" ]["isochrone" ] = {}
77+
78+ # Expand the max_locations limit to allow system-wide bulk routing
79+ valhalla_conf ["service_limits" ]["isochrone" ]["max_locations" ] = 5000
80+ # ---------------------------------------------------------
81+
82+ with open (config_path , "w" ) as f :
83+ json .dump (valhalla_conf , f , indent = 4 )
84+
85+ # 2. Define the blocking C++ execution function
86+ def run_compiler ():
87+ # 1. Build the Admin Database
88+ # This parses country borders, timezones, and local driving rules (e.g., right vs left side of road)
89+ if progress :
90+ progress .console .print ("[cyan]Building admin rules database...[/cyan]" )
91+ run_cli ([
92+ "valhalla_build_admins" , "-c" , config_path , pbf_path
93+ ])
94+
95+ # 2. Build the Routing Tiles
96+ # This generates the actual mathematical DAG and writes it to the 'valhalla_tiles' folder
97+ if progress :
98+ progress .console .print ("[cyan]Building routing graph ...[/cyan]" )
99+ run_cli ([
100+ "valhalla_build_tiles" , "-c" , config_path , pbf_path
101+ ])
102+
103+ # 3. Compress into the Extract
104+ # This reads the generated folder and packs it into the high-performance memory-mapped .tar file
105+ if progress :
106+ progress .console .print ("[cyan]Compressing graph into a tarball...[/cyan]" )
107+ run_cli ([
108+ "valhalla_build_extract" , "-c" , config_path , "-v" , "--overwrite"
109+ ])
110+
111+ # 3. Offload compilation to a worker thread
112+ if progress :
113+ progress .console .print ("[cyan]Compiling binary DAG ...[/cyan]" )
114+
115+ await asyncio .to_thread (run_compiler )
116+
117+ if progress :
118+ progress .console .print (f"[bold green]✓ Valhalla DAG compiled successfully: { tar_path } [/bold green]" )
119+
120+ return tar_path
0 commit comments