File size: 4,105 Bytes
74645f6
c8a9a0a
9d4bd7c
 
 
 
 
 
74645f6
9d4bd7c
 
 
 
0f06d85
1e12801
6541314
b06927a
9c765c3
5c7ec94
9d4bd7c
9c765c3
9d4bd7c
c8a9a0a
 
 
 
 
1e12801
c8a9a0a
677d08a
 
 
9d4bd7c
 
976085c
 
 
 
 
 
 
 
 
 
 
 
9d4bd7c
 
 
 
74645f6
 
677d08a
 
74645f6
9d4bd7c
 
9c765c3
74645f6
 
 
 
 
 
 
 
 
 
 
677d08a
9d4bd7c
 
 
 
 
976085c
 
 
 
9d4bd7c
 
9c765c3
e558c69
 
 
 
 
 
 
9d4bd7c
 
74645f6
9d4bd7c
 
 
 
0f06d85
1e12801
6541314
b06927a
9d4bd7c
9c765c3
9d4bd7c
 
c8a9a0a
9d4bd7c
c8a9a0a
0f06d85
c8a9a0a
677d08a
5c7ec94
1e12801
 
9d4bd7c
9c765c3
9d4bd7c
 
 
 
9c765c3
9d4bd7c
 
9c765c3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import asyncio
import logging
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError, HTTPException
from starlette.status import HTTP_400_BAD_REQUEST
from App.routers.stocks.routes import router as stocks_router
from App.routers.funds.routes import router as funds_router
from App.routers.bonds.routes import router as bonds_router
from App.routers.tasks.routes import router as tasks_router
from App.routers.users.routes import router as users_router
from App.routers.portfolio.routes import router as portfolio_router
from App.routers.admin.routes import router as admin_router
from App.routers.economy.config import load_local_env
from App.routers.economy.routes import api_router as economy_api_router, router as economy_router
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from App.schemas import ResponseModel, AppException
from App.scheduler import scheduled_economy_loop, scheduled_market_loop, scheduled_news_loop

from db import init_db, close_db, clear_db

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
load_local_env()

app = FastAPI(
    title="Uwekezaji API", description="Stock Market Data API", redirect_slashes=False
)


def _json_safe(value):
    if isinstance(value, bytes):
        return value.decode("utf-8", errors="replace")
    if isinstance(value, dict):
        return {key: _json_safe(item) for key, item in value.items()}
    if isinstance(value, list):
        return [_json_safe(item) for item in value]
    if isinstance(value, tuple):
        return [_json_safe(item) for item in value]
    return value


@app.exception_handler(AppException)
async def custom_http_exception_handler(request: Request, exc: AppException):
    return JSONResponse(
        status_code=exc.status_code,
        content=ResponseModel(
            success=False,
            message=getattr(exc, "message", str(exc.detail)),
            data=getattr(exc, "data", None),
        ).model_dump(),
    )


@app.exception_handler(HTTPException)
async def generic_http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content=ResponseModel(
            success=False,
            message=str(exc.detail),
            data=None,
        ).model_dump(),
    )


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=HTTP_400_BAD_REQUEST,
        content=ResponseModel(
            success=False,
            message="Validation error",
            data={"errors": _json_safe(exc.errors())},
        ).model_dump(),
    )


app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=False,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(stocks_router)
app.include_router(funds_router)
app.include_router(bonds_router)
app.include_router(tasks_router)
app.include_router(users_router)
app.include_router(portfolio_router)
app.include_router(admin_router)
app.include_router(economy_router)
app.include_router(economy_api_router)
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")


@app.on_event("startup")
async def startup_event():
    logger.info("[startup] database initialization started")
    await init_db()
    logger.info("[startup] database initialization complete")
    asyncio.create_task(scheduled_market_loop())
    logger.info("[startup] scheduled market background loop started")
    asyncio.create_task(scheduled_news_loop())
    logger.info("[startup] scheduled news background loop started")
    asyncio.create_task(scheduled_economy_loop())
    logger.info("[startup] economy pipeline loop registered")


@app.on_event("shutdown")
async def shutdown_event():
    await close_db()


@app.get("/")
async def root():
    return {"message": "Welcome to Uwekezaji API"}