diff --git a/lnbits/core/services/payments.py b/lnbits/core/services/payments.py index ef1d07dbd..a3203d467 100644 --- a/lnbits/core/services/payments.py +++ b/lnbits/core/services/payments.py @@ -13,13 +13,13 @@ from lnbits.core.crud.payments import get_daily_stats from lnbits.core.db import db from lnbits.core.models import PaymentDailyStats, PaymentFilters from lnbits.core.models.payments import CreateInvoice +from lnbits.core.services.fiat_providers import handle_fiat_payment_confirmation from lnbits.db import Connection, Filters from lnbits.decorators import check_user_extension_access from lnbits.exceptions import InvoiceError, PaymentError, UnsupportedError from lnbits.fiat import get_fiat_provider from lnbits.helpers import check_callback_url from lnbits.settings import settings -from lnbits.tasks import create_task, internal_invoice_queue_put from lnbits.utils.crypto import fake_privkey, random_secret_and_hash, verify_preimage from lnbits.utils.exchange_rates import fiat_amount_as_satoshis, satoshis_amount_as_fiat from lnbits.wallets import fake_wallet, get_funding_source @@ -509,6 +509,8 @@ async def update_wallet_balance( ) payment.status = PaymentState.SUCCESS await update_payment(payment, conn=conn) + from lnbits.tasks import internal_invoice_queue_put + await internal_invoice_queue_put(payment.checking_id) @@ -819,6 +821,8 @@ async def _pay_external_invoice( fee_reserve_msat = fee_reserve(amount_msat, internal=False) + from lnbits.tasks import create_task + task = create_task( _fundingsource_pay_invoice(checking_id, payment.bolt11, fee_reserve_msat) ) @@ -1068,3 +1072,30 @@ async def _send_payment_notification_in_background( if not wallet: raise PaymentError(f"Could not fetch wallet '{wallet_id}'.", status="failed") send_payment_notification_in_background(wallet, payment) + + +async def update_invoice_callback(checking_id: str) -> Payment | None: + """ + Takes a checking_id of an incoming payment, from either paid_invoices_stream() + or internal_invoice_queue. Checks its status, updates and returns it. + returns None if no payment was found or it not and incoming payment. + """ + payment = await get_standalone_payment(checking_id, incoming=True) + if not payment: + logger.warning(f"No payment found for '{checking_id}'.") + return None + if not payment.is_in: + logger.warning(f"Payment '{checking_id}' is not incoming, skipping.") + return None + + status = await check_payment_status( + payment, skip_internal_payment_notifications=True + ) + payment.fee = status.fee_msat or payment.fee + # only overwrite preimage if status.preimage provides it + payment.preimage = status.preimage or payment.preimage + payment.status = PaymentState.SUCCESS + await update_payment(payment) + if payment.fiat_provider: + await handle_fiat_payment_confirmation(payment) + return payment diff --git a/lnbits/tasks.py b/lnbits/tasks.py index f7428651e..8d2b05e88 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -5,12 +5,8 @@ from collections.abc import Callable, Coroutine from loguru import logger -from lnbits.core.crud import ( - get_standalone_payment, - update_payment, -) -from lnbits.core.models import Payment, PaymentState -from lnbits.core.services.fiat_providers import handle_fiat_payment_confirmation +from lnbits.core.models import Payment +from lnbits.core.services.payments import update_invoice_callback from lnbits.settings import settings from lnbits.wallets import get_funding_source @@ -116,7 +112,10 @@ async def internal_invoice_listener() -> None: while settings.lnbits_running: checking_id = await internal_invoice_queue.get() logger.info(f"got an internal payment notification {checking_id}") - await invoice_callback_dispatcher(checking_id, is_internal=True) + payment = await update_invoice_callback(checking_id) + if payment: + logger.success(f"internal invoice {checking_id} settled") + await invoice_callback_dispatcher(payment) async def invoice_listener() -> None: @@ -129,7 +128,10 @@ async def invoice_listener() -> None: funding_source = get_funding_source() async for checking_id in funding_source.paid_invoices_stream(): logger.info(f"got a payment notification {checking_id}") - await invoice_callback_dispatcher(checking_id) + payment = await update_invoice_callback(checking_id) + if payment: + logger.success(f"fundingsource invoice {checking_id} settled") + await invoice_callback_dispatcher(payment) def wait_for_paid_invoices( @@ -165,33 +167,7 @@ def run_interval( return wrapper -async def invoice_callback_dispatcher(checking_id: str, is_internal: bool = False): - """ - Takes an incoming payment, checks its status, and dispatches it to - invoice_listeners from core and extensions. - """ - payment = await get_standalone_payment(checking_id, incoming=True) - if not payment: - logger.warning(f"No payment found for '{checking_id}'.") - return - if not payment.is_in: - logger.warning(f"Payment '{checking_id}' is not incoming, skipping.") - return - - from lnbits.core.services.payments import check_payment_status - - status = await check_payment_status( - payment, skip_internal_payment_notifications=True - ) - payment.fee = status.fee_msat or payment.fee - # only overwrite preimage if status.preimage provides it - payment.preimage = status.preimage or payment.preimage - payment.status = PaymentState.SUCCESS - await update_payment(payment) - if payment.fiat_provider: - await handle_fiat_payment_confirmation(payment) - internal = "internal" if is_internal else "" - logger.success(f"{internal} invoice {checking_id} settled") +async def invoice_callback_dispatcher(payment: Payment): for name, send_chan in invoice_listeners.items(): logger.trace(f"invoice listeners: sending to `{name}`") await send_chan.put(payment)