async invoice listeners through webhooks: lnpay and opennode.

This commit is contained in:
fiatjaf
2020-10-04 12:04:49 -03:00
parent 74117ffc57
commit 2c92205703
4 changed files with 64 additions and 15 deletions
+18 -9
View File
@@ -1,6 +1,8 @@
import json
import asyncio
import aiohttp
from os import getenv
from http import HTTPStatus
from typing import Optional, Dict, AsyncGenerator
from requests import get, post
from quart import request
@@ -18,7 +20,6 @@ class LNPayWallet(Wallet):
self.auth_invoice = getenv("LNPAY_INVOICE_KEY")
self.auth_read = getenv("LNPAY_READ_KEY")
self.auth_api = {"X-Api-Key": getenv("LNPAY_API_KEY")}
self.queue = asyncio.Queue()
def create_invoice(
self,
@@ -79,18 +80,26 @@ class LNPayWallet(Wallet):
return PaymentStatus(statuses[r.json()["settled"]])
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
self.queue: asyncio.Queue = asyncio.Queue()
while True:
yield await self.queue.get()
item = await self.queue.get()
yield item
self.queue.task_done()
async def webhook_listener(self):
data = await request.get_json()
if "event" not in data or data["event"].get("name") != "wallet_receive":
return ""
text: str = await request.get_data()
data = json.loads(text)
if type(data) is not dict or "event" not in data or data["event"].get("name") != "wallet_receive":
return "", HTTPStatus.NO_CONTENT
lntx_id = data["data"]["wtx"]["lnTx"]["id"]
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.endpoint}/user/lntx/{lntx_id}?fields=settled") as resp:
data = await resp.json()
if data["settled"]:
self.queue.put_nowait(lntx_id)
resp = await session.get(
f"{self.endpoint}/user/lntx/{lntx_id}?fields=settled",
headers=self.auth_api,
)
data = await resp.json()
if data["settled"]:
self.queue.put_nowait(lntx_id)
return "", HTTPStatus.NO_CONTENT
+41 -3
View File
@@ -1,6 +1,11 @@
import json
import asyncio
import hmac
from http import HTTPStatus
from os import getenv
from typing import Optional
from typing import Optional, AsyncGenerator
from requests import get, post
from quart import request, url_for
from .base import InvoiceResponse, PaymentResponse, PaymentStatus, Wallet, Unsupported
@@ -23,13 +28,18 @@ class OpenNodeWallet(Wallet):
r = post(
url=f"{self.endpoint}/v1/charges",
headers=self.auth_invoice,
json={"amount": f"{amount}", "description": memo}, # , "private": True},
json={
"amount": amount,
"description": memo or "",
"callback_url": url_for("webhook_listener", _external=True),
},
)
ok, checking_id, payment_request, error_message = r.ok, None, None, None
if r.ok:
data = r.json()["data"]
checking_id, payment_request = data["id"], data["lightning_invoice"]["payreq"]
checking_id = data["id"]
payment_request = data["lightning_invoice"]["payreq"]
else:
error_message = r.json()["message"]
@@ -64,3 +74,31 @@ class OpenNodeWallet(Wallet):
statuses = {"initial": None, "pending": None, "confirmed": True, "error": False, "failed": False}
return PaymentStatus(statuses[r.json()["data"]["status"]])
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
self.queue: asyncio.Queue = asyncio.Queue()
while True:
item = await self.queue.get()
yield item
self.queue.task_done()
async def webhook_listener(self):
print("a request!")
text: str = await request.get_data()
print("text", text)
data = json.loads(text)
if type(data) is not dict or "event" not in data or data["event"].get("name") != "wallet_receive":
return "", HTTPStatus.NO_CONTENT
charge_id = data["id"]
if data["status"] != "paid":
return "", HTTPStatus.NO_CONTENT
x = hmac.new(self.auth_invoice["Authorization"], digestmod="sha256")
x.update(charge_id)
if x.hexdigest() != data["hashed_order"]:
print("invalid webhook, not from opennode")
return "", HTTPStatus.NO_CONTENT
self.queue.put_nowait(charge_id)
return "", HTTPStatus.NO_CONTENT