|
| 1 | +import json |
| 2 | +import logging |
| 3 | +import os |
| 4 | +from io import BytesIO |
| 5 | + |
| 6 | +import folium |
| 7 | +import requests |
| 8 | +from dotenv import load_dotenv |
| 9 | +from google.cloud import storage |
| 10 | + |
| 11 | +from reverse_geolocation_processor import reverse_geolocation_process |
| 12 | + |
| 13 | +HOST = "localhost" |
| 14 | +PORT = 9023 |
| 15 | +BUCKET_NAME = "verifier" |
| 16 | +feed_stable_id = "mdb-1" |
| 17 | + |
| 18 | +station_information_url = ( |
| 19 | + "https://data.rideflamingo.com/gbfs/3/auckland/station_information.json" |
| 20 | +) |
| 21 | +vehicle_status_url = "https://data.rideflamingo.com/gbfs/3/auckland/vehicle_status.json" |
| 22 | +free_bike_status_url = None |
| 23 | + |
| 24 | +# Load environment variables from .env.local |
| 25 | +load_dotenv(dotenv_path=".env.local") |
| 26 | + |
| 27 | + |
| 28 | +def download_to_local(url: str, filename: str): |
| 29 | + """ |
| 30 | + Download a file from a URL and upload it to the Google Cloud Storage emulator. |
| 31 | + If the file already exists, it will not be downloaded again. |
| 32 | + Args: |
| 33 | + url (str): The URL to download the file from. |
| 34 | + filename (str): The name of the file to save in the emulator. |
| 35 | + """ |
| 36 | + blob_path = f"{feed_stable_id}/{filename}" |
| 37 | + client = storage.Client() |
| 38 | + bucket = client.bucket(BUCKET_NAME) |
| 39 | + blob = bucket.blob(blob_path) |
| 40 | + |
| 41 | + # Check if the blob already exists in the emulator |
| 42 | + if not blob.exists(): |
| 43 | + logging.info(f"Downloading and uploading: {blob_path}") |
| 44 | + with requests.get(url, stream=True) as response: |
| 45 | + response.raise_for_status() |
| 46 | + blob.content_type = "application/json" |
| 47 | + # The file is downloaded into memory before uploading to ensure it's seekable. |
| 48 | + # Be careful with large files. |
| 49 | + data = BytesIO(response.content) |
| 50 | + blob.upload_from_file(data, rewind=True) |
| 51 | + else: |
| 52 | + logging.info(f"Blob already exists: gs://{BUCKET_NAME}/{blob_path}") |
| 53 | + |
| 54 | + |
| 55 | +if __name__ == "__main__": |
| 56 | + import geopandas as gpd |
| 57 | + from gcp_storage_emulator.server import create_server |
| 58 | + from flask import Flask, Request |
| 59 | + |
| 60 | + data = { |
| 61 | + "stable_id": feed_stable_id, |
| 62 | + "dataset_id": "example_dataset_id", |
| 63 | + "station_information_url": f"http://{HOST}:{PORT}/{BUCKET_NAME}/{feed_stable_id}/station_information.json", |
| 64 | + "vehicle_status_url": f"http://{HOST}:{PORT}/{BUCKET_NAME}/{feed_stable_id}/vehicle_status.json", |
| 65 | + "free_bike_status_url": free_bike_status_url, |
| 66 | + "strategy": "per-point", |
| 67 | + "data_type": "gbfs", |
| 68 | + "public": "False", |
| 69 | + } |
| 70 | + app = Flask(__name__) |
| 71 | + |
| 72 | + try: |
| 73 | + os.environ["STORAGE_EMULATOR_HOST"] = f"http://{HOST}:{PORT}" |
| 74 | + os.environ["DATASETS_BUCKET_NAME_GBFS"] = BUCKET_NAME |
| 75 | + os.environ["DATASETS_BUCKET_NAME_GTFS"] = BUCKET_NAME |
| 76 | + server = create_server( |
| 77 | + host=HOST, port=PORT, in_memory=False, default_bucket=BUCKET_NAME |
| 78 | + ) |
| 79 | + server.start() |
| 80 | + |
| 81 | + download_to_local( |
| 82 | + url=station_information_url, filename="station_information.json" |
| 83 | + ) |
| 84 | + download_to_local(url=vehicle_status_url, filename="vehicle_status.json") |
| 85 | + |
| 86 | + with app.test_request_context( |
| 87 | + path="/reverse_geolocation", |
| 88 | + method="POST", |
| 89 | + data=json.dumps(data), |
| 90 | + headers={"Content-Type": "application/json"}, |
| 91 | + ): |
| 92 | + request = Request.from_values( |
| 93 | + method="POST", |
| 94 | + path="/reverse_geolocation", |
| 95 | + data=json.dumps(data), |
| 96 | + headers={"Content-Type": "application/json"}, |
| 97 | + ) |
| 98 | + reverse_geolocation_process(request) |
| 99 | + |
| 100 | + # Visualize the resulting geojson file |
| 101 | + url = f"http://{HOST}:{PORT}/{BUCKET_NAME}/{feed_stable_id}/geolocation.geojson" |
| 102 | + gdf = gpd.read_file(url) |
| 103 | + |
| 104 | + # Calculate centroid for map center |
| 105 | + center = gdf.geometry.union_all().centroid |
| 106 | + m = folium.Map(location=[center.y, center.x], zoom_start=2) |
| 107 | + |
| 108 | + # Add GeoJSON overlay |
| 109 | + folium.GeoJson(gdf).add_to(m) |
| 110 | + |
| 111 | + # Automatically zoom to fit the full polygon bounds |
| 112 | + minx, miny, maxx, maxy = gdf.total_bounds |
| 113 | + m.fit_bounds([[miny, minx], [maxy, maxx]]) # [[south, west], [north, east]] |
| 114 | + |
| 115 | + # Save the map |
| 116 | + m.save(f".cloudstorage/verifier/{feed_stable_id}/geojson_map.html") |
| 117 | + except Exception as e: |
| 118 | + logging.error(f"Error verifying download content: {e}") |
| 119 | + finally: |
| 120 | + server.stop() |
0 commit comments