diff --git a/.env.sample b/.env.sample index 4ea839e..87cbab9 100644 --- a/.env.sample +++ b/.env.sample @@ -63,3 +63,10 @@ EXPORT_GEOJSON_STREAM_BATCH_CAP=200 # Max batch size for streaming # Metrics endpoint access control (comma-separated IPs/CIDRs) METRICS_ALLOWED_IPS=127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,::1 + +# Self-hosted routing engines (POI distance calculator) +OSRM_FOOT_URL=http://osrm-foot:5000 # OSRM walking profile +OSRM_BICYCLE_URL=http://osrm-bicycle:5000 # OSRM cycling profile +OTP_URL=http://otp:8080 # OpenTripPlanner for transit +OSRM_BATCH_SIZE=50 # Origins per OSRM /table request +OTP_MAX_CONCURRENT=10 # Max concurrent OTP requests diff --git a/docker-compose.yml b/docker-compose.yml index e0f4eb0..2b631bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -140,6 +140,45 @@ services: networks: - rec-network + osrm-foot: + image: ghcr.io/project-osrm/osrm-backend:latest + container_name: rec-osrm-foot + command: ["osrm-routed", "--algorithm", "MLD", "/data/foot/greater-london-latest.osrm"] + volumes: + - osrm_data:/data + ports: + - "5100:5000" + networks: + - rec-network + profiles: + - routing + + osrm-bicycle: + image: ghcr.io/project-osrm/osrm-backend:latest + container_name: rec-osrm-bicycle + command: ["osrm-routed", "--algorithm", "MLD", "/data/bicycle/greater-london-latest.osrm"] + volumes: + - osrm_data:/data + ports: + - "5101:5000" + networks: + - rec-network + profiles: + - routing + + otp: + image: opentripplanner/opentripplanner:2.6.0 + container_name: rec-otp + command: ["--load", "--serve"] + volumes: + - otp_data:/var/opentripplanner + ports: + - "8080:8080" + networks: + - rec-network + profiles: + - routing + networks: rec-network: driver: bridge @@ -150,3 +189,5 @@ volumes: app_venv: frontend_node_modules: caddy_data: + osrm_data: + otp_data: diff --git a/scripts/osrm-setup.sh b/scripts/osrm-setup.sh new file mode 100755 index 0000000..d61d1ef --- /dev/null +++ b/scripts/osrm-setup.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# OSRM data setup script for Greater London +# Downloads OSM extract and pre-processes for foot and bicycle profiles. +# +# Usage: +# ./scripts/osrm-setup.sh [DATA_DIR] +# +# DATA_DIR defaults to ./osrm-data/ +# The processed data is suitable for mounting into OSRM Docker containers. + +set -euo pipefail + +DATA_DIR="${1:-./osrm-data}" +GEOFABRIK_URL="https://download.geofabrik.de/europe/great-britain/england/greater-london-latest.osm.pbf" +OSM_FILE="greater-london-latest.osm.pbf" +OSRM_IMAGE="ghcr.io/project-osrm/osrm-backend:latest" + +echo "==> OSRM Setup for Greater London" +echo " Data directory: ${DATA_DIR}" + +mkdir -p "${DATA_DIR}/foot" "${DATA_DIR}/bicycle" + +# Download OSM extract if not present +if [ ! -f "${DATA_DIR}/${OSM_FILE}" ]; then + echo "==> Downloading Greater London OSM extract..." + curl -L -o "${DATA_DIR}/${OSM_FILE}" "${GEOFABRIK_URL}" +else + echo "==> OSM extract already downloaded" +fi + +# Process for foot profile +if [ ! -f "${DATA_DIR}/foot/greater-london-latest.osrm" ]; then + echo "==> Processing foot profile..." + cp "${DATA_DIR}/${OSM_FILE}" "${DATA_DIR}/foot/${OSM_FILE}" + + docker run --rm -v "${DATA_DIR}/foot:/data" "${OSRM_IMAGE}" \ + osrm-extract -p /opt/foot.lua "/data/${OSM_FILE}" + + docker run --rm -v "${DATA_DIR}/foot:/data" "${OSRM_IMAGE}" \ + osrm-partition "/data/greater-london-latest.osrm" + + docker run --rm -v "${DATA_DIR}/foot:/data" "${OSRM_IMAGE}" \ + osrm-customize "/data/greater-london-latest.osrm" + + # Clean up the source PBF from the profile dir + rm -f "${DATA_DIR}/foot/${OSM_FILE}" + echo "==> Foot profile ready" +else + echo "==> Foot profile already processed" +fi + +# Process for bicycle profile +if [ ! -f "${DATA_DIR}/bicycle/greater-london-latest.osrm" ]; then + echo "==> Processing bicycle profile..." + cp "${DATA_DIR}/${OSM_FILE}" "${DATA_DIR}/bicycle/${OSM_FILE}" + + docker run --rm -v "${DATA_DIR}/bicycle:/data" "${OSRM_IMAGE}" \ + osrm-extract -p /opt/bicycle.lua "/data/${OSM_FILE}" + + docker run --rm -v "${DATA_DIR}/bicycle:/data" "${OSRM_IMAGE}" \ + osrm-partition "/data/greater-london-latest.osrm" + + docker run --rm -v "${DATA_DIR}/bicycle:/data" "${OSRM_IMAGE}" \ + osrm-customize "/data/greater-london-latest.osrm" + + rm -f "${DATA_DIR}/bicycle/${OSM_FILE}" + echo "==> Bicycle profile ready" +else + echo "==> Bicycle profile already processed" +fi + +echo "" +echo "==> OSRM setup complete!" +echo " Mount ${DATA_DIR} as /data in OSRM containers." +echo "" +echo " Example:" +echo " docker run -p 5100:5000 -v ${DATA_DIR}:/data ${OSRM_IMAGE} \\" +echo " osrm-routed --algorithm MLD /data/foot/greater-london-latest.osrm" diff --git a/scripts/otp-setup.sh b/scripts/otp-setup.sh new file mode 100755 index 0000000..99dad89 --- /dev/null +++ b/scripts/otp-setup.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# OpenTripPlanner data setup script for Greater London +# Downloads OSM extract and TfL GTFS feeds for transit routing. +# +# Usage: +# ./scripts/otp-setup.sh [DATA_DIR] +# +# DATA_DIR defaults to ./otp-data/ +# The directory is suitable for mounting as /var/opentripplanner in OTP container. + +set -euo pipefail + +DATA_DIR="${1:-./otp-data}" +GEOFABRIK_URL="https://download.geofabrik.de/europe/great-britain/england/greater-london-latest.osm.pbf" +OSM_FILE="greater-london-latest.osm.pbf" + +# TfL GTFS feeds (Bus Open Data Service + TfL open data) +# These URLs may need updating; check https://data.bus-data.dft.gov.uk/ and TfL API +TFL_GTFS_URLS=( + "https://data.bus-data.dft.gov.uk/timetable/download/gtfs-file/london/" +) + +echo "==> OTP Setup for Greater London" +echo " Data directory: ${DATA_DIR}" + +mkdir -p "${DATA_DIR}" + +# Download OSM extract +if [ ! -f "${DATA_DIR}/${OSM_FILE}" ]; then + echo "==> Downloading Greater London OSM extract..." + curl -L -o "${DATA_DIR}/${OSM_FILE}" "${GEOFABRIK_URL}" +else + echo "==> OSM extract already downloaded" +fi + +# Download GTFS feeds +for i in "${!TFL_GTFS_URLS[@]}"; do + GTFS_FILE="gtfs-london-${i}.zip" + if [ ! -f "${DATA_DIR}/${GTFS_FILE}" ]; then + echo "==> Downloading GTFS feed ${i}..." + curl -L -o "${DATA_DIR}/${GTFS_FILE}" "${TFL_GTFS_URLS[$i]}" || { + echo " WARNING: Failed to download GTFS feed from ${TFL_GTFS_URLS[$i]}" + echo " You may need to manually download GTFS data." + echo " Check: https://data.bus-data.dft.gov.uk/" + echo " Place .zip files in ${DATA_DIR}/" + } + else + echo "==> GTFS feed ${i} already downloaded" + fi +done + +# Create OTP build config if not present +if [ ! -f "${DATA_DIR}/build-config.json" ]; then + echo "==> Creating OTP build config..." + cat > "${DATA_DIR}/build-config.json" << 'EOF' +{ + "osm": [ + { + "source": "greater-london-latest.osm.pbf" + } + ], + "transitFeeds": [ + { + "type": "gtfs", + "source": "gtfs-london-0.zip" + } + ] +} +EOF +fi + +# Create OTP router config if not present +if [ ! -f "${DATA_DIR}/router-config.json" ]; then + echo "==> Creating OTP router config..." + cat > "${DATA_DIR}/router-config.json" << 'EOF' +{ + "routingDefaults": { + "walkSpeed": 1.3, + "bikeSpeed": 5.0, + "numItineraries": 3 + } +} +EOF +fi + +echo "" +echo "==> OTP setup complete!" +echo " Mount ${DATA_DIR} as /var/opentripplanner in OTP container." +echo "" +echo " OTP will build the transit graph on first startup (~2 min for London)." +echo "" +echo " Example:" +echo " docker run -p 8080:8080 -v ${DATA_DIR}:/var/opentripplanner \\" +echo " opentripplanner/opentripplanner:2.6.0 --load --serve"