2021-11-14 11:52:44 +01:00
import collections
2021-11-09 13:56:42 +01:00
import re
2021-11-14 11:52:44 +01:00
from typing import DefaultDict , Dict , List , Optional , Tuple
2021-11-09 12:33:52 +01:00
import httpx
2021-11-09 12:33:18 +01:00
from fastapi import FastAPI , HTTPException
2021-11-12 15:58:03 +01:00
from fastapi . middleware . cors import CORSMiddleware
2021-11-09 12:50:21 +01:00
from fastapi . params import Header , Path
2021-11-09 12:33:18 +01:00
from pydantic import BaseModel
app = FastAPI ( )
2021-11-12 15:58:03 +01:00
origins = [ " http://localhost:3000 " , " https://display.augendre.info " ]
app . add_middleware (
CORSMiddleware ,
allow_origins = origins ,
allow_credentials = True ,
allow_methods = [ " * " ] ,
allow_headers = [ " * " ] ,
)
2021-11-09 12:33:52 +01:00
2021-11-14 11:52:44 +01:00
class Stop ( BaseModel ) :
id : int
name : str
2021-11-09 12:33:18 +01:00
class Passage ( BaseModel ) :
ligne : str
2021-11-09 13:44:40 +01:00
delais : List [ str ]
2021-11-14 11:52:44 +01:00
destination : Stop
2021-11-09 12:33:18 +01:00
2021-11-09 12:33:52 +01:00
2021-11-09 12:33:18 +01:00
class Passages ( BaseModel ) :
passages : List [ Passage ]
2021-11-14 11:52:44 +01:00
stop : Stop
2021-11-09 12:33:18 +01:00
2021-11-09 12:33:52 +01:00
2021-11-09 12:33:18 +01:00
@app.get ( " /stop/ {stop_id} " , response_model = Passages )
2021-11-09 12:50:21 +01:00
async def stop (
stop_id : int = Path (
None ,
description = " Stop id to monitor. Can be obtained using https://data.grandlyon.com/jeux-de-donnees/points-arret-reseau-transports-commun-lyonnais/donnees " ,
) ,
authorization : Optional [ str ] = Header (
None ,
alias = " Authorization " ,
description = " Basic auth for remote API (data grand lyon) " ,
) ,
) :
2021-11-14 11:52:44 +01:00
monitored_stop_id = stop_id
2021-11-09 12:33:18 +01:00
if authorization is None :
raise HTTPException ( status_code = 401 , detail = " Not authenticated " )
2021-11-09 12:33:52 +01:00
headers = { " Authorization " : authorization }
2021-11-09 12:33:18 +01:00
async with httpx . AsyncClient ( headers = headers ) as client :
2021-11-14 11:52:44 +01:00
passages_res = client . get (
2021-11-09 12:33:52 +01:00
" https://download.data.grandlyon.com/ws/rdata/tcl_sytral.tclpassagearret/all.json?maxfeatures=-1 "
)
2021-11-14 11:52:44 +01:00
infos_res = client . get (
" https://download.data.grandlyon.com/ws/rdata/tcl_sytral.tclarret/all.json?maxfeatures=-1 "
)
passages_res = await passages_res
infos_res = await infos_res
if passages_res . status_code != 200 :
raise HTTPException (
status_code = passages_res . status_code ,
detail = " HTTP error during call to remote API " ,
)
if infos_res . status_code != 200 :
2021-11-09 12:33:52 +01:00
raise HTTPException (
2021-11-14 11:52:44 +01:00
status_code = infos_res . status_code ,
2021-11-09 12:33:52 +01:00
detail = " HTTP error during call to remote API " ,
)
2021-11-14 11:52:44 +01:00
stop_ids = { monitored_stop_id }
passages : Dict [ Tuple [ str , int ] , list ] = collections . defaultdict ( list )
for passage in passages_res . json ( ) . get ( " values " ) :
if passage . get ( " id " ) == monitored_stop_id :
2021-11-09 13:56:42 +01:00
ligne = passage . get ( " ligne " )
ligne = re . sub (
" [A-Z]$ " , " " , ligne
) # Remove letter suffix to group by commercial line name
2021-11-14 11:52:44 +01:00
destination = passage . get ( " idtarretdestination " )
passages [ ( ligne , destination ) ] . append ( passage . get ( " delaipassage " ) )
stop_ids . add ( destination )
stop_infos : Dict [ int , Stop ] = { }
for info in infos_res . json ( ) . get ( " values " ) :
stop_id = info . get ( " id " )
if stop_id in stop_ids :
stop_infos [ stop_id ] = Stop ( id = stop_id , name = info . get ( " nom " ) )
if len ( stop_infos ) == len ( stop_ids ) :
break
2021-11-09 13:44:40 +01:00
passages_list = [ ]
2021-11-14 11:52:44 +01:00
for key , delais in passages . items ( ) :
passages_list . append (
Passage ( ligne = key [ 0 ] , delais = delais , destination = stop_infos . get ( key [ 1 ] ) )
)
return Passages ( passages = passages_list , stop = stop_infos . get ( monitored_stop_id ) )