mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-22 11:24:19 +01:00
* settings * fix name settings * management rpc * hook up the RPC server * working * format * update build script fix import error * remove accidental commit of vscode extension data * working ✔ * \n * add get mint quote get melt quote * gRPC cli update quotes commands * update mint melt quotes from cli * comment under get cli command group * keyset rotation not yet implemented * try fix * change back contact info default to be empty list * fix import * add server mTLS * ll * script for generating certificates * rename settings * move generation script * do not save TTL expiry into Cache object, rather always load from settings. * update lightning fees * update auth limits * auth rate limit cli * optional arguemnts * better error messages * tests for db update mint/melt quotes * start mint rpc tests * add tos_url field to get-info grpc response * format checks * add types to click groups where it's needed * tests on updating quotes * fix tests * skip updating mint quote state if on regtest * test edge case * unified test_add_remove_contact * mark pytest-asyncio * fix missing db argument * hopefully no more silly errors * fix test_db_update_mint_quote_state * pass in the quote id string. * add keyset rotation * test for keyset rotation through gRPC command * fix logger warning * remove rotation test because it breaks other tests * use different bolt11 invoices * assert returned melt quote has quote * is_postgres * try different things * skip if deprecated api * format checks * update .gitignore * default location for certificates
127 lines
3.7 KiB
Python
127 lines
3.7 KiB
Python
import asyncio
|
|
import sys
|
|
from collections.abc import AsyncIterator
|
|
from contextlib import asynccontextmanager
|
|
from traceback import print_exception
|
|
|
|
from fastapi import FastAPI, status
|
|
from fastapi.exceptions import RequestValidationError
|
|
from fastapi.responses import JSONResponse
|
|
from loguru import logger
|
|
from starlette.requests import Request
|
|
|
|
from ..core.errors import CashuError
|
|
from ..core.logging import configure_logger
|
|
from ..core.settings import settings
|
|
from .auth.router import auth_router
|
|
from .router import redis, router
|
|
from .router_deprecated import router_deprecated
|
|
from .startup import (
|
|
shutdown_management_rpc,
|
|
shutdown_mint,
|
|
start_auth,
|
|
start_management_rpc,
|
|
start_mint,
|
|
)
|
|
|
|
if settings.debug_profiling:
|
|
pass
|
|
|
|
if settings.mint_rate_limit:
|
|
pass
|
|
|
|
from .middleware import add_middlewares, request_validation_exception_handler
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
|
|
await start_mint()
|
|
if settings.mint_require_auth:
|
|
await start_auth()
|
|
if settings.mint_rpc_server_enable:
|
|
await start_management_rpc()
|
|
try:
|
|
yield
|
|
except asyncio.CancelledError:
|
|
# Handle the cancellation gracefully
|
|
logger.info("Shutdown process interrupted by CancelledError")
|
|
finally:
|
|
try:
|
|
await shutdown_management_rpc()
|
|
await redis.disconnect()
|
|
await shutdown_mint()
|
|
except asyncio.CancelledError:
|
|
logger.error("CancelledError during shutdown, shutting down forcefully")
|
|
|
|
|
|
def create_app(config_object="core.settings") -> FastAPI:
|
|
configure_logger()
|
|
|
|
app = FastAPI(
|
|
title="Nutshell Mint",
|
|
description="Ecash mint based on the Cashu protocol.",
|
|
version=settings.version,
|
|
license_info={
|
|
"name": "MIT License",
|
|
"url": "https://raw.githubusercontent.com/cashubtc/cashu/main/LICENSE",
|
|
},
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
return app
|
|
|
|
|
|
app = create_app()
|
|
|
|
# Add middlewares
|
|
add_middlewares(app)
|
|
|
|
|
|
@app.middleware("http")
|
|
async def catch_exceptions(request: Request, call_next):
|
|
CORS_HEADERS = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "*",
|
|
"Access-Control-Allow-Headers": "*",
|
|
"Access-Control-Allow-Credentials": "true",
|
|
}
|
|
try:
|
|
return await call_next(request)
|
|
except Exception as e:
|
|
try:
|
|
err_message = str(e)
|
|
except Exception:
|
|
err_message = e.args[0] if e.args else "Unknown error"
|
|
|
|
if isinstance(e, CashuError) or isinstance(e.args[0], CashuError):
|
|
logger.error(f"CashuError: {err_message}")
|
|
code = e.code if isinstance(e, CashuError) else e.args[0].code
|
|
# return with cors headers
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={"detail": err_message, "code": code},
|
|
headers=CORS_HEADERS,
|
|
)
|
|
logger.error(f"Exception: {err_message}")
|
|
if settings.debug:
|
|
print_exception(*sys.exc_info())
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={"detail": err_message, "code": 0},
|
|
headers=CORS_HEADERS,
|
|
)
|
|
|
|
|
|
# Add exception handlers
|
|
app.add_exception_handler(RequestValidationError, request_validation_exception_handler) # type: ignore
|
|
|
|
# Add routers
|
|
if settings.debug_mint_only_deprecated:
|
|
app.include_router(router=router_deprecated, tags=["Deprecated"], deprecated=True)
|
|
else:
|
|
app.include_router(router=router, tags=["Mint"])
|
|
app.include_router(router=router_deprecated, tags=["Deprecated"], deprecated=True)
|
|
|
|
if settings.mint_require_auth:
|
|
app.include_router(auth_router, tags=["Auth"])
|