From 7e4a42e7ff424f13a70a6e378133613baa67cda1 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sun, 21 Mar 2021 17:57:33 -0300 Subject: [PATCH] stop doing the check_invoices thing on each call. do it once on lnbits starup and then rely on the invoices listener. --- lnbits/app.py | 16 ++++++-- lnbits/core/crud.py | 53 +++++++++++++++------------ lnbits/core/models.py | 6 +-- lnbits/core/static/js/wallet.js | 14 ------- lnbits/core/views/api.py | 12 ------ lnbits/extensions/usermanager/crud.py | 4 +- lnbits/static/js/base.js | 3 -- lnbits/tasks.py | 23 +++++++----- 8 files changed, 61 insertions(+), 70 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index b5fe71bd..15c22fb6 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -11,10 +11,17 @@ from .commands import db_migrate, handle_assets from .core import core_app from .helpers import get_valid_extensions, get_js_vendored, get_css_vendored, url_for_vendored from .proxy_fix import ASGIProxyFix -from .tasks import run_deferred_async, invoice_listener, internal_invoice_listener, webhook_handler, grab_app_for_later +from .tasks import ( + run_deferred_async, + check_pending_payments, + invoice_listener, + internal_invoice_listener, + webhook_handler, + grab_app_for_later, +) from .settings import WALLET -secure_headers = SecureHeaders(hsts=False,xfo=False) +secure_headers = SecureHeaders(hsts=False, xfo=False) def create_app(config_object="lnbits.settings") -> QuartTrio: @@ -123,8 +130,9 @@ def register_async_tasks(app): @app.before_serving async def listeners(): run_deferred_async(app.nursery) - app.nursery.start_soon(invoice_listener) - app.nursery.start_soon(internal_invoice_listener) + app.nursery.start_soon(check_pending_payments) + app.nursery.start_soon(invoice_listener, app.nursery) + app.nursery.start_soon(internal_invoice_listener, app.nursery) @app.after_serving async def stop_listeners(): diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 2c91bc22..c759482e 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -1,7 +1,7 @@ import json import datetime from uuid import uuid4 -from typing import List, Optional, Dict +from typing import List, Optional, Dict, Any from lnbits import bolt11 from lnbits.settings import DEFAULT_WALLET_NAME @@ -158,9 +158,9 @@ async def get_wallet_payment(wallet_id: str, payment_hash: str) -> Optional[Paym return Payment.from_row(row) if row else None -async def get_wallet_payments( - wallet_id: str, +async def get_payments( *, + wallet_id: Optional[str] = None, complete: bool = False, pending: bool = False, outgoing: bool = False, @@ -171,41 +171,48 @@ async def get_wallet_payments( Filters payments to be returned by complete | pending | outgoing | incoming. """ - clause = "" - if complete and pending: - clause += "" - elif complete: - clause += "AND ((amount > 0 AND pending = 0) OR amount < 0)" - elif pending: - clause += "AND pending = 1" - else: - raise TypeError("at least one of [complete, pending] must be True.") + args: Any = () - clause += " " + clause = [] + + if wallet_id: + clause.append("wallet = ?") + args = (wallet_id,) + + if complete and pending: + pass + elif complete: + clause.append("((amount > 0 AND pending = 0) OR amount < 0)") + elif pending: + clause.append("pending = 1") + else: + pass if outgoing and incoming: - clause += "" + pass elif outgoing: - clause += "AND amount < 0" + clause.append("amount < 0") elif incoming: - clause += "AND amount > 0" + clause.append("amount > 0") else: - raise TypeError("at least one of [outgoing, incoming] must be True.") - - clause += " " + pass if exclude_uncheckable: # checkable means it has a checking_id that isn't internal - clause += "AND checking_id NOT LIKE 'temp_%' " - clause += "AND checking_id NOT LIKE 'internal_%' " + clause.append("checking_id NOT LIKE 'temp_%'") + clause.append("checking_id NOT LIKE 'internal_%'") + + where = "" + if clause: + where = f"WHERE {' AND '.join(clause)}" rows = await db.fetchall( f""" SELECT * FROM apipayments - WHERE wallet = ? {clause} + {where} ORDER BY time DESC """, - (wallet_id,), + args, ) return [Payment.from_row(row) for row in rows] diff --git a/lnbits/core/models.py b/lnbits/core/models.py index 9e37baa1..d3e9580d 100644 --- a/lnbits/core/models.py +++ b/lnbits/core/models.py @@ -60,10 +60,10 @@ class Wallet(NamedTuple): incoming: bool = True, exclude_uncheckable: bool = False ) -> List["Payment"]: - from .crud import get_wallet_payments + from .crud import get_payments - return await get_wallet_payments( - self.id, + return await get_payments( + wallet_id=self.id, complete=complete, pending=pending, outgoing=outgoing, diff --git a/lnbits/core/static/js/wallet.js b/lnbits/core/static/js/wallet.js index 58345ab0..bfed347b 100644 --- a/lnbits/core/static/js/wallet.js +++ b/lnbits/core/static/js/wallet.js @@ -604,19 +604,6 @@ new Vue({ ]) }) }, - checkPendingPayments: function () { - var dismissMsg = this.$q.notify({ - timeout: 0, - message: 'Checking pending transactions...' - }) - - LNbits.api - .checkPending(this.g.wallet) - .then(() => LNbits.api.fetchPayments) - .then(() => { - dismissMsg() - }) - }, exportCSV: function () { LNbits.utils.exportCSV(this.paymentsTable.columns, this.payments) } @@ -629,7 +616,6 @@ new Vue({ created: function () { this.fetchBalance() this.fetchPayments() - this.checkPendingPayments() }, mounted: function () { // show disclaimer diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 5a461c33..e513a8d6 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -13,7 +13,6 @@ from lnbits.decorators import api_check_wallet_key, api_validate_post_request from .. import core_app, db from ..services import create_invoice, pay_invoice, perform_lnurlauth -from ..crud import delete_expired_invoices from ..tasks import sse_listeners @@ -32,17 +31,6 @@ async def api_wallet(): ) -@core_app.route("/api/v1/checkpending", methods=["POST"]) -@api_check_wallet_key("invoice") -async def api_checkpending(): - g.nursery.start_soon(delete_expired_invoices) - - for payment in await g.wallet.get_payments(complete=False, pending=True, exclude_uncheckable=True): - await payment.check_pending() - - return "", HTTPStatus.NO_CONTENT - - @core_app.route("/api/v1/payments", methods=["GET"]) @api_check_wallet_key("invoice") async def api_payments(): diff --git a/lnbits/extensions/usermanager/crud.py b/lnbits/extensions/usermanager/crud.py index db41b8dd..350a03f9 100644 --- a/lnbits/extensions/usermanager/crud.py +++ b/lnbits/extensions/usermanager/crud.py @@ -4,7 +4,7 @@ from lnbits.core.models import Payment from lnbits.core.crud import ( create_account, get_user, - get_wallet_payments, + get_payments, create_wallet, delete_wallet, ) @@ -91,7 +91,7 @@ async def get_usermanager_wallets(user_id: str) -> List[Wallets]: async def get_usermanager_wallet_transactions(wallet_id: str) -> List[Payment]: - return await get_wallet_payments(wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True) + return await get_payments(wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True) async def delete_usermanager_wallet(wallet_id: str, user_id: str) -> None: diff --git a/lnbits/static/js/base.js b/lnbits/static/js/base.js index 61d56248..318d8d13 100644 --- a/lnbits/static/js/base.js +++ b/lnbits/static/js/base.js @@ -52,9 +52,6 @@ window.LNbits = { getWallet: function (wallet) { return this.request('get', '/api/v1/wallet', wallet.inkey) }, - checkPending: function (wallet) { - return this.request('post', '/api/v1/checkpending', wallet.inkey) - }, getPayments: function (wallet) { return this.request('get', '/api/v1/payments', wallet.inkey) }, diff --git a/lnbits/tasks.py b/lnbits/tasks.py index 3acb2a07..ca3d9d67 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -4,7 +4,7 @@ from typing import Optional, List, Callable from quart_trio import QuartTrio from lnbits.settings import WALLET -from lnbits.core.crud import get_standalone_payment +from lnbits.core.crud import get_payments, get_standalone_payment, delete_expired_invoices main_app: Optional[QuartTrio] = None @@ -54,16 +54,21 @@ async def webhook_handler(): internal_invoice_paid, internal_invoice_received = trio.open_memory_channel(0) -async def internal_invoice_listener(): - async with trio.open_nursery() as nursery: - async for checking_id in internal_invoice_received: - nursery.start_soon(invoice_callback_dispatcher, checking_id) +async def internal_invoice_listener(nursery): + async for checking_id in internal_invoice_received: + nursery.start_soon(invoice_callback_dispatcher, checking_id) -async def invoice_listener(): - async with trio.open_nursery() as nursery: - async for checking_id in WALLET.paid_invoices_stream(): - nursery.start_soon(invoice_callback_dispatcher, checking_id) +async def invoice_listener(nursery): + async for checking_id in WALLET.paid_invoices_stream(): + nursery.start_soon(invoice_callback_dispatcher, checking_id) + + +async def check_pending_payments(): + await delete_expired_invoices() + for payment in await get_payments(complete=False, pending=True, exclude_uncheckable=True): + print(" - checking pending", payment.checking_id) + await payment.check_pending() async def invoice_callback_dispatcher(checking_id: str):