refactor: replace Trio with asyncio/uvloop

This commit is contained in:
Stefan Stammberger
2021-08-30 19:55:02 +02:00
parent fe79709698
commit d9849d43d2
21 changed files with 332 additions and 317 deletions
+29 -43
View File
@@ -1,3 +1,4 @@
import asyncio
import hashlib
import json
from binascii import unhexlify
@@ -6,15 +7,15 @@ from typing import Dict, Optional, Union
from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
import httpx
import trio
from fastapi import Query, security
from fastapi import Query, Request
from fastapi.exceptions import HTTPException
from fastapi.param_functions import Depends
from fastapi.params import Body
from sse_starlette.sse import EventSourceResponse
from pydantic import BaseModel
from lnbits import bolt11, lnurl
from lnbits.core.models import Wallet
from lnbits.core.models import Payment, Wallet
from lnbits.decorators import (WalletAdminKeyChecker, WalletInvoiceKeyChecker,
WalletTypeInfo, get_key_type)
from lnbits.helpers import url_for
@@ -251,57 +252,42 @@ async def api_payments_pay_lnurl(data: CreateLNURLData):
HTTPStatus.CREATED,
)
@core_app.get("/api/v1/payments/sse")
async def api_payments_sse(wallet: WalletTypeInfo = Depends(get_key_type)):
async def subscribe(request: Request, wallet: Wallet):
this_wallet_id = wallet.wallet.id
send_payment, receive_payment = trio.open_memory_channel(0)
payment_queue = asyncio.Queue(0)
print("adding sse listener", send_payment)
api_invoice_listeners.append(send_payment)
print("adding sse listener", payment_queue)
api_invoice_listeners.append(payment_queue)
send_event, event_to_send = trio.open_memory_channel(0)
send_queue = asyncio.Queue(0)
async def payment_received() -> None:
async for payment in receive_payment:
if payment.wallet_id == this_wallet_id:
await send_event.send(("payment-received", payment))
async def repeat_keepalive():
await trio.sleep(1)
while True:
await send_event.send(("keepalive", ""))
await trio.sleep(25)
payment: Payment = await payment_queue.get()
if payment.wallet_id == this_wallet_id:
await send_queue.put(("payment-received", payment))
async with trio.open_nursery() as nursery:
nursery.start_soon(payment_received)
nursery.start_soon(repeat_keepalive)
async def send_events():
try:
async for typ, data in event_to_send:
message = [f"event: {typ}".encode("utf-8")]
asyncio.create_task(payment_received())
if data:
jdata = json.dumps(dict(data._asdict(), pending=False))
message.append(f"data: {jdata}".encode("utf-8"))
try:
while True:
typ, data = await send_queue.get()
message = [f"event: {typ}".encode("utf-8")]
yield b"\n".join(message) + b"\r\n\r\n"
except trio.Cancelled:
return
if data:
jdata = json.dumps(dict(data.dict(), pending=False))
message.append(f"data: {jdata}".encode("utf-8"))
yield dict(data=jdata.encode("utf-8"), event=typ.encode("utf-8"))
except asyncio.CancelledError:
return
@core_app.get("/api/v1/payments/sse")
async def api_payments_sse(request: Request, wallet: WalletTypeInfo = Depends(get_key_type)):
return EventSourceResponse(subscribe(request, wallet))
response = await make_response(
send_events(),
{
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"X-Accel-Buffering": "no",
"Connection": "keep-alive",
"Transfer-Encoding": "chunked",
},
)
response.timeout = None
return response
@core_app.get("/api/v1/payments/{payment_hash}")
async def api_payment(payment_hash, wallet: WalletTypeInfo = Depends(get_key_type)):
+7 -7
View File
@@ -1,3 +1,5 @@
import asyncio
from http import HTTPStatus
from typing import Optional
@@ -9,7 +11,6 @@ from fastapi.responses import FileResponse, RedirectResponse
from fastapi.routing import APIRouter
from pydantic.types import UUID4
from starlette.responses import HTMLResponse
import trio
from lnbits.core import db
from lnbits.helpers import template_renderer, url_for
@@ -142,8 +143,7 @@ async def lnurl_full_withdraw_callback(request: Request):
except:
pass
async with trio.open_nursery() as n:
n.start_soon(pay)
asyncio.create_task(pay())
balance_notify = request.args.get("balanceNotify")
if balance_notify:
@@ -187,14 +187,14 @@ async def lnurlwallet(request: Request):
user = await get_user(account.id, conn=conn)
wallet = await create_wallet(user_id=user.id, conn=conn)
async with trio.open_nursery() as n:
n.start_soon(
redeem_lnurl_withdraw,
asyncio.create_task(
redeem_lnurl_withdraw(
wallet.id,
request.args.get("lightning"),
"LNbits initial funding: voucher redeem.",
{"tag": "lnurlwallet"},
5, # wait 5 seconds before sending the invoice to the service
5 # wait 5 seconds before sending the invoice to the service
)
)
return RedirectResponse(f"/wallet?usr={user.id}&wal={wallet.id}", status_code=status.HTTP_307_TEMPORARY_REDIRECT)
+9 -9
View File
@@ -1,4 +1,4 @@
import trio
import asyncio
import datetime
from http import HTTPStatus
@@ -26,27 +26,27 @@ async def api_public_payment_longpolling(payment_hash):
except:
return {"message": "Invalid bolt11 invoice."}, HTTPStatus.BAD_REQUEST
send_payment, receive_payment = trio.open_memory_channel(0)
payment_queue = asyncio.Queue(0)
print("adding standalone invoice listener", payment_hash, send_payment)
api_invoice_listeners.append(send_payment)
print("adding standalone invoice listener", payment_hash, payment_queue)
api_invoice_listeners.append(payment_queue)
response = None
async def payment_info_receiver(cancel_scope):
async for payment in receive_payment:
async for payment in payment_queue.get():
if payment.payment_hash == payment_hash:
nonlocal response
response = ({"status": "paid"}, HTTPStatus.OK)
cancel_scope.cancel()
async def timeouter(cancel_scope):
await trio.sleep(45)
await asyncio.sleep(45)
cancel_scope.cancel()
async with trio.open_nursery() as nursery:
nursery.start_soon(payment_info_receiver, nursery.cancel_scope)
nursery.start_soon(timeouter, nursery.cancel_scope)
asyncio.create_task(payment_info_receiver())
asyncio.create_task(timeouter())
if response:
return response