You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.3 KiB
112 lines
3.3 KiB
import gc
|
|
import requests
|
|
|
|
|
|
from datetime import datetime, timedelta
|
|
from requests.utils import urlparse
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from fastapi import FastAPI, BackgroundTasks
|
|
from fastapi.responses import JSONResponse
|
|
from fastapi.middleware import Middleware
|
|
from starlette.middleware.cors import CORSMiddleware
|
|
from fastapi_utils.tasks import repeat_every
|
|
|
|
from app.settings import *
|
|
|
|
# App
|
|
middleware = [
|
|
Middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
),
|
|
]
|
|
app = FastAPI(title="noaa", middleware=middleware)
|
|
|
|
|
|
# API
|
|
# GET 'test'
|
|
@app.get("/test/")
|
|
async def get_test():
|
|
# check source availability
|
|
# fresh one might be missing and old ones get deleted, so check yesterday's
|
|
yesterday_news = datetime.now(tz=ZoneInfo("US/Eastern")) - timedelta(days=1)
|
|
url = form_gfswave_link(target_time=yesterday_news)
|
|
if not is_reachable(url): # just one should be fine
|
|
print(url, " is not reachable at this time")
|
|
# TODO: should we actually error out?
|
|
return JSONResponse(content={"status": "success"})
|
|
|
|
|
|
# GET 'test_background'
|
|
@app.get("/test_background/{field_1}")
|
|
async def get_test_background(field_1: str, background_tasks: BackgroundTasks):
|
|
# background_tasks - for "heavy" processes
|
|
# TODO
|
|
background_tasks.add_task(service_example.run_test, field_1)
|
|
return JSONResponse(content={"status": "Background task started"})
|
|
|
|
|
|
# Tasks
|
|
# gc
|
|
@app.on_event("startup")
|
|
@repeat_every(seconds=(1 * 60))
|
|
async def task_gc() -> None:
|
|
gc.collect()
|
|
|
|
|
|
def is_reachable(url: str):
|
|
"""Check if url is reachable at all with the current setup
|
|
|
|
:param url: URL to check
|
|
:return: True if url is reachable, False otherwise
|
|
"""
|
|
if requests.head(url):
|
|
return True
|
|
return False
|
|
|
|
|
|
def form_gfs_link(target_time=None, prod_hour=384):
|
|
"""Return well formed link to gfs data which
|
|
should be available by given time
|
|
|
|
:param target_time: time to check, defaults to current time
|
|
:param prod_hour: forecast hour to link to, defaults to 384
|
|
:returns: URL to gfs file
|
|
"""
|
|
if not target_time:
|
|
target_time = datetime.now(
|
|
tz=ZoneInfo("US/Eastern")
|
|
) # noaa is located in washington
|
|
|
|
looking_at = "atmos"
|
|
|
|
date_str = target_time.strftime("%Y%m%d")
|
|
hour_str = str((target_time.hour // 6) * 6).zfill(2)
|
|
target_url = f"https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.{date_str}/{hour_str}/{looking_at}/gfs.t{hour_str}z.pgrb2.0p25.f{prod_hour}"
|
|
return target_url
|
|
|
|
|
|
def form_gfswave_link(target_time=None, prod_hour=384):
|
|
"""Return well formed link to gfs data which
|
|
should be available by given time
|
|
|
|
:param target_time: time to check, defaults to current time
|
|
:param prod_hour: forecast hour to link to, defaults to 384
|
|
:returns: URL to gfs file
|
|
"""
|
|
if not target_time:
|
|
target_time = datetime.now(
|
|
tz=ZoneInfo("US/Eastern")
|
|
) # noaa is located in washington
|
|
|
|
looking_at = "wave"
|
|
|
|
date_str = target_time.strftime("%Y%m%d")
|
|
hour_str = str((target_time.hour // 6) * 6).zfill(2)
|
|
target_url = f"https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.{date_str}/{hour_str}/{looking_at}/gridded/gfs{looking_at}.t{hour_str}z.global.0p25.f{prod_hour}.grib2"
|
|
return target_url
|