import asyncio import datetime from http import HTTPStatus from fastapi import HTTPException from loguru import logger from lnbits import bolt11 from .. import core_app from ..crud import get_standalone_payment from ..tasks import api_invoice_listeners @core_app.get("/public/v1/payment/{payment_hash}") async def api_public_payment_longpolling(payment_hash): payment = await get_standalone_payment(payment_hash) if not payment: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Payment does not exist." ) elif not payment.pending: return {"status": "paid"} try: invoice = bolt11.decode(payment.bolt11) expiration = datetime.datetime.fromtimestamp(invoice.date + invoice.expiry) if expiration < datetime.datetime.now(): return {"status": "expired"} except Exception: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail="Invalid bolt11 invoice." ) payment_queue = asyncio.Queue(0) logger.debug(f"adding standalone invoice listener for hash: {payment_hash}") api_invoice_listeners[payment_hash] = payment_queue response = None async def payment_info_receiver(): for payment in await payment_queue.get(): if payment.payment_hash == payment_hash: nonlocal response response = {"status": "paid"} async def timeouter(cancel_scope): await asyncio.sleep(45) cancel_scope.cancel() cancel_scope = asyncio.create_task(payment_info_receiver()) asyncio.create_task(timeouter(cancel_scope)) if response: return response else: raise HTTPException(status_code=HTTPStatus.REQUEST_TIMEOUT, detail="timeout")