from __future__ import annotations import sqlite3 from datetime import datetime, timezone class ReservationsRepository: def __init__(self, conn: sqlite3.Connection) -> None: self._conn = conn @staticmethod def _now() -> str: return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace( "+00:00", "Z", ) def create_reservation( self, reservation_id: str, handshake_id: int, method_id: str, method_version: int, job_id: str, client_id: str | None = None, expires_at: str | None = None, ) -> None: self._conn.execute( """ INSERT INTO crack_reservations ( id, handshake_id, method_id, method_version, job_id, client_id, status, created_at, expires_at, released_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( reservation_id, handshake_id, method_id, method_version, job_id, client_id, "ACTIVE", self._now(), expires_at, None, ), ) def get_reservation( self, reservation_id: str, ) -> sqlite3.Row | None: return self._conn.execute( """ SELECT id, handshake_id, method_id, method_version, job_id, client_id, status, created_at, expires_at, released_at FROM crack_reservations WHERE id = ? """, (reservation_id,), ).fetchone() def get_active_reservation( self, handshake_id: int, method_id: str, method_version: int, ) -> sqlite3.Row | None: return self._conn.execute( """ SELECT id, handshake_id, method_id, method_version, job_id, client_id, status, created_at, expires_at, released_at FROM crack_reservations WHERE handshake_id = ? AND method_id = ? AND method_version = ? AND status = 'ACTIVE' """, ( handshake_id, method_id, method_version, ), ).fetchone() def list_job_reservations( self, job_id: str, ) -> list[sqlite3.Row]: return self._conn.execute( """ SELECT id, handshake_id, method_id, method_version, job_id, client_id, status, created_at, expires_at, released_at FROM crack_reservations WHERE job_id = ? ORDER BY created_at, id """, (job_id,), ).fetchall() def list_client_reservations( self, client_id: str, status: str | None = None, ) -> list[sqlite3.Row]: query = """ SELECT id, handshake_id, method_id, method_version, job_id, client_id, status, created_at, expires_at, released_at FROM crack_reservations WHERE client_id = ? """ params: list[object] = [client_id] if status is not None: query += "\n AND status = ?" params.append(status) query += "\n ORDER BY created_at, id" return self._conn.execute(query, params).fetchall() def update_status( self, reservation_id: str, status: str, released_at: str | None = None, ) -> None: if released_at is None and status in { "RELEASED", "EXPIRED", "CANCELLED", }: released_at = self._now() self._conn.execute( """ UPDATE crack_reservations SET status = ?, released_at = ? WHERE id = ? """, ( status, released_at, reservation_id, ), ) def update_expires_at( self, reservation_id: str, expires_at: str | None, ) -> None: self._conn.execute( """ UPDATE crack_reservations SET expires_at = ? WHERE id = ? """, ( expires_at, reservation_id, ), )