mirror of
https://github.com/lnbits/lnbits.git
synced 2025-06-02 19:21:37 +02:00
chore: code clean-up
This commit is contained in:
parent
2044c9f14b
commit
5ffc7185e8
@ -59,7 +59,7 @@ class TokenBucket:
|
|||||||
# Calculate time needed for one token
|
# Calculate time needed for one token
|
||||||
wait_time = (self.period / self.rate) * (1 - self.tokens)
|
wait_time = (self.period / self.rate) * (1 - self.tokens)
|
||||||
await asyncio.sleep(wait_time)
|
await asyncio.sleep(wait_time)
|
||||||
|
|
||||||
# After waiting, update time and add one token
|
# After waiting, update time and add one token
|
||||||
self.last_refill = time.monotonic()
|
self.last_refill = time.monotonic()
|
||||||
self.tokens = 1 # We now have exactly one token available
|
self.tokens = 1 # We now have exactly one token available
|
||||||
@ -132,7 +132,7 @@ class StrikeWallet(Wallet):
|
|||||||
try:
|
try:
|
||||||
await self.client.aclose()
|
await self.client.aclose()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Error closing Strike client")
|
logger.error("Error closing Strike client")
|
||||||
|
|
||||||
# --------------------------------------------------------------------- #
|
# --------------------------------------------------------------------- #
|
||||||
# low-level request helpers #
|
# low-level request helpers #
|
||||||
@ -246,7 +246,7 @@ class StrikeWallet(Wallet):
|
|||||||
logger.error(f"Strike API error: {e.response.text}")
|
logger.error(f"Strike API error: {e.response.text}")
|
||||||
return StatusResponse(f"Strike API error: {e.response.text}", 0)
|
return StatusResponse(f"Strike API error: {e.response.text}", 0)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Unexpected error in status()")
|
logger.error("Unexpected error in status()")
|
||||||
return StatusResponse("Connection error", 0)
|
return StatusResponse("Connection error", 0)
|
||||||
|
|
||||||
async def create_invoice(
|
async def create_invoice(
|
||||||
@ -266,7 +266,7 @@ class StrikeWallet(Wallet):
|
|||||||
"amount": {
|
"amount": {
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
"amount": str(btc_amt),
|
"amount": str(btc_amt),
|
||||||
}, # Set amount in BTC.
|
},
|
||||||
"description": memo or "",
|
"description": memo or "",
|
||||||
},
|
},
|
||||||
"targetCurrency": "BTC",
|
"targetCurrency": "BTC",
|
||||||
@ -291,12 +291,13 @@ class StrikeWallet(Wallet):
|
|||||||
ok=True, checking_id=invoice_id, payment_request=bolt11
|
ok=True, checking_id=invoice_id, payment_request=bolt11
|
||||||
)
|
)
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
|
logger.error(e)
|
||||||
msg = e.response.json().get(
|
msg = e.response.json().get(
|
||||||
"message", e.response.text
|
"message", e.response.text
|
||||||
) # Get error message from response.
|
) # Get error message from response.
|
||||||
return InvoiceResponse(ok=False, error_message=f"Strike API error: {msg}")
|
return InvoiceResponse(ok=False, error_message=f"Strike API error: {msg}")
|
||||||
except Exception:
|
except Exception as e:
|
||||||
logger.exception("Error in create_invoice()")
|
logger.error(e)
|
||||||
return InvoiceResponse(ok=False, error_message="Connection error")
|
return InvoiceResponse(ok=False, error_message="Connection error")
|
||||||
|
|
||||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||||
@ -306,148 +307,121 @@ class StrikeWallet(Wallet):
|
|||||||
"/payment-quotes/lightning",
|
"/payment-quotes/lightning",
|
||||||
json={"lnInvoice": bolt11},
|
json={"lnInvoice": bolt11},
|
||||||
)
|
)
|
||||||
quote_id = q.json().get("paymentQuoteId") # Get the payment quote ID.
|
quote_id = q.json().get("paymentQuoteId")
|
||||||
if not quote_id: # Check if the quote ID is present.
|
if not quote_id:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
False, None, None, None, "Strike: missing paymentQuoteId"
|
ok=False, error_message="Strike: missing paymentQuoteId"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2) Execute the payment quote.
|
# 2) Execute the payment quote.
|
||||||
e = await self._patch(f"/payment-quotes/{quote_id}/execute")
|
e = await self._patch(f"/payment-quotes/{quote_id}/execute")
|
||||||
data = (
|
data = e.json() if e.content else {}
|
||||||
e.json() if e.content else {}
|
payment_id = data.get("paymentId")
|
||||||
) # Parse JSON response or use an empty dictionary.
|
state = data.get("state", "").upper()
|
||||||
payment_id = data.get("paymentId") # Get the payment ID.
|
|
||||||
state = data.get(
|
|
||||||
"state", ""
|
|
||||||
).upper() # Get the payment state and convert it to uppercase.
|
|
||||||
|
|
||||||
# Network fee → msat.
|
# Network fee → msat.
|
||||||
fee_obj = (
|
fee_obj = data.get("lightningNetworkFee") or data.get("totalFee") or {}
|
||||||
data.get("lightningNetworkFee") or data.get("totalFee") or {}
|
fee_btc = Decimal(fee_obj.get("amount", "0"))
|
||||||
) # Get fee object.
|
fee_msat = int(fee_btc * Decimal(1e11)) # millisatoshis.
|
||||||
fee_btc = Decimal(fee_obj.get("amount", "0")) # Get fee amount in BTC.
|
|
||||||
fee_msat = int(
|
|
||||||
fee_btc * Decimal(1e11)
|
|
||||||
) # Convert fee from BTC to millisatoshis.
|
|
||||||
|
|
||||||
# Store mapping for later polling.
|
# Store mapping for later polling.
|
||||||
if payment_id: # If payment ID is present.
|
if payment_id: # If payment ID is present.
|
||||||
self.pending_payments[payment_id] = quote_id
|
self.pending_payments[payment_id] = quote_id
|
||||||
|
|
||||||
if state in {"SUCCEEDED", "COMPLETED"}: # If payment succeeded.
|
if state in {"SUCCEEDED", "COMPLETED"}:
|
||||||
preimage = data.get("preimage") or data.get(
|
preimage = data.get("preimage") or data.get("preImage")
|
||||||
"preImage"
|
|
||||||
) # Get payment preimage.
|
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
True, payment_id, fee_msat, preimage, None
|
ok=True,
|
||||||
) # Return successful payment response.
|
checking_id=payment_id,
|
||||||
|
fee_msat=fee_msat,
|
||||||
|
preimage=preimage,
|
||||||
|
)
|
||||||
|
|
||||||
# Explicitly check for known failure states.
|
|
||||||
failed_states = {
|
failed_states = {
|
||||||
"CANCELED",
|
"CANCELED",
|
||||||
"FAILED",
|
"FAILED",
|
||||||
"TIMED_OUT",
|
"TIMED_OUT",
|
||||||
} # Add any other known failure states here.
|
}
|
||||||
if state in failed_states:
|
if state in failed_states:
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
False, payment_id, None, None, f"State: {state}"
|
ok=False, checking_id=payment_id, error_message=f"State: {state}"
|
||||||
) # Return failed payment response with state.
|
)
|
||||||
|
|
||||||
# Treat all other states as pending (including unknown states).
|
# Treat all other states as pending (including unknown states).
|
||||||
return PaymentResponse(
|
return PaymentResponse(ok=None, checking_id=payment_id)
|
||||||
None, payment_id, None, None, None
|
|
||||||
) # Return pending payment response.
|
|
||||||
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
error_message = e.response.json().get(
|
error_message = e.response.json().get("message", e.response.text)
|
||||||
"message", e.response.text
|
# Keep pending. Not sure if the payment went trough or not.
|
||||||
) # Get error message from response.
|
|
||||||
return PaymentResponse(
|
return PaymentResponse(
|
||||||
ok=False,
|
ok=None,
|
||||||
checking_id=None,
|
|
||||||
fee_msat=None,
|
|
||||||
preimage=None,
|
|
||||||
error_message=f"Strike API error: {error_message}",
|
error_message=f"Strike API error: {error_message}",
|
||||||
) # Return payment response with error.
|
)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
logger.exception("Error in pay_invoice()")
|
logger.error(e)
|
||||||
return PaymentResponse(False, None, None, None, "Connection error")
|
# Keep pending. Not sure if the payment went trough or not.
|
||||||
|
return PaymentResponse(ok=None, error_message="Connection error")
|
||||||
|
|
||||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||||
try:
|
try:
|
||||||
r = await self._get(
|
r = await self._get(f"/receive-requests/{checking_id}/receives")
|
||||||
f"/receive-requests/{checking_id}/receives"
|
for itm in r.json().get("items", []):
|
||||||
) # Get receive requests for the invoice.
|
if itm.get("state") == "COMPLETED":
|
||||||
for itm in r.json().get("items", []): # Iterate through received items.
|
|
||||||
if itm.get("state") == "COMPLETED": # If an item is completed.
|
|
||||||
# Extract preimage from lightning object if available
|
# Extract preimage from lightning object if available
|
||||||
preimage = None
|
preimage = None
|
||||||
lightning_data = itm.get("lightning")
|
lightning_data = itm.get("lightning")
|
||||||
if lightning_data:
|
if lightning_data:
|
||||||
preimage = lightning_data.get("preimage")
|
preimage = lightning_data.get("preimage")
|
||||||
return PaymentSuccessStatus(
|
return PaymentSuccessStatus(fee_msat=0, preimage=preimage)
|
||||||
fee_msat=0, preimage=preimage
|
return PaymentPendingStatus()
|
||||||
) # Return successful payment status with preimage.
|
|
||||||
return (
|
|
||||||
PaymentPendingStatus()
|
|
||||||
) # Return pending payment status if no completed items.
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
if e.response.status_code == 404: # If invoice not found.
|
if e.response.status_code == 404: # If invoice not found.
|
||||||
try:
|
try:
|
||||||
r2 = await self._get(
|
# Try getting invoice from the old endpoint with correct path.
|
||||||
f"/v1/invoices/{checking_id}"
|
r2 = await self._get(f"/v1/invoices/{checking_id}")
|
||||||
) # Try getting invoice from the old endpoint with correct path.
|
st = r2.json().get("state", "")
|
||||||
st = r2.json().get("state", "") # Get invoice state.
|
if st == "PAID":
|
||||||
if st == "PAID": # If invoice is paid.
|
return PaymentSuccessStatus(fee_msat=0)
|
||||||
return PaymentSuccessStatus(
|
if st == "CANCELLED":
|
||||||
fee_msat=0
|
return PaymentFailedStatus(False)
|
||||||
) # Return successful payment status.
|
|
||||||
if st == "CANCELLED": # If invoice is cancelled.
|
|
||||||
return PaymentStatus(False) # Return failed payment status.
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # Ignore exceptions from the old endpoint.
|
pass # Ignore exceptions from the old endpoint.
|
||||||
return PaymentPendingStatus() # Return pending payment status.
|
return PaymentPendingStatus()
|
||||||
except Exception: # Handle other exceptions.
|
except Exception as e:
|
||||||
logger.exception("Error in get_invoice_status()")
|
logger.error(e)
|
||||||
return PaymentPendingStatus()
|
return PaymentPendingStatus()
|
||||||
|
|
||||||
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||||
quote_id = self.pending_payments.get(checking_id)
|
quote_id = self.pending_payments.get(checking_id)
|
||||||
if not quote_id: # Payment not found in pending list.
|
if not quote_id:
|
||||||
if checking_id in self.failed_payments:
|
if checking_id in self.failed_payments:
|
||||||
return PaymentFailedStatus(
|
return PaymentFailedStatus()
|
||||||
paid=False
|
|
||||||
) # Payment is known to have failed.
|
|
||||||
return PaymentPendingStatus()
|
return PaymentPendingStatus()
|
||||||
try: # Try to get payment quote.
|
try:
|
||||||
r = await self._get(
|
r = await self._get(f"/payment-quotes/{quote_id}")
|
||||||
f"/payment-quotes/{quote_id}"
|
|
||||||
) # Get payment quote from Strike API.
|
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
data = r.json() # Parse JSON response.
|
data = r.json()
|
||||||
state = data.get("state") # Get payment state.
|
state = data.get("state")
|
||||||
preimage = data.get("preimage") or data.get(
|
preimage = data.get("preimage") or data.get("preImage")
|
||||||
"preImage"
|
if state in {"SUCCEEDED", "COMPLETED"}:
|
||||||
) # Get payment preimage.
|
return PaymentSuccessStatus(fee_msat=0, preimage=preimage)
|
||||||
if state in ("SUCCEEDED", "COMPLETED"): # If payment succeeded.
|
# todo: check for FAILED status and default to pending
|
||||||
return PaymentSuccessStatus(
|
if state == "FAILED":
|
||||||
fee_msat=0, preimage=preimage
|
return PaymentFailedStatus()
|
||||||
) # Return successful payment status.
|
return PaymentPendingStatus()
|
||||||
if state == "FAILED": # Explicitly check for FAILED state
|
|
||||||
return PaymentStatus(False) # Return failed payment status.
|
|
||||||
# Default to pending for PENDING and any other states
|
|
||||||
return PaymentPendingStatus() # Return pending payment status.
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
|
# todo: better handle this inside the try block
|
||||||
|
# todo: right before r.raise_for_status()
|
||||||
if e.response.status_code == 404:
|
if e.response.status_code == 404:
|
||||||
# Quote not found, likely expired or payment failed.
|
# Quote not found, likely expired or payment failed.
|
||||||
self.pending_payments.pop(checking_id, None)
|
self.pending_payments.pop(checking_id, None)
|
||||||
self.failed_payments[checking_id] = quote_id
|
self.failed_payments[checking_id] = quote_id
|
||||||
return PaymentFailedStatus(paid=False)
|
return PaymentFailedStatus()
|
||||||
raise # Re-raise other HTTP errors
|
raise # Re-raise other HTTP errors
|
||||||
except Exception: # Handle exceptions.
|
except Exception as e: # Handle exceptions.
|
||||||
logger.exception(f"Error in get_payment_status() for payment {checking_id}")
|
logger.error(e)
|
||||||
return PaymentPendingStatus() # Treat as pending for now.
|
return PaymentPendingStatus()
|
||||||
|
|
||||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||||
"""
|
"""
|
||||||
@ -526,5 +500,5 @@ class StrikeWallet(Wallet):
|
|||||||
) # Get invoices from Strike API.
|
) # Get invoices from Strike API.
|
||||||
return r.json()
|
return r.json()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Error in get_invoices()")
|
logger.error("Error in get_invoices()")
|
||||||
return {"error": "unable to fetch invoices"}
|
return {"error": "unable to fetch invoices"}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user