- Remplacement du QR code par un système de 4 mots - Interface unifiée avec détection automatique créateur/joiner - Amélioration UX avec feedback en temps réel - Design moderne glassmorphism avec animations - Validation intelligente des 4 mots pour le joiner - Status de progression détaillé pour les deux flux - Redirection automatique vers /account après pairing - Styles CSS améliorés avec variables et responsive design - Gestion d'erreurs et messages utilisateur clairs - Fonctionnalité de copie des 4 mots pour le créateur
285 lines
12 KiB
Markdown
285 lines
12 KiB
Markdown
# Analyse du Système de Pairing - Version Actuelle
|
||
|
||
## Vue d'ensemble
|
||
|
||
Ce document résume l'analyse complète du système de pairing et les corrections apportées pour résoudre les problèmes identifiés.
|
||
|
||
## Problèmes Identifiés et Solutions
|
||
|
||
### 1. Problème de `checkConnections` pour le Pairing
|
||
|
||
**Problème** : La méthode `checkConnections` a été mise à jour il y a un mois pour prendre un `Process` et un `stateId` au lieu d'une liste de membres, mais la gestion des processus de pairing était défaillante.
|
||
|
||
**Symptômes** :
|
||
- `checkConnections` échouait pour les processus de pairing
|
||
- Les adresses des membres n'étaient pas correctement récupérées
|
||
- Erreur "Not a pairing process" même pour des processus de pairing valides
|
||
|
||
**Solution Appliquée** :
|
||
```typescript
|
||
// Correction dans checkConnections pour gérer les pairedAddresses
|
||
if (members.size === 0) {
|
||
// This must be a pairing process
|
||
let publicData: Record<string, any> | null = null;
|
||
if (!stateId) {
|
||
publicData = process.states[process.states.length - 2]?.public_data;
|
||
} else {
|
||
publicData = process.states.find(state => state.state_id === stateId)?.public_data || null;
|
||
}
|
||
|
||
// If pairedAddresses is not in the current state, look in previous states
|
||
if (!publicData || !publicData['pairedAddresses']) {
|
||
// Look for pairedAddresses in previous states
|
||
for (let i = process.states.length - 1; i >= 0; i--) {
|
||
const state = process.states[i];
|
||
if (state.public_data && state.public_data['pairedAddresses']) {
|
||
publicData = state.public_data;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
const decodedAddresses = this.decodeValue(publicData['pairedAddresses']);
|
||
members.add({ sp_addresses: decodedAddresses });
|
||
}
|
||
```
|
||
|
||
### 2. Problème de `confirmPairing` avec `getPairingProcessId()`
|
||
|
||
**Problème** : `confirmPairing` échouait car `getPairingProcessId()` utilisait `sdkClient.get_pairing_process_id()` qui n'était pas encore disponible car le processus de pairing n'était pas encore committé.
|
||
|
||
**Symptômes** :
|
||
- Erreur "Failed to get pairing process" dans `confirmPairing`
|
||
- Le SDK n'avait pas encore le processus de pairing disponible
|
||
- Échec de confirmation du pairing
|
||
|
||
**Solution Appliquée** :
|
||
```typescript
|
||
public async confirmPairing(pairingId?: string) {
|
||
try {
|
||
console.log('confirmPairing');
|
||
let processId: string;
|
||
if (pairingId) {
|
||
processId = pairingId;
|
||
console.log('pairingId (provided):', processId);
|
||
} else if (this.processId) {
|
||
processId = this.processId;
|
||
console.log('pairingId (from stored processId):', processId);
|
||
} else {
|
||
// Try to get pairing process ID, with retry if it fails
|
||
let retries = 3;
|
||
while (retries > 0) {
|
||
try {
|
||
processId = this.getPairingProcessId();
|
||
console.log('pairingId (from SDK):', processId);
|
||
break;
|
||
} catch (e) {
|
||
retries--;
|
||
if (retries === 0) throw e;
|
||
console.log(`Failed to get pairing process ID, retrying... (${retries} attempts left)`);
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
}
|
||
}
|
||
}
|
||
// ... rest of the method
|
||
} catch (e) {
|
||
console.error('Failed to confirm pairing');
|
||
return;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Problème de `pairing_process_commitment` à `null`
|
||
|
||
**Problème** : Le `pairing_process_commitment` restait à `null` dans le device dump car le device n'était pas synchronisé avec l'état committé du processus.
|
||
|
||
**Symptômes** :
|
||
- `pairing_process_commitment: null` dans le device dump
|
||
- Le commitment n'était pas synchronisé avec l'état committé du processus
|
||
- Échec de la confirmation du pairing
|
||
|
||
**Solution Appliquée** :
|
||
```typescript
|
||
// Intégration de updateDevice() dans waitForPairingCommitment
|
||
public async waitForPairingCommitment(processId: string, maxRetries: number = 10, retryDelay: number = 1000): Promise<void> {
|
||
console.log(`Waiting for pairing process ${processId} to be committed...`);
|
||
|
||
// First, try to update the device to sync with the committed state
|
||
try {
|
||
await this.updateDevice();
|
||
console.log('Device updated, checking commitment...');
|
||
} catch (e) {
|
||
console.log('Failed to update device, continuing with polling...', e);
|
||
}
|
||
|
||
for (let i = 0; i < maxRetries; i++) {
|
||
try {
|
||
const device = this.dumpDeviceFromMemory();
|
||
console.log(`Attempt ${i + 1}/${maxRetries}: pairing_process_commitment =`, device.pairing_process_commitment);
|
||
|
||
// Check if the commitment is set and not null/empty
|
||
if (device.pairing_process_commitment &&
|
||
device.pairing_process_commitment !== null &&
|
||
device.pairing_process_commitment !== '') {
|
||
console.log('Pairing process commitment found:', device.pairing_process_commitment);
|
||
return;
|
||
}
|
||
} catch (e) {
|
||
console.log(`Attempt ${i + 1}/${maxRetries}: Device not ready yet - ${e}`);
|
||
}
|
||
|
||
if (i < maxRetries - 1) {
|
||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||
}
|
||
}
|
||
|
||
throw new Error(`Pairing process ${processId} was not committed after ${maxRetries} attempts`);
|
||
}
|
||
```
|
||
|
||
Et simplification du router :
|
||
```typescript
|
||
console.log("⏳ Waiting for pairing process to be committed...");
|
||
await services.waitForPairingCommitment(pairingId);
|
||
|
||
console.log("🔁 Confirming pairing...");
|
||
await services.confirmPairing(pairingId);
|
||
```
|
||
|
||
## Architecture du Système de Pairing
|
||
|
||
### Flux de Création du Pairing (Créateur)
|
||
|
||
1. **Création du processus** : `createPairingProcess("", [myAddress])`
|
||
2. **Enregistrement du device** : `pairDevice(pairingId, [myAddress])`
|
||
3. **Traitement de l'API** : `handleApiReturn(createPairingProcessReturn)`
|
||
4. **Création de la mise à jour PRD** : `createPrdUpdate(pairingId, stateId)`
|
||
5. **Approbation du changement** : `approveChange(pairingId, stateId)`
|
||
6. **Attente du commit avec synchronisation** : `waitForPairingCommitment(pairingId)` (inclut `updateDevice()`)
|
||
7. **Confirmation du pairing** : `confirmPairing(pairingId)`
|
||
|
||
### Flux de Rejoindre le Pairing (Joiner) - ⚠️ INCOHÉRENT
|
||
|
||
**Problème identifié** : Le joiner n'a pas de flux de confirmation complet.
|
||
|
||
**Flux actuel (incomplet)** :
|
||
1. **Création avec liste vide** : `createPairingProcess("", [])` ❌
|
||
2. **Établissement des connexions** : `checkConnections(process)`
|
||
3. **Pas de confirmation** : Aucun `waitForPairingCommitment` ou `confirmPairing` ❌
|
||
|
||
**Flux attendu (cohérent)** :
|
||
1. **Récupération du processus existant** : `getPairingProcessId()`
|
||
2. **Rejoindre le processus** : Pas de création, mais participation au processus existant
|
||
3. **Flux de confirmation complet** : Même flux que le créateur
|
||
4. **Attente du commit** : `waitForPairingCommitment()`
|
||
5. **Confirmation du pairing** : `confirmPairing()`
|
||
|
||
### Gestion des Connexions
|
||
|
||
La méthode `checkConnections` gère maintenant :
|
||
- **Processus normaux** : Utilise les rôles pour trouver les membres
|
||
- **Processus de pairing** : Utilise `pairedAddresses` des données publiques
|
||
- **Recherche dans les états précédents** : Si `pairedAddresses` n'est pas dans l'état actuel
|
||
- **Décodage des adresses** : Les données publiques sont encodées et nécessitent un décodage
|
||
|
||
## Points Clés Appris
|
||
|
||
### 1. Encodage des Données Publiques
|
||
- Les données publiques sont encodées avec `this.sdkClient.encode_json()`
|
||
- `pairedAddresses` nécessite un décodage avec `this.decodeValue()`
|
||
- Les données ne sont pas directement utilisables sans décodage
|
||
|
||
### 2. Gestion Multi-Hosts
|
||
- Le créateur et le joiner peuvent être sur des hosts différents
|
||
- Le joiner doit récupérer les adresses depuis le processus existant
|
||
- `this.processId` n'est disponible que sur le même host
|
||
|
||
### 3. Synchronisation du SDK
|
||
- Le SDK n'a pas immédiatement le processus de pairing disponible
|
||
- Il faut attendre que le processus soit committé
|
||
- `updateDevice()` est nécessaire pour synchroniser l'état
|
||
|
||
### 4. Gestion des États
|
||
- Les processus de pairing peuvent avoir des mises à jour partielles
|
||
- Il faut chercher `pairedAddresses` dans les états précédents si nécessaire
|
||
- La logique de fallback est cruciale pour la robustesse
|
||
|
||
## Version Actuelle
|
||
|
||
### État des Corrections
|
||
- ✅ `checkConnections` corrigé pour les processus de pairing
|
||
- ✅ `confirmPairing` avec gestion des paramètres et retry
|
||
- ✅ `waitForPairingCommitment` avec synchronisation automatique du device
|
||
- ✅ Intégration de `updateDevice()` dans `waitForPairingCommitment`
|
||
- ✅ Gestion des cas multi-hosts
|
||
- ✅ Simplification du flux de création
|
||
- ✅ **Flux du joiner implémenté** : Découverte et rejoindre un processus existant
|
||
- ✅ **Détection automatique** : Créateur vs Joiner via paramètre URL
|
||
|
||
### Fonctionnalités Opérationnelles
|
||
- **Création de pairing** : ✅ Fonctionne avec les adresses correctes
|
||
- **Rejoindre un pairing** : ✅ Flux complet avec découverte et synchronisation
|
||
- **Établissement des connexions** : ✅ `checkConnections` trouve les membres
|
||
- **Confirmation du pairing** : ✅ Côté créateur et joiner
|
||
- **Synchronisation du commitment** : ✅ Côté créateur et joiner
|
||
- **Flux simplifié** : ✅ Côté créateur et joiner
|
||
|
||
### Flux Unifié Créateur vs Joiner
|
||
|
||
#### Flux du Créateur
|
||
1. **Création** : `createPairingProcess()` avec son adresse
|
||
2. **QR Code** : `generateQRCode()` pour le joiner
|
||
3. **Attente** : `waitForJoinerAndUpdateProcess()` pour détecter le joiner
|
||
4. **Synchronisation** : `waitForPairingCommitment()`
|
||
5. **Confirmation** : `confirmPairing()`
|
||
|
||
#### Flux du Joiner
|
||
1. **Découverte** : `discoverAndJoinPairingProcess()` via QR code
|
||
2. **Synchronisation** : `waitForPairingCommitment()`
|
||
3. **Confirmation** : `confirmPairing()`
|
||
|
||
#### Détection Automatique
|
||
- **Créateur** : Pas de paramètre `sp_address` dans l'URL
|
||
- **Joiner** : Paramètre `sp_address` présent dans l'URL
|
||
- **Logique** : `onCreateButtonClick()` détecte automatiquement le flux
|
||
|
||
### Améliorations Récentes
|
||
|
||
#### Synchronisation Automatique du Device
|
||
- **Intégration de `updateDevice()`** : Appelé automatiquement dans `waitForPairingCommitment`
|
||
- **Gestion des erreurs** : Continue le polling même si `updateDevice()` échoue
|
||
- **Logs détaillés** : Suivi complet du processus de synchronisation
|
||
- **Temps d'attente augmenté** : 30 tentatives × 2 secondes = 60 secondes max
|
||
|
||
#### Simplification du Flux
|
||
- **Moins d'étapes manuelles** : `updateDevice()` intégré dans `waitForPairingCommitment`
|
||
- **Flux plus robuste** : Gestion automatique de la synchronisation
|
||
- **Code plus maintenable** : Logique centralisée dans une seule méthode
|
||
|
||
### Points d'Attention
|
||
- Le système nécessite que les deux côtés soient synchronisés
|
||
- Les retry automatiques sont implémentés pour la robustesse
|
||
- La gestion des erreurs est améliorée avec des logs détaillés
|
||
- Le flux est maintenant plus prévisible et fiable
|
||
- La synchronisation du device est automatique et robuste
|
||
|
||
## Recommandations
|
||
|
||
### Corrections Prioritaires
|
||
1. **Corriger le flux du joiner** : Implémenter le même flux de confirmation que le créateur
|
||
2. **Unifier les processus** : Le joiner devrait rejoindre un processus existant, pas en créer un nouveau
|
||
3. **Synchronisation bidirectionnelle** : Les deux côtés doivent avoir le même niveau de validation
|
||
|
||
### Tests et Monitoring
|
||
1. **Tests** : Tester le pairing entre différents hosts avec les deux flux
|
||
2. **Monitoring** : Surveiller les logs pour identifier les problèmes potentiels
|
||
3. **Performance** : Optimiser les délais de retry si nécessaire
|
||
4. **Documentation** : Maintenir cette documentation à jour avec les évolutions
|
||
|
||
### Actions Immédiates
|
||
1. **Analyser le flux du joiner** : Comprendre comment il devrait rejoindre un processus existant
|
||
2. **Implémenter la cohérence** : Appliquer le même flux de confirmation aux deux côtés
|
||
3. **Valider la synchronisation** : S'assurer que les deux côtés ont le même `pairing_process_commitment`
|
||
|
||
Cette analyse fournit une base solide pour comprendre et maintenir le système de pairing, mais révèle des incohérences importantes qui doivent être corrigées.
|