Files
OSIT-AE-API-FastAPI/app/main.py

196 lines
7.6 KiB
Python

import datetime, json, os, pytz, random, secrets # , uvicorn
from enum import Enum
#from datetime import datetime, time, timedelta
from fastapi import Body, Cookie, Depends, FastAPI, File, Form, Header, HTTPException, Path, Query, Request, Response, status, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, PlainTextResponse
from fastapi.staticfiles import StaticFiles
from functools import lru_cache
from pydantic import BaseModel, EmailStr, Field
from typing import Dict, List, Optional, Set, Union
from . import config
# from app.lib_general import common_route_params, Common_Route_Params
import logging
import app.log
# Import middleware with alias to avoid shadowing 'app' FastAPI instance
from app.middleware import add_process_time_header as process_time_middleware
# Centralized router registry
from app.routers.registry import setup_routers
from app.db_sql import sql_select, reset_redis, reconnect_db
from app.lib_config_v3 import bootstrap_db_config, validate_critical_config
print('### **** *** ** * The Aether API v4 using FastAPI is loading... * ** *** **** ###')
log = logging.getLogger(__name__)
# log.setLevel(logging.DEBUG) # DEBUG > INFO > WARNING > ERROR > CRITICAL
#logging.basicConfig(
#format='[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s'
#)
print('### **** *** ** * Aether API v4 using FastAPI - About to try FastAPI() while loading... * ** *** **** ###')
app = FastAPI(
# debug = True,
title = 'Aether API',
description = 'One Sky IT\'s Aether API v4 using FastAPI.',
version = '4.9.0',
operationsSorter = 'method',
)
log.setLevel(logging.INFO)
# log.debug(config.settings)
print('### **** *** ** * Aether API v4 using FastAPI - Bootstrapping Configuration... * ** *** **** ###')
# Sync settings from DB with robust error handling
try:
if bootstrap_db_config(config.settings):
log.info("Successfully bootstrapped configuration from database.")
# Re-initialize the database engine with new credentials/URI
if reconnect_db():
log.info("Database connection re-established with production configuration.")
else:
log.warning("FAILED to re-establish database connection after bootstrap. Falling back to .env settings.")
else:
log.warning("System bootstrap from DB returned no results. Using environment defaults.")
except Exception as e:
log.error(f"Unexpected error during configuration bootstrap: {e}. Falling back to .env settings.")
# Perform final validation of critical infrastructure
validate_critical_config(config.settings)
print('### **** *** ** * Aether API v4 using FastAPI - Finished Configuration Phase * ** *** **** ###' )
log.debug(config.settings)
# @lru_cache()
# def get_settings():
# return config.Settings()
app.mount('/static', StaticFiles(directory='static'), name='static')
# Register all application routes
setup_routers(app)
# BEGIN: CORS
# NOTE: Eventually this should query the DB for the specific list based on the cfg table and or site_domain table. That way it is dynamic and only allowing those defined in the DB. No wildcards or regex.
# NOTE: Need to include .localhost for less browser restrictions! Mainly for audio and video.
app.add_middleware(
CORSMiddleware,
# allow_origins = origins,
allow_origins = config.settings.ORIGINS,
allow_origin_regex = config.settings.ORIGINS_REGEX,
# allow_origin_regex = 'https://.*\.oneskyit\.com',
allow_credentials = True,
allow_methods = ['*'],
allow_headers = ['*'],
#expose_headers = [],
#max_age = 600,
)
# END: CORS
# Register utility middleware from external module
app.middleware('http')(process_time_middleware)
# ### BEGIN ### API Main ### fastapi_root() ###
@app.get('/', tags=['Root'], response_class=PlainTextResponse)
async def fastapi_root(response: Response = Response):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# log.info(config.settings.APP_NAME)
log.info('One Sky IT\'s Aether API root (FastAPI)')
log.info('***')
log.debug('This is debug') # 10 DEBUG
log.info('This is info') # 20 INFO
log.warning('This is a warning') # 30 WARNING (and WARN)
log.error('This is an error') # 40 ERROR
log.exception('This is an exception') # 40 ERROR
log.critical('This is critical') # 50 CRITICAL
log.info('^^^')
log.warning('Resetting Redis...')
reset_redis()
log.info('Reset Redis')
response_data = {}
response_data['message'] = 'This is One Sky IT\'s Aether API root (FastAPI).'
current_datetime = datetime.datetime.now()
current_datetime_string = current_datetime.isoformat()
timezone = pytz.timezone("America/New_York")
current_datetime_tz = timezone.localize(current_datetime)
current_datetime_tz_string = current_datetime_tz.isoformat()
current_datetime_utc = datetime.datetime.utcnow()
current_datetime_utc_string = current_datetime_utc.isoformat()
current_datetime_utc_localize = pytz.utc.localize(current_datetime_utc)
current_datetime_utc_localize_string = current_datetime_utc_localize.isoformat()
current_datetime_utc_localize_pst = current_datetime_utc_localize.astimezone(pytz.timezone("America/Los_Angeles"))
current_datetime_utc_localize_pst_string = current_datetime_utc_localize_pst.isoformat()
response_data['datetime'] = current_datetime_string
response_data['datetime_tz'] = current_datetime_tz_string
response_data['datetime_utc'] = current_datetime_utc_string
response_data['datetime_utc_localize'] = current_datetime_utc_localize_string
response_data['datetime_utc_localize_pst'] = current_datetime_utc_localize_pst_string
response_data['url_safe_string_4_bytes_1'] = secrets.token_urlsafe(4)
response_data['url_safe_string_8_bytes_1'] = secrets.token_urlsafe(8)
response_data['url_safe_string_8_bytes_2'] = secrets.token_urlsafe(8)
response_data['url_safe_string_8_bytes_3'] = secrets.token_urlsafe(8)
response_data['url_safe_string_8_bytes_4'] = secrets.token_urlsafe(8)
response_data['url_safe_string_8_bytes_5'] = secrets.token_urlsafe(8)
response_data['url_safe_string_16_bytes_1'] = secrets.token_urlsafe(16)
response_data['url_safe_string_16_bytes_2'] = secrets.token_urlsafe(16)
response_data['url_safe_string_16_bytes_3'] = secrets.token_urlsafe(16)
response_data['url_safe_string_16_bytes_4'] = secrets.token_urlsafe(16)
response_data['url_safe_string_16_bytes_5'] = secrets.token_urlsafe(16)
response_data['hex_string_4_bytes_1'] = secrets.token_hex(4)
response_data['hex_string_8_bytes_1'] = secrets.token_hex(8)
response_data['hex_string_16_bytes_1'] = secrets.token_hex(16)
response_data['hex_string_32_bytes_1'] = secrets.token_hex(32)
log.debug(json.dumps(response_data, indent=4))
return json.dumps(response_data, indent=4) # , sort_keys=True
# ### END ### API Main ### fastapi_root() ###
# ### BEGIN ### API Main ### generate_id_random() ###
# NOTE: This is just a quick utility function to generate a bunch of random IDs.
# Updated 2022-03-30
@app.get('/generate_id_random', tags=['Root'], response_class=PlainTextResponse)
async def generate_id_random(response: Response = Response):
log.setLevel(logging.INFO) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
response_data = {}
html_list = '<ul>'
for x in range(50):
html_list += f'<li>{secrets.token_urlsafe(8)}</li>'
html_list += '</ul>'
return HTMLResponse(content=html_list, status_code=200)
# ### END ### API Main ### generate_id_random() ###