wrongmove/config/routing_config.py
Viktor Barzin 41b7d221e4
Fix 7 bugs: security, memory leak, stale state, error handling
- WebSocket: verify task ownership before allowing subscribe (security)
- POI routes: replace assert with HTTPException for production safety
- cancel_task: return HTTP 404 instead of 200 for missing tasks
- routing_config: add descriptive ValueError for invalid env vars
- POIManager: show error feedback instead of silently swallowing failures
- VisualizationCard: reset POI/travel mode state on metric switch
- Map: clean up heatmap layers/sources on unmount to prevent memory leak
- Update test to expect 404 from cancel_task ownership check
2026-02-13 19:36:43 +00:00

61 lines
2.3 KiB
Python

"""Routing engine configuration with environment variable loading."""
from __future__ import annotations
import os
from dataclasses import dataclass
from typing import Self
def _int_env(name: str, default: str) -> int:
"""Parse an integer environment variable with a descriptive error."""
raw = os.environ.get(name, default)
try:
return int(raw)
except ValueError:
raise ValueError(f"Environment variable {name}={raw!r} must be an integer")
@dataclass(frozen=True)
class RoutingConfig:
"""Configuration for self-hosted routing engines (OSRM + OTP).
Attributes:
osrm_foot_url: URL for OSRM walking profile instance.
osrm_bicycle_url: URL for OSRM cycling profile instance.
otp_url: URL for OpenTripPlanner instance.
osrm_batch_size: Number of origins per OSRM /table request.
otp_max_concurrent: Max concurrent OTP requests.
"""
osrm_foot_url: str = "http://osrm-foot:5000"
osrm_bicycle_url: str = "http://osrm-bicycle:5000"
otp_url: str = "http://otp:8080"
osrm_batch_size: int = 50
otp_max_concurrent: int = 10
@classmethod
def from_env(cls) -> Self:
"""Load configuration from environment variables.
Environment variables:
OSRM_FOOT_URL: OSRM walking instance URL (default: http://osrm-foot:5000)
OSRM_BICYCLE_URL: OSRM cycling instance URL (default: http://osrm-bicycle:5000)
OTP_URL: OpenTripPlanner URL (default: http://otp:8080)
OSRM_BATCH_SIZE: Origins per /table request (default: 50)
OTP_MAX_CONCURRENT: Max concurrent OTP requests (default: 10)
"""
return cls(
osrm_foot_url=os.environ.get("OSRM_FOOT_URL", "http://osrm-foot:5000"),
osrm_bicycle_url=os.environ.get("OSRM_BICYCLE_URL", "http://osrm-bicycle:5000"),
otp_url=os.environ.get("OTP_URL", "http://otp:8080"),
osrm_batch_size=_int_env("OSRM_BATCH_SIZE", "50"),
otp_max_concurrent=_int_env("OTP_MAX_CONCURRENT", "10"),
)
def get_osrm_url(self, profile: str) -> str:
"""Get the OSRM URL for a given profile."""
if profile == "foot":
return self.osrm_foot_url
elif profile == "bicycle":
return self.osrm_bicycle_url
raise ValueError(f"Unknown OSRM profile: {profile}")