Files
geo/docs/gestion_hive_boxes.md

10 KiB

Guide de Gestion des Boîtes Hive dans GeoSector

Ce document explique comment les boîtes Hive sont gérées dans l'application GeoSector, particulièrement pendant les processus de connexion et déconnexion.

Table des matières

  1. Introduction
  2. Boîtes Hive utilisées
  3. Initialisation des boîtes Hive
  4. Services et repositories impliqués
  5. Processus de connexion (login)
  6. Processus de déconnexion (logout)
  7. Problèmes connus et solutions
  8. Bonnes pratiques

Introduction

Hive est une base de données NoSQL légère et rapide utilisée dans GeoSector pour stocker les données localement. Les données sont organisées en "boîtes" (boxes) qui peuvent être typées pour stocker des modèles spécifiques.

Dans cette application, Hive est utilisé pour :

  • Stocker les données utilisateur et maintenir les sessions
  • Conserver les données des opérations, secteurs et passages
  • Permettre l'utilisation de l'application en mode hors ligne

Boîtes Hive utilisées

Les boîtes Hive sont définies dans lib/core/constants/app_keys.dart :

// Noms des boîtes Hive
static const String usersBoxName = 'users';
static const String operationsBoxName = 'operations';
static const String sectorsBoxName = 'sectors';
static const String passagesBoxName = 'passages';
static const String settingsBoxName = 'settings';

Chaque boîte stocke un type spécifique de données :

  • users : Stocke les informations des utilisateurs (UserModel)
  • operations : Stocke les opérations (OperationModel)
  • sectors : Stocke les secteurs (SectorModel)
  • passages : Stocke les passages (PassageModel)
  • settings : Stocke les préférences utilisateur (non typée)

Initialisation des boîtes Hive

Actuellement, les boîtes Hive sont initialisées dès le démarrage de l'application dans main.dart :

// Initialiser Hive
await Hive.initFlutter();

// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());

// Ouvrir les boîtes Hive
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
await Hive.openBox<OperationModel>(AppKeys.operationsBoxName);
await Hive.openBox<SectorModel>(AppKeys.sectorsBoxName);
await Hive.openBox<PassageModel>(AppKeys.passagesBoxName);
await Hive.openBox(AppKeys.settingsBoxName);

Problème d'initialisation précoce

Cette approche ouvre toutes les boîtes Hive dès le démarrage de l'application, même sur les pages publiques comme LandingPage où elles ne sont pas nécessaires. Cela explique pourquoi vous voyez les messages suivants dans la console :

Got object store box in database users.
Got object store box in database operations.
Got object store box in database sectors.
Got object store box in database passages.
Got object store box in database settings.

Solution recommandée

Pour optimiser l'initialisation des boîtes Hive, il est recommandé de :

  1. N'initialiser que la boîte users au démarrage (pour vérifier si un utilisateur est déjà connecté)
  2. Initialiser les autres boîtes uniquement après une connexion réussie

Modification suggérée pour main.dart :

// Initialiser Hive
await Hive.initFlutter();

// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());

// N'ouvrir que la boîte des utilisateurs au démarrage
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
await Hive.openBox(AppKeys.settingsBoxName); // Préférences générales

// Les autres boîtes seront ouvertes après connexion dans UserRepository.login()

Services et repositories impliqués

UserRepository

Le UserRepository est le principal gestionnaire des boîtes Hive. Il est responsable de :

  • L'initialisation des boîtes au démarrage de l'application
  • La gestion des boîtes pendant les processus de connexion et déconnexion
  • Le nettoyage et la recréation des boîtes lorsque nécessaire

Autres repositories spécialisés

  • OperationRepository : Gère la boîte operations
  • SectorRepository : Gère la boîte sectors
  • PassageRepository : Gère la boîte passages

Ces repositories sont injectés dans le UserRepository pour traiter les données spécifiques à chaque modèle.

Processus de connexion (login)

Le processus de connexion dans UserRepository.login() suit ces étapes :

  1. Nettoyage initial :

    • Suppression des boîtes non référencées (auth, locations, messages)
    • Nettoyage adapté à la plateforme (Web, iOS, Android)
  2. Préparation des boîtes :

    • Appel à _clearAndRecreateBoxes() pour vider et recréer les boîtes sans les fermer
    • Utilisation de _ensureBoxIsOpen() pour garantir que les boîtes sont ouvertes
  3. Appel API et traitement des données :

    • Connexion via l'API
    • Vérification que toutes les boîtes sont ouvertes avant le traitement
    • Traitement des données reçues (opérations, secteurs, passages)
  4. Gestion des erreurs :

    • Tentatives de récupération en cas d'erreur
    • Réouverture des boîtes si nécessaire

Code clé pour la connexion

// S'assurer que les boîtes sont ouvertes
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
await _ensureBoxIsOpen(AppKeys.passagesBoxName);

// Traiter les données
await _processOperations(operationsData);
await _processSectors(sectorsData);
await _processPassages(passagesData);

Processus de déconnexion (logout)

Le processus de déconnexion dans UserRepository.logout() suit ces étapes :

  1. Préparation :

    • S'assurer que la boîte des utilisateurs est ouverte
    • Suppression des boîtes non référencées
  2. Gestion de l'utilisateur :

    • Récupération de l'utilisateur actuel avant nettoyage
    • Déconnexion de la session API
    • Mise à jour de l'utilisateur pour effacer les données de session
  3. Nettoyage des données :

    • Nettoyage adapté à la plateforme (Web, iOS, Android)
    • Appel à _clearAndRecreateBoxes() pour vider les boîtes sans les fermer

Code clé pour la déconnexion

// S'assurer que la boîte des utilisateurs est ouverte
await _ensureBoxIsOpen(AppKeys.usersBoxName);

// Récupérer l'utilisateur et effacer sa session
final updatedUser = currentUser.copyWith(
  sessionId: null,
  sessionExpiry: null,
  lastPath: null
);
await saveUser(updatedUser);

// Vider les boîtes sans les fermer
await _clearAndRecreateBoxes();

Problèmes connus et solutions

1. Initialisation précoce des boîtes Hive

Problème : Toutes les boîtes Hive sont ouvertes dès le démarrage de l'application, même sur les pages publiques où elles ne sont pas nécessaires.

Solution : Modifier main.dart pour n'ouvrir que les boîtes essentielles au démarrage (users et settings) et initialiser les autres boîtes uniquement après connexion.

2. Erreur "Box has already been closed"

Problème : Des erreurs se produisent lorsqu'on tente d'accéder à une boîte qui a été fermée prématurément.

Solution :

  • Utiliser la méthode _ensureBoxIsOpen() avant d'accéder à une boîte
  • Éviter de fermer les boîtes qui pourraient être utilisées plus tard
  • Préférer box.clear() à box.close() pour vider les données sans fermer la boîte

3. Persistance indésirable des données entre sessions

Problème : Les données peuvent persister entre les sessions utilisateur, créant des conflits ou des fuites de données.

Solution : Utiliser _clearAndRecreateBoxes() lors de la déconnexion pour vider correctement toutes les boîtes sauf users.

Bonnes pratiques

Initialisation à la demande

  1. Initialiser les boîtes uniquement lorsqu'elles sont nécessaires :

    • N'ouvrir que les boîtes users et settings au démarrage
    • Initialiser les autres boîtes après connexion réussie
    • Utiliser _ensureBoxIsOpen() avant chaque accès à une boîte
  2. Centraliser la gestion des boîtes :

    • Créer un service dédié à la gestion des boîtes Hive
    • Utiliser des méthodes comme openRequiredBoxes() et clearAllBoxes()
  3. Optimiser pour les différentes plateformes :

    • Adapter le nettoyage selon la plateforme (Web, iOS, Android)
    • Utiliser des méthodes spécifiques comme _clearIndexedDB() pour le web

Éviter l'erreur "Box has already been closed"

  1. Ne jamais fermer une boîte qui pourrait être utilisée plus tard :

    • Utiliser _ensureBoxIsOpen() au lieu de fermer et rouvrir les boîtes
    • Vider les boîtes avec box.clear() au lieu de les fermer
  2. Vérifier qu'une boîte est ouverte avant de l'utiliser :

    if (!Hive.isBoxOpen(boxName)) {
      await Hive.openBox<T>(boxName);
    }
    
  3. Gestion des erreurs robuste :

    • Toujours entourer les opérations Hive de blocs try/catch
    • Prévoir des mécanismes de récupération en cas d'erreur

Méthode utilitaire _ensureBoxIsOpen

Cette méthode est cruciale pour garantir qu'une boîte est ouverte avant de l'utiliser :

Future<void> _ensureBoxIsOpen(String boxName) async {
  try {
    if (!Hive.isBoxOpen(boxName)) {
      debugPrint('Ouverture de la boîte $boxName...');
      if (boxName == AppKeys.passagesBoxName) {
        await Hive.openBox<PassageModel>(boxName);
      } else if (boxName == AppKeys.operationsBoxName) {
        await Hive.openBox<OperationModel>(boxName);
      } else if (boxName == AppKeys.sectorsBoxName) {
        await Hive.openBox<SectorModel>(boxName);
      } else if (boxName == AppKeys.usersBoxName) {
        await Hive.openBox<UserModel>(boxName);
      } else {
        await Hive.openBox(boxName);
      }
      debugPrint('Boîte $boxName ouverte avec succès');
    }
  } catch (e) {
    debugPrint('Erreur lors de l\'ouverture de la boîte $boxName: $e');
    throw Exception('Impossible d\'ouvrir la boîte $boxName: $e');
  }
}

Ce guide devrait aider à comprendre et maintenir la gestion des boîtes Hive dans l'application GeoSector. Pour toute question ou problème, consultez la documentation de Hive ou contactez l'équipe de développement.