Agencies, regions

This commit is contained in:
Csaba 2024-05-09 16:23:51 +02:00
parent d610699f9f
commit aaa9aa4e09
3 changed files with 91 additions and 39 deletions

View file

@ -12,6 +12,7 @@ import schedule
import threading import threading
import time import time
import logging import logging
import os
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
from .models.Carpool import Carpool, Region from .models.Carpool import Carpool, Region
@ -19,8 +20,8 @@ from .router import _assert_region_exists
from .services import stops #TODO: make stop service its own package?? from .services import stops #TODO: make stop service its own package??
from .services.trips import TripStore, Trip from .services.trips import TripStore, Trip
from .services.carpools import CarpoolService from .services.carpools import CarpoolService
from amarillo.services.agencies import AgencyService from .services.agencies import AgencyService
from amarillo.services.regions import RegionService from .services.regions import RegionService
from amarillo.utils.utils import agency_carpool_ids_from_filename from amarillo.utils.utils import agency_carpool_ids_from_filename
@ -53,6 +54,11 @@ class EventHandler(FileSystemEventHandler):
def init(): def init():
logger.info(f"Current working directory is {os.path.abspath(os.getcwd())}")
if not os.path.isdir('data/agency'):
logger.error(f'{os.path.abspath("data/agency")} directory does not exist')
container['agencies'] = AgencyService() container['agencies'] = AgencyService()
logger.info("Loaded %d agencies", len(container['agencies'].agencies)) logger.info("Loaded %d agencies", len(container['agencies'].agencies))
@ -76,12 +82,13 @@ def init():
logger.info("Restore carpools...") logger.info("Restore carpools...")
for agency_id in container['agencies'].agencies: for agency_id in container['agencies'].agencies:
for carpool_file_name in glob(f'data/carpool/{agency_id}/*.json'): for carpool_file_name in glob(f'data/enhanced/{agency_id}/*.json'):
try: try:
with open(carpool_file_name) as carpool_file: with open(carpool_file_name) as carpool_file:
carpool = Carpool(**(json.load(carpool_file))) carpool = Carpool(**(json.load(carpool_file)))
#TODO: convert to trip and add to tripstore directly #TODO: convert to trip and add to tripstore directly
container['carpools'].put(carpool.agency, carpool.id, carpool) container['carpools'].put(carpool.agency, carpool.id, carpool)
logger.info(f"Restored carpool {carpool_file_name}")
except Exception as e: except Exception as e:
logger.warning("Issue during restore of carpool %s: %s", carpool_file_name, repr(e)) logger.warning("Issue during restore of carpool %s: %s", carpool_file_name, repr(e))
@ -90,21 +97,21 @@ def init():
observer.schedule(EventHandler(), 'data/enhanced', recursive=True) observer.schedule(EventHandler(), 'data/enhanced', recursive=True)
observer.start() observer.start()
def run_schedule(): # def run_schedule():
while 1: # while 1:
try: # try:
schedule.run_pending() # schedule.run_pending()
except Exception as e: # except Exception as e:
logger.exception(e) # logger.exception(e)
time.sleep(1) # time.sleep(1)
def midnight(): # def midnight():
container['stops_store'].load_stop_sources() # container['stops_store'].load_stop_sources()
# container['trips_store'].unflag_unrecent_updates() # # container['trips_store'].unflag_unrecent_updates()
# container['carpools'].purge_outdated_offers() # # container['carpools'].purge_outdated_offers()
generate_gtfs() # generate_gtfs()
#TODO: generate for a specific region only #TODO: generate for a specific region only
#TODO: what happens when there are no trips? #TODO: what happens when there are no trips?
@ -128,20 +135,20 @@ def generate_gtfs_rt():
for region in container['regions'].regions.values(): for region in container['regions'].regions.values():
rt = producer.export_feed(time.time(), f"data/gtfs/amarillo.{region.id}.gtfsrt", bbox=region.bbox) rt = producer.export_feed(time.time(), f"data/gtfs/amarillo.{region.id}.gtfsrt", bbox=region.bbox)
def start_schedule(): # def start_schedule():
schedule.every().day.at("00:00").do(midnight) # # schedule.every().day.at("00:00").do(midnight)
schedule.every(60).seconds.do(generate_gtfs_rt) # schedule.every(60).seconds.do(generate_gtfs_rt)
# Create all feeds once at startup # # Create all feeds once at startup
schedule.run_all() # schedule.run_all()
job_thread = threading.Thread(target=run_schedule, daemon=True) # job_thread = threading.Thread(target=run_schedule, daemon=True)
job_thread.start() # job_thread.start()
def setup(app : FastAPI): # def setup(app : FastAPI):
# TODO: Create all feeds once at startup # # TODO: Create all feeds once at startup
# configure_enhancer_services() # # configure_enhancer_services()
# app.include_router(router) # # app.include_router(router)
# start_schedule() # # start_schedule()
pass # pass
logging.config.fileConfig('logging.conf', disable_existing_loggers=False) logging.config.fileConfig('logging.conf', disable_existing_loggers=False)
logger = logging.getLogger("gtfs-generator") logger = logging.getLogger("gtfs-generator")
@ -243,9 +250,9 @@ async def get_file(region_id: str):
# verify_permission("gtfs", requesting_user) # verify_permission("gtfs", requesting_user)
return FileResponse(f'data/gtfs/amarillo.{region_id}.gtfs.zip') return FileResponse(f'data/gtfs/amarillo.{region_id}.gtfs.zip')
@app.get("/region/{region_id}/grfs-rt/", @app.get("/region/{region_id}/gtfs-rt/",
summary="Return GRFS-RT Feed for this region", summary="Return GTFS-RT Feed for this region",
response_description="GRFS-RT-Feed", response_description="GTFS-RT-Feed",
response_class=FileResponse, response_class=FileResponse,
responses={ responses={
status.HTTP_404_NOT_FOUND: {"description": "Region not found"}, status.HTTP_404_NOT_FOUND: {"description": "Region not found"},
@ -256,20 +263,20 @@ async def get_file(region_id: str, format: str = 'protobuf'):
generate_gtfs_rt() generate_gtfs_rt()
_assert_region_exists(region_id) _assert_region_exists(region_id)
if format == 'json': if format == 'json':
return FileResponse(f'data/grfs/amarillo.{region_id}.gtfsrt.json') return FileResponse(f'data/gtfs/amarillo.{region_id}.gtfsrt.json')
elif format == 'protobuf': elif format == 'protobuf':
return FileResponse(f'data/grfs/amarillo.{region_id}.gtfsrt.pbf') return FileResponse(f'data/gtfs/amarillo.{region_id}.gtfsrt.pbf')
else: else:
message = "Specified format is not supported, i.e. neither protobuf nor json." message = "Specified format is not supported, i.e. neither protobuf nor json."
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)
#TODO: sync endpoint that calls midnight #TODO: sync endpoint that calls midnight
@app.post("/sync", # @app.post("/sync",
operation_id="sync") # operation_id="sync")
#TODO: add examples # #TODO: add examples
async def post_sync(): # async def post_sync():
logger.info(f"Sync") # logger.info(f"Sync")
midnight() # midnight()

View file

@ -0,0 +1,24 @@
import json
from glob import glob
from typing import Dict
from amarillo.models.Carpool import Agency
# TODO FG HB this service should also listen to pyinotify
# because the (updated) agencies are needed in the enhancer
# as well.
class AgencyService:
def __init__(self):
self.agencies: Dict[str, Agency] = {}
for agency_file_name in glob('data/agency/*.json'):
with open(agency_file_name) as agency_file:
dict = json.load(agency_file)
agency = Agency(**dict)
agency_id = agency.id
self.agencies[agency_id] = agency
def get_agency(self, agency_id: str) -> Agency:
agency = self.agencies.get(agency_id)
return agency

View file

@ -0,0 +1,21 @@
import json
from glob import glob
from typing import Dict
from amarillo.models.Carpool import Region
class RegionService:
def __init__(self):
self.regions: Dict[str, Region] = {}
for region_file_name in glob('data/region/*.json'):
with open(region_file_name) as region_file:
dict = json.load(region_file)
region = Region(**dict)
region_id = region.id
self.regions[region_id] = region
def get_region(self, region_id: str) -> Region:
region = self.regions.get(region_id)
return region