Files
ja4-platform/shared/python/ja4_common/ja4_common/clickhouse.py
toto 3dfeba860b docs: add standardized comments to all services (Python, Go, Bash)
- Add docs/commenting-standard.md defining per-language comment standards
  (Go godoc, Python PEP-257, C Doxygen, Bash header blocks, SQL banners)

- services/dashboard: 100% docstring coverage (100/100 functions)
  - All FastAPI route handlers, helpers, classes, and models documented
  - Language: French (project convention)

- services/bot-detector: 100% docstring coverage (53/53 symbols)
  - bot_detector.py: 14 functions + module docstring
  - anubis/fetch_rules.py: 9 functions

- shared/python/ja4_common: full docstrings on ClickHouseClient (7 methods)
  and ClickHouseSettings class

- services/correlator: 24 godoc comments added across 6 Go files
  - correlation_service.go: 10 private helpers
  - unixsocket/source.go: 6 parsing/socket helpers
  - correlated_log.go: 4 field extraction helpers
  - orchestrator.go, logger.go, main.go: 4 comments

- services/correlator/scripts/audit-architecture.sh: standardized header block

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-07 21:32:29 +02:00

71 lines
2.5 KiB
Python

"""Client ClickHouse singleton partagé pour la suite de sécurité JA4."""
import clickhouse_connect
from typing import Optional
from .settings import settings
class ClickHouseClient:
"""Client ClickHouse singleton avec reconnexion automatique.
Attributs :
_client : instance du client clickhouse_connect sous-jacent,
ou None si la connexion n'est pas encore établie.
"""
def __init__(self):
"""Initialise le client sans ouvrir de connexion immédiate."""
self._client: Optional[clickhouse_connect.driver.client.Client] = None
def connect(self) -> clickhouse_connect.driver.client.Client:
"""Retourne un client connecté, en créant ou rétablissant la connexion si nécessaire."""
if self._client is None or not self._ping():
self._client = clickhouse_connect.get_client(
host=settings.CLICKHOUSE_HOST,
port=settings.CLICKHOUSE_PORT,
database=settings.CLICKHOUSE_DB,
user=settings.CLICKHOUSE_USER,
password=settings.CLICKHOUSE_PASSWORD,
connect_timeout=10,
)
return self._client
def _ping(self) -> bool:
"""Vérifie que la connexion existante est active. Retourne False en cas d'erreur."""
try:
if self._client:
self._client.ping()
return True
except Exception:
pass
return False
def query(self, query: str, params: Optional[dict] = None):
"""Exécute une requête SELECT et retourne le résultat."""
return self.connect().query(query, params)
def command(self, query: str, params: Optional[dict] = None):
"""Exécute une commande DDL/DML (INSERT, CREATE, TRUNCATE, etc.)."""
return self.connect().command(query, parameters=params)
def insert(self, table: str, data, column_names=None):
"""Insère des données dans la table cible."""
return self.connect().insert(table, data, column_names=column_names)
def close(self):
"""Ferme la connexion et réinitialise le client interne."""
if self._client:
self._client.close()
self._client = None
_client: Optional[ClickHouseClient] = None
def get_client() -> ClickHouseClient:
"""Retourne l'instance singleton du ClickHouseClient, en la créant si nécessaire."""
global _client
if _client is None:
_client = ClickHouseClient()
return _client