mirror of
https://github.com/aljazceru/nutshell.git
synced 2026-01-07 02:44:19 +01:00
Mint: add websockets for quote updates (#413)
* add websockets for quote updates * add test (not working) * wip: emit events to everyone * wip: emit events to everyone * wip, lots of things broken but invoice callback works * wip * add wip files * tests almost passing * add task * refactor nut constants * startup fix * works with old mints * wip cli * fix mypy * remove automatic invoice test now with websockets * remove comment * better logging * send back response * add rate limiter to websocket * add rate limiter to subscriptions * refactor websocket ratelimit * websocket tests * subscription kinds * doesnt start * remove circular import * update * fix mypy * move test file in test because it fails if it runs later... dunno why * adjust websocket NUT-06 settings * local import and small fix * disable websockets in CLI if "no_check" is selected * move subscription test to where it was * check proof state with callback, add tests * tests: run mint fixture per module instead of per session * subscription command name fix * test per session again * update test race conditions * fix tests * clean up * tmp * fix db issues and remove cached secrets * fix tests * blindly try pipeline * remove comments * comments
This commit is contained in:
97
cashu/mint/db/write.py
Normal file
97
cashu/mint/db/write.py
Normal file
@@ -0,0 +1,97 @@
|
||||
import asyncio
|
||||
from typing import List, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ...core.base import Proof, ProofState, SpentState
|
||||
from ...core.db import Connection, Database, get_db_connection
|
||||
from ...core.errors import (
|
||||
TransactionError,
|
||||
)
|
||||
from ..crud import LedgerCrud
|
||||
from ..events.events import LedgerEventManager
|
||||
|
||||
|
||||
class DbWriteHelper:
|
||||
db: Database
|
||||
crud: LedgerCrud
|
||||
events: LedgerEventManager
|
||||
proofs_pending_lock: asyncio.Lock = (
|
||||
asyncio.Lock()
|
||||
) # holds locks for proofs_pending database
|
||||
|
||||
def __init__(
|
||||
self, db: Database, crud: LedgerCrud, events: LedgerEventManager
|
||||
) -> None:
|
||||
self.db = db
|
||||
self.crud = crud
|
||||
self.events = events
|
||||
|
||||
async def _set_proofs_pending(
|
||||
self, proofs: List[Proof], quote_id: Optional[str] = None
|
||||
) -> None:
|
||||
"""If none of the proofs is in the pending table (_validate_proofs_pending), adds proofs to
|
||||
the list of pending proofs or removes them. Used as a mutex for proofs.
|
||||
|
||||
Args:
|
||||
proofs (List[Proof]): Proofs to add to pending table.
|
||||
quote_id (Optional[str]): Melt quote ID. If it is not set, we assume the pending tokens to be from a swap.
|
||||
|
||||
Raises:
|
||||
Exception: At least one proof already in pending table.
|
||||
"""
|
||||
# first we check whether these proofs are pending already
|
||||
async with self.proofs_pending_lock:
|
||||
async with get_db_connection(self.db) as conn:
|
||||
await self._validate_proofs_pending(proofs, conn)
|
||||
try:
|
||||
for p in proofs:
|
||||
await self.crud.set_proof_pending(
|
||||
proof=p, db=self.db, quote_id=quote_id, conn=conn
|
||||
)
|
||||
await self.events.submit(
|
||||
ProofState(Y=p.Y, state=SpentState.pending)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set proofs pending: {e}")
|
||||
raise TransactionError("Failed to set proofs pending.")
|
||||
|
||||
async def _unset_proofs_pending(self, proofs: List[Proof], spent=True) -> None:
|
||||
"""Deletes proofs from pending table.
|
||||
|
||||
Args:
|
||||
proofs (List[Proof]): Proofs to delete.
|
||||
spent (bool): Whether the proofs have been spent or not. Defaults to True.
|
||||
This should be False if the proofs were NOT invalidated before calling this function.
|
||||
It is used to emit the unspent state for the proofs (otherwise the spent state is emitted
|
||||
by the _invalidate_proofs function when the proofs are spent).
|
||||
"""
|
||||
async with self.proofs_pending_lock:
|
||||
async with get_db_connection(self.db) as conn:
|
||||
for p in proofs:
|
||||
await self.crud.unset_proof_pending(proof=p, db=self.db, conn=conn)
|
||||
if not spent:
|
||||
await self.events.submit(
|
||||
ProofState(Y=p.Y, state=SpentState.unspent)
|
||||
)
|
||||
|
||||
async def _validate_proofs_pending(
|
||||
self, proofs: List[Proof], conn: Optional[Connection] = None
|
||||
) -> None:
|
||||
"""Checks if any of the provided proofs is in the pending proofs table.
|
||||
|
||||
Args:
|
||||
proofs (List[Proof]): Proofs to check.
|
||||
|
||||
Raises:
|
||||
Exception: At least one of the proofs is in the pending table.
|
||||
"""
|
||||
if not (
|
||||
len(
|
||||
await self.crud.get_proofs_pending(
|
||||
Ys=[p.Y for p in proofs], db=self.db, conn=conn
|
||||
)
|
||||
)
|
||||
== 0
|
||||
):
|
||||
raise TransactionError("proofs are pending.")
|
||||
Reference in New Issue
Block a user