Adding bitcoinswitch to lnurldevices

This commit is contained in:
ben
2022-10-06 17:10:15 +01:00
parent 27bae6a0c6
commit 3222ae198d
6 changed files with 135 additions and 4 deletions

View File

@@ -2,6 +2,7 @@ from fastapi import APIRouter
from lnbits.db import Database
from lnbits.helpers import template_renderer
from lnbits.tasks import catch_everything_and_restart
db = Database("ext_lnurldevice")
@@ -11,7 +12,11 @@ lnurldevice_ext: APIRouter = APIRouter(prefix="/lnurldevice", tags=["lnurldevice
def lnurldevice_renderer():
return template_renderer(["lnbits/extensions/lnurldevice/templates"])
from .tasks import wait_for_paid_invoices
from .lnurl import * # noqa
from .views import * # noqa
from .views_api import * # noqa
def lnurldevice_start():
loop = asyncio.get_event_loop()
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))

View File

@@ -102,7 +102,22 @@ async def lnurl_v1_params(
if device.device == "atm":
if paymentcheck:
return {"status": "ERROR", "reason": f"Payment already claimed"}
if device.device == "switch":
lnurldevicepayment = await create_lnurldevicepayment(
deviceid=device.id,
sats=device.profit,
)
if not lnurldevicepayment:
return {"status": "ERROR", "reason": "Could not create payment."}
return {
"tag": "payRequest",
"callback": request.url_for(
"lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id
),
"minSendable": device.profit * 1000,
"maxSendable": device.profit * 1000,
"metadata": await device.lnurlpay_metadata(),
}
if len(p) % 4 > 0:
p += "=" * (4 - (len(p) % 4))
@@ -205,6 +220,27 @@ async def lnurl_callback(
extra={"tag": "withdraw"},
)
return {"status": "OK"}
if device.device == "switch":
payment_hash, payment_request = await create_invoice(
wallet_id=device.wallet,
amount=lnurldevicepayment.sats / 1000,
memo=device.title,
unhashed_description=(await device.lnurlpay_metadata()).encode("utf-8"),
extra={"tag": "Switch", "id": device.paymentid, "time": device.amount},
)
lnurldevicepayment = await update_lnurldevicepayment(
lnurldevicepayment_id=paymentid, payhash=payment_hash
)
return {
"pr": payment_request,
"successAction": {
"tag": "url",
"description": "Check the attached link",
"url": request.url_for("lnurldevice.displaypin", paymentid=paymentid),
},
"routes": [],
}
payment_hash, payment_request = await create_invoice(
wallet_id=device.wallet,
@@ -226,5 +262,3 @@ async def lnurl_callback(
},
"routes": [],
}
return resp.dict()

View File

@@ -79,3 +79,9 @@ async def m002_redux(db):
)
except:
return
async def m003_redux(db):
"""
Add 'meta' for storing various metadata about the wallet
"""
await db.execute("ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount INT DEFAULT 0;")

View File

@@ -17,6 +17,7 @@ class createLnurldevice(BaseModel):
currency: str
device: str
profit: float
amount: int
class lnurldevices(BaseModel):
@@ -27,6 +28,7 @@ class lnurldevices(BaseModel):
currency: str
device: str
profit: float
amount: int
timestamp: str
def from_row(cls, row: Row) -> "lnurldevices":

View File

@@ -0,0 +1,39 @@
import asyncio
import json
from http import HTTPStatus
from urllib.parse import urlparse
import httpx
from fastapi import HTTPException
from lnbits import bolt11
from lnbits.core.models import Payment
from lnbits.core.services import pay_invoice
from lnbits.helpers import get_current_extension_name
from lnbits.tasks import register_invoice_listener
from .crud import get_lnurldevice
from .views import updater
async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
register_invoice_listener(invoice_queue, get_current_extension_name())
while True:
payment = await invoice_queue.get()
await on_invoice_paid(payment)
async def on_invoice_paid(payment: Payment) -> None:
# (avoid loops)
if "switch" == payment.extra.get("tag"):
lnurldevicepayment = await get_lnurldevicepayment(payment.extra.get("id"))
if not lnurldevicepayment:
return
if lnurldevicepayment.payhash == "used":
return
lnurldevicepayment = await update_lnurldevicepayment(
lnurldevicepayment_id=paymentid, payhash="used"
)
return await updater(lnurldevicepayment.deviceid)
return

View File

@@ -51,3 +51,48 @@ async def displaypin(request: Request, paymentid: str = Query(None)):
"lnurldevice/error.html",
{"request": request, "pin": "filler", "not_paid": True},
)
##################WEBSOCKET ROUTES########################
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket, lnurldevice_id: str):
await websocket.accept()
websocket.id = lnurldevice_id
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def send_personal_message(self, message: str, lnurldevice_id: str):
for connection in self.active_connections:
if connection.id == lnurldevice_id:
await connection.send_text(message)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@lnurldevice_ext.websocket("/ws/{lnurldevice_id}", name="lnurldevice.lnurldevice_by_id")
async def websocket_endpoint(websocket: WebSocket, lnurldevice_id: str):
await manager.connect(websocket, lnurldevice_id)
try:
while True:
data = await websocket.receive_text()
except WebSocketDisconnect:
manager.disconnect(websocket)
async def updater(lnurldevice_id):
lnurldevice = await get_lnurldevice(lnurldevice_id)
if not lnurldevice:
return
await manager.send_personal_message(f"{lnurldevice.amount}", lnurldevice_id)