diff --git a/decnet/web/db/repository.py b/decnet/web/db/repository.py index 5368009d..188cd5b1 100644 --- a/decnet/web/db/repository.py +++ b/decnet/web/db/repository.py @@ -31,16 +31,34 @@ class BaseRepository(ABC): self, limit: int = 50, offset: int = 0, - search: Optional[str] = None + search: Optional[str] = None, + start_time: Optional[str] = None, + end_time: Optional[str] = None, ) -> list[dict[str, Any]]: """Retrieve paginated log entries.""" pass @abstractmethod - async def get_total_logs(self, search: Optional[str] = None) -> int: + async def get_total_logs( + self, + search: Optional[str] = None, + start_time: Optional[str] = None, + end_time: Optional[str] = None, + ) -> int: """Retrieve the total count of logs, optionally filtered by search.""" pass + @abstractmethod + async def get_log_histogram( + self, + search: Optional[str] = None, + start_time: Optional[str] = None, + end_time: Optional[str] = None, + interval_minutes: int = 15, + ) -> list[dict[str, Any]]: + """Return bucketed log counts for histogram display.""" + pass + @abstractmethod async def get_stats_summary(self) -> dict[str, Any]: """Retrieve high-level dashboard metrics.""" @@ -236,7 +254,14 @@ class BaseRepository(ABC): pass @abstractmethod - async def get_logs_after_id(self, last_id: int, limit: int = 500) -> list[dict[str, Any]]: + async def get_logs_after_id( + self, + last_id: int, + limit: int = 500, + search: Optional[str] = None, + start_time: Optional[str] = None, + end_time: Optional[str] = None, + ) -> list[dict[str, Any]]: """Return logs with id > last_id, ordered by id ASC, up to limit.""" pass @@ -737,7 +762,12 @@ class BaseRepository(ABC): async def list_topologies_needing_resync(self) -> list[TopologySummary]: raise NotImplementedError - async def add_lan(self, data: dict[str, Any]) -> str: + async def add_lan( + self, + data: dict[str, Any], + *, + expected_version: Optional[int] = None, + ) -> str: raise NotImplementedError async def update_lan( @@ -755,7 +785,12 @@ class BaseRepository(ABC): ) -> list[LANRow]: raise NotImplementedError - async def add_topology_decky(self, data: dict[str, Any]) -> str: + async def add_topology_decky( + self, + data: dict[str, Any], + *, + expected_version: Optional[int] = None, + ) -> str: raise NotImplementedError async def update_topology_decky( @@ -773,7 +808,12 @@ class BaseRepository(ABC): ) -> list[DeckyRow]: raise NotImplementedError - async def add_topology_edge(self, data: dict[str, Any]) -> str: + async def add_topology_edge( + self, + data: dict[str, Any], + *, + expected_version: Optional[int] = None, + ) -> str: raise NotImplementedError async def list_topology_edges( @@ -1233,3 +1273,30 @@ class BaseRepository(ABC): (stage 3b). """ raise NotImplementedError + + # -------------------- tarpit rules -------------------- + + async def set_tarpit_rule(self, data: dict[str, Any]) -> None: + raise NotImplementedError + + async def get_tarpit_rule(self, decky_name: str) -> Optional[dict[str, Any]]: + raise NotImplementedError + + async def delete_tarpit_rule(self, decky_name: str) -> bool: + raise NotImplementedError + + async def list_tarpit_rules(self) -> list[dict[str, Any]]: + raise NotImplementedError + + # -------------------- attacker export -------------------- + + async def get_all_attackers_for_export(self) -> list[dict[str, Any]]: + raise NotImplementedError + + # -------------------- fleet helpers -------------------- + + async def get_fleet_decky_by_name(self, name: str) -> Optional[dict[str, Any]]: + raise NotImplementedError + + async def count_probe_relays(self, attacker_ip: str, decky: str) -> int: + raise NotImplementedError