11import logging
2- from functools import lru_cache
3- from fastapi import Depends , FastAPI , Request
2+ from typing import Any
3+
4+ from fastapi import Depends , Request , FastAPI , HTTPException
45from httpx import HTTPStatusError
56from pytimeparse .timeparse import timeparse
6- from fastapi import HTTPException
77
88from adapter import init_adapter
9- from app import config
9+ from app . config import Settings
1010from app .report import init_db
11- from app .report .middlewares import CollectVerifyData , CollectRequestData
12- from app .report .models import Verify
11+ from app .report .middlewares import CollectRequestData
12+ from app .report .models import Verify , StatusReport , GatewayInfo
1313from app .utils .cache import Cache
14- from app .utils .types import VerifyErrorType
15- from app .utils .helper import is_allow_data_source_id , get_band_signature_hash , verify_request , get_band_signature_hash
14+ from app .utils .helper import is_data_source_id_allowed , verify_request_from_bandchain , get_band_signature_hash
1615from app .utils .log_config import init_loggers
16+ from app .utils .types import VerifyErrorType
1717
1818app = FastAPI ()
1919
20+ # Get setting
21+ settings = Settings ()
2022
21- @lru_cache ()
22- def get_settings ():
23- return config .Settings ()
24-
25-
26- settings = get_settings ()
27-
28- # create logger
23+ # Setup logger
2924init_loggers (log_level = settings .LOG_LEVEL )
3025log = logging .getLogger ("pds_gateway_log" )
31-
32-
3326log .info (f"GATEWAY_MODE: { settings .MODE } " )
3427
35-
36- app .state .cache_data = Cache (settings .CACHE_SIZE , timeparse (settings .TTL_TIME ))
28+ # Setup app state
29+ app .state .cache_data = Cache (settings .CACHE_SIZE , timeparse (settings .TTL ))
3730app .state .db = init_db (settings .MONGO_DB_URL , settings .COLLECTION_DB_NAME , log )
3831app .state .adapter = init_adapter (settings .ADAPTER_TYPE , settings .ADAPTER_NAME )
3932
4033
41- @CollectVerifyData (db = app .state .db )
42- async def verify (request : Request , settings : config .Settings = settings ):
43- if settings .MODE == "production" :
44- # pass verify if already cache
45- if app .state .cache_data .get_data (get_band_signature_hash (request .headers )):
46- return Verify (response_code = 200 , is_delay = False )
47-
48- verified = await verify_request (request .headers , settings .VERIFY_REQUEST_URL , settings .MAX_DELAY_VERIFICATION )
49-
50- if not is_allow_data_source_id (int (verified ["data_source_id" ]), settings .ALLOWED_DATA_SOURCE_IDS ):
51- raise HTTPException (
52- status_code = 401 ,
53- detail = {
54- "verify_error_type" : VerifyErrorType .UNSUPPORTED_DS_ID .value ,
55- "error_msg" : f'wrong data_source_id. expected { settings .ALLOWED_DATA_SOURCE_IDS } , got { verified ["data_source_id" ]} .' ,
56- },
34+ async def verify_request (req : Request ) -> Verify :
35+ """Verifies if the request originated from BandChain"""
36+ # Skip verification if request has already been cached
37+ if settings .MODE == "production" and app .state .cache_data .get_data (get_band_signature_hash (req .headers )):
38+ # Verify the request is from BandChain
39+ verified = await verify_request_from_bandchain (
40+ req .headers , settings .VERIFY_REQUEST_URL , settings .MAX_DELAY_VERIFICATION
41+ )
42+
43+ # Checks if the data source requesting is whitelisted
44+ if not is_data_source_id_allowed (int (verified ["data_source_id" ]), settings .ALLOWED_DATA_SOURCE_IDS ):
45+ return Verify (
46+ response_code = 401 ,
47+ is_delay = None ,
48+ error_type = VerifyErrorType .UNSUPPORTED_DS_ID .value ,
49+ error_msg = "wrong data_source_id. expected {allowed}, got {actual}." .format (
50+ allowed = settings .ALLOWED_DATA_SOURCE_IDS , actual = verified ["data_source_id" ]
51+ ),
5752 )
5853
5954 return Verify (response_code = 200 , is_delay = verified ["is_delay" ])
@@ -63,30 +58,26 @@ async def verify(request: Request, settings: config.Settings = settings):
6358
6459@app .get ("/" )
6560@CollectRequestData (db = app .state .db )
66- async def request (
67- request : Request , settings : config .Settings = Depends (get_settings ), verify : Verify = Depends (verify )
68- ):
61+ async def request_data (request : Request , verify : Verify = Depends (verify_request )) -> Any :
62+ """Requests data from the premium data source"""
63+ assert verify
64+
6965 if settings .MODE == "production" :
70- # get cache data
71- latest_data = app .state .cache_data .get_data (get_band_signature_hash (request .headers ))
72- if latest_data :
73- latest_data ["cached_data" ] = True
66+ # Get cached data and if it exists return it
67+ if latest_data := app .state .cache_data .get_data (get_band_signature_hash (request .headers )):
7468 return latest_data
7569
7670 try :
7771 output = await app .state .adapter .unified_call (dict (request .query_params ))
7872 if settings .MODE == "production" :
79- # cache data
73+ # Cache data
8074 app .state .cache_data .set_data (get_band_signature_hash (request .headers ), output )
81-
8275 return output
83-
8476 except HTTPStatusError as e :
8577 raise HTTPException (
8678 status_code = e .response .status_code ,
8779 detail = {"error_msg" : f"{ e } " },
8880 )
89-
9081 except Exception as e :
9182 raise HTTPException (
9283 status_code = 500 ,
@@ -95,21 +86,23 @@ async def request(
9586
9687
9788@app .get ("/status" )
98- async def get_report_status (settings : config .Settings = Depends (get_settings )):
99- res = {
100- "gateway_info" : {
101- "allow_data_source_ids" : settings .ALLOWED_DATA_SOURCE_IDS ,
102- "max_delay_verification" : settings .MAX_DELAY_VERIFICATION ,
103- }
104- }
89+ async def get_status_report () -> StatusReport :
90+ """Gets a status report: gateway info, latest request and latest failed request"""
91+ gateway_info = GatewayInfo (
92+ allow_data_source_ids = settings .ALLOWED_DATA_SOURCE_IDS ,
93+ max_delay_verification = settings .MAX_DELAY_VERIFICATION ,
94+ )
10595
10696 if app .state .db :
10797 try :
108- res ["latest_request" ] = await app .state .db .get_latest_request_info ()
109- res ["latest_failed_request" ] = await app .state .db .get_latest_verify_failed ()
110-
111- return res
98+ latest_request = await app .state .db .get_latest_request_info ()
99+ latest_failed_request = await app .state .db .get_latest_failed_request_info ()
112100 except Exception as e :
113- raise HTTPException (f"{ e } " , status_code = 500 )
101+ raise HTTPException (status_code = 500 , detail = f"{ e } " )
102+ else :
103+ latest_request = None
104+ latest_failed_request = None
114105
115- return res
106+ return StatusReport (
107+ gateway_info = gateway_info , latest_request = latest_request , latest_failed_request = latest_failed_request
108+ )
0 commit comments