chore: code clean-up

This commit is contained in:
Vlad Stan 2025-05-14 15:13:22 +03:00
parent 2044c9f14b
commit 5ffc7185e8

View File

@ -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"}