2021-03-24 05:41:19 +01:00
|
|
|
import time
|
2021-08-30 19:55:02 +02:00
|
|
|
import asyncio
|
2021-07-31 00:26:22 +02:00
|
|
|
import traceback
|
2020-10-06 05:39:54 +02:00
|
|
|
from http import HTTPStatus
|
2021-07-31 00:26:22 +02:00
|
|
|
from typing import List, Callable
|
2020-10-06 05:39:54 +02:00
|
|
|
|
2021-09-11 11:02:48 +02:00
|
|
|
from fastapi.exceptions import HTTPException
|
|
|
|
|
2020-10-06 05:39:54 +02:00
|
|
|
from lnbits.settings import WALLET
|
2021-03-24 04:40:32 +01:00
|
|
|
from lnbits.core.crud import (
|
|
|
|
get_payments,
|
|
|
|
get_standalone_payment,
|
|
|
|
delete_expired_invoices,
|
2021-04-17 23:27:15 +02:00
|
|
|
get_balance_checks,
|
2021-03-24 04:40:32 +01:00
|
|
|
)
|
2021-04-17 23:27:15 +02:00
|
|
|
from lnbits.core.services import redeem_lnurl_withdraw
|
2020-10-06 05:39:54 +02:00
|
|
|
|
|
|
|
|
2020-10-06 06:50:55 +02:00
|
|
|
deferred_async: List[Callable] = []
|
|
|
|
|
|
|
|
|
|
|
|
def record_async(func: Callable) -> Callable:
|
|
|
|
def recorder(state):
|
|
|
|
deferred_async.append(func)
|
|
|
|
|
|
|
|
return recorder
|
|
|
|
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
async def run_deferred_async():
|
2020-10-06 06:50:55 +02:00
|
|
|
for func in deferred_async:
|
2021-08-30 19:55:02 +02:00
|
|
|
asyncio.create_task(catch_everything_and_restart(func))
|
2021-07-31 00:26:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
async def catch_everything_and_restart(func):
|
|
|
|
try:
|
|
|
|
await func()
|
2021-08-30 19:55:02 +02:00
|
|
|
except asyncio.CancelledError:
|
2021-07-31 00:26:22 +02:00
|
|
|
raise # because we must pass this up
|
|
|
|
except Exception as exc:
|
|
|
|
print("caught exception in background task:", exc)
|
|
|
|
print(traceback.format_exc())
|
|
|
|
print("will restart the task in 5 seconds.")
|
2021-08-30 19:55:02 +02:00
|
|
|
await asyncio.sleep(5)
|
2021-07-31 00:26:22 +02:00
|
|
|
await catch_everything_and_restart(func)
|
2020-10-06 06:50:55 +02:00
|
|
|
|
|
|
|
|
2020-10-06 05:39:54 +02:00
|
|
|
async def send_push_promise(a, b) -> None:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
invoice_listeners: List[asyncio.Queue] = []
|
2020-10-06 05:39:54 +02:00
|
|
|
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
def register_invoice_listener(send_chan: asyncio.Queue):
|
2020-10-06 05:39:54 +02:00
|
|
|
"""
|
|
|
|
A method intended for extensions to call when they want to be notified about
|
|
|
|
new invoice payments incoming.
|
|
|
|
"""
|
2020-10-06 06:50:55 +02:00
|
|
|
invoice_listeners.append(send_chan)
|
2020-10-06 05:39:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
async def webhook_handler():
|
|
|
|
handler = getattr(WALLET, "webhook_listener", None)
|
|
|
|
if handler:
|
|
|
|
return await handler()
|
2021-09-11 11:02:48 +02:00
|
|
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
2020-10-06 05:39:54 +02:00
|
|
|
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
internal_invoice_queue = asyncio.Queue(0)
|
2020-10-22 20:36:37 +02:00
|
|
|
|
|
|
|
|
2021-07-31 00:26:22 +02:00
|
|
|
async def internal_invoice_listener():
|
2021-08-30 19:55:02 +02:00
|
|
|
while True:
|
|
|
|
checking_id = await internal_invoice_queue.get()
|
|
|
|
asyncio.create_task(invoice_callback_dispatcher(checking_id))
|
2020-10-22 20:36:37 +02:00
|
|
|
|
|
|
|
|
2021-07-31 00:26:22 +02:00
|
|
|
async def invoice_listener():
|
2021-03-21 21:57:33 +01:00
|
|
|
async for checking_id in WALLET.paid_invoices_stream():
|
2021-08-01 15:30:27 +02:00
|
|
|
print("> got a payment notification", checking_id)
|
2021-08-30 19:55:02 +02:00
|
|
|
asyncio.create_task(invoice_callback_dispatcher(checking_id))
|
2021-03-21 21:57:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
async def check_pending_payments():
|
|
|
|
await delete_expired_invoices()
|
2021-03-28 05:11:41 +02:00
|
|
|
|
|
|
|
outgoing = True
|
|
|
|
incoming = True
|
|
|
|
|
2021-03-21 21:59:54 +01:00
|
|
|
while True:
|
2021-03-24 04:40:32 +01:00
|
|
|
for payment in await get_payments(
|
2021-03-24 05:41:19 +01:00
|
|
|
since=(int(time.time()) - 60 * 60 * 24 * 15), # 15 days ago
|
|
|
|
complete=False,
|
|
|
|
pending=True,
|
2021-03-28 05:11:41 +02:00
|
|
|
outgoing=outgoing,
|
|
|
|
incoming=incoming,
|
2021-03-24 05:41:19 +01:00
|
|
|
exclude_uncheckable=True,
|
2021-03-24 04:40:32 +01:00
|
|
|
):
|
2021-03-21 21:59:54 +01:00
|
|
|
await payment.check_pending()
|
|
|
|
|
2021-03-28 05:11:41 +02:00
|
|
|
# after the first check we will only check outgoing, not incoming
|
|
|
|
# that will be handled by the global invoice listeners, hopefully
|
|
|
|
incoming = False
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
await asyncio.sleep(60 * 30) # every 30 minutes
|
2020-10-06 05:39:54 +02:00
|
|
|
|
|
|
|
|
2021-04-17 23:27:15 +02:00
|
|
|
async def perform_balance_checks():
|
|
|
|
while True:
|
|
|
|
for bc in await get_balance_checks():
|
|
|
|
redeem_lnurl_withdraw(bc.wallet, bc.url)
|
|
|
|
|
2021-08-30 19:55:02 +02:00
|
|
|
await asyncio.sleep(60 * 60 * 6) # every 6 hours
|
2021-04-17 23:27:15 +02:00
|
|
|
|
|
|
|
|
2020-10-06 05:39:54 +02:00
|
|
|
async def invoice_callback_dispatcher(checking_id: str):
|
2020-11-21 22:04:39 +01:00
|
|
|
payment = await get_standalone_payment(checking_id)
|
2020-10-06 05:39:54 +02:00
|
|
|
if payment and payment.is_in:
|
2020-11-21 22:04:39 +01:00
|
|
|
await payment.set_pending(False)
|
2020-10-06 06:50:55 +02:00
|
|
|
for send_chan in invoice_listeners:
|
2021-08-30 19:55:02 +02:00
|
|
|
await send_chan.put(payment)
|