Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix LNbits backend to use proper BaseModels #352

Merged
merged 1 commit into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cashu/lightning/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
class FakeWallet(Wallet):
"""https://github.com/lnbits/lnbits"""

queue: asyncio.Queue = asyncio.Queue(0)
queue: asyncio.Queue[Bolt11] = asyncio.Queue(0)
paid_invoices: Set[str] = set()
secret: str = "FAKEWALLET SECRET"
privkey: str = hashlib.pbkdf2_hmac(
Expand All @@ -52,7 +52,6 @@ async def create_invoice(
unhashed_description: Optional[bytes] = None,
expiry: Optional[int] = None,
payment_secret: Optional[bytes] = None,
**_,
) -> InvoiceResponse:
tags = Tags()

Expand Down
97 changes: 45 additions & 52 deletions cashu/lightning/lnbits.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# type: ignore
from typing import Dict, Optional
from typing import Optional

import httpx

Expand Down Expand Up @@ -29,18 +29,25 @@ async def status(self) -> StatusResponse:
r.raise_for_status()
except Exception as exc:
return StatusResponse(
f"Failed to connect to {self.endpoint} due to: {exc}", 0
error_message=f"Failed to connect to {self.endpoint} due to: {exc}",
balance_msat=0,
)

try:
data = r.json()
data: dict = r.json()
except Exception:
return StatusResponse(
f"Failed to connect to {self.endpoint}, got: '{r.text[:200]}...'", 0
error_message=(
f"Failed to connect to {self.endpoint}, got: '{r.text[:200]}...'"
),
balance_msat=0,
)
if "detail" in data:
return StatusResponse(f"LNbits error: {data['detail']}", 0)
return StatusResponse(None, data["balance"])
return StatusResponse(
error_message=f"LNbits error: {data['detail']}", balance_msat=0
)

return StatusResponse(error_message=None, balance_msat=data["balance"])

async def create_invoice(
self,
Expand All @@ -49,7 +56,7 @@ async def create_invoice(
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
) -> InvoiceResponse:
data: Dict = {"out": False, "amount": amount}
data = {"out": False, "amount": amount}
if description_hash:
data["description_hash"] = description_hash.hex()
if unhashed_description:
Expand All @@ -62,18 +69,19 @@ async def create_invoice(
)
r.raise_for_status()
except Exception:
return InvoiceResponse(False, None, None, r.json()["detail"])
ok, checking_id, payment_request, error_message = (
True,
None,
None,
None,
)
return InvoiceResponse(
ok=False,
error_message=r.json()["detail"],
)

data = r.json()
checking_id, payment_request = data["checking_id"], data["payment_request"]

return InvoiceResponse(ok, checking_id, payment_request, error_message)
return InvoiceResponse(
ok=True,
checking_id=checking_id,
payment_request=payment_request,
)

async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
try:
Expand All @@ -84,20 +92,24 @@ async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse
)
r.raise_for_status()
except Exception:
error_message = r.json()["detail"]
return PaymentResponse(None, None, None, None, error_message)
return PaymentResponse(error_message=r.json()["detail"])
if r.status_code > 299:
return PaymentResponse(None, None, None, None, f"HTTP status: {r.reason}")
return PaymentResponse(error_message=(f"HTTP status: {r.reason_phrase}",))
if "detail" in r.json():
return PaymentResponse(None, None, None, None, r.json()["detail"])
return PaymentResponse(error_message=(r.json()["detail"],))

data = r.json()
data: dict = r.json()
checking_id = data["payment_hash"]

# we do this to get the fee and preimage
payment: PaymentStatus = await self.get_payment_status(checking_id)

return PaymentResponse(True, checking_id, payment.fee_msat, payment.preimage)
return PaymentResponse(
ok=True,
checking_id=checking_id,
fee_msat=payment.fee_msat,
preimage=payment.preimage,
)

async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
try:
Expand All @@ -106,10 +118,11 @@ async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
)
r.raise_for_status()
except Exception:
return PaymentStatus(None)
if r.json().get("detail"):
return PaymentStatus(None)
return PaymentStatus(r.json()["paid"])
return PaymentStatus(paid=None)
data: dict = r.json()
if data.get("detail"):
return PaymentStatus(paid=None)
return PaymentStatus(paid=r.json()["paid"])

async def get_payment_status(self, checking_id: str) -> PaymentStatus:
try:
Expand All @@ -118,33 +131,13 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus:
)
r.raise_for_status()
except Exception:
return PaymentStatus(None)
return PaymentStatus(paid=None)
data = r.json()
if "paid" not in data and "details" not in data:
return PaymentStatus(None)
return PaymentStatus(paid=None)

return PaymentStatus(data["paid"], data["details"]["fee"], data["preimage"])

# async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
# url = f"{self.endpoint}/api/v1/payments/sse"

# while True:
# try:
# async with requests.stream("GET", url) as r:
# async for line in r.aiter_lines():
# if line.startswith("data:"):
# try:
# data = json.loads(line[5:])
# except json.decoder.JSONDecodeError:
# continue

# if type(data) is not dict:
# continue

# yield data["payment_hash"] # payment_hash

# except:
# pass

# print("lost connection to lnbits /payments/sse, retrying in 5 seconds")
# await asyncio.sleep(5)
return PaymentStatus(
paid=data["paid"],
fee_msat=data["details"]["fee"],
preimage=data["preimage"],
)
Loading