Compare commits
3 Commits
8e61990f79
...
fe60812c53
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fe60812c53 | ||
![]() |
26f985195d | ||
![]() |
34a65ec079 |
@ -9,8 +9,12 @@ Toutes les modifications notables de ce projet seront documentées ici.
|
|||||||
- Surveillance périodique des `pcd_commitment` (toutes les 30 secondes)
|
- Surveillance périodique des `pcd_commitment` (toutes les 30 secondes)
|
||||||
- API WebSocket pour contrôler le background sync (`FORCE_DATA_SCAN`, `GET_BACKGROUND_SYNC_STATUS`)
|
- API WebSocket pour contrôler le background sync (`FORCE_DATA_SCAN`, `GET_BACKGROUND_SYNC_STATUS`)
|
||||||
- Gestion automatique des entrées `diff` pour le tracking des données manquantes
|
- Gestion automatique des entrées `diff` pour le tracking des données manquantes
|
||||||
- Récupération automatique des données manquantes auprès des pairs
|
- Récupération en deux étapes des données manquantes :
|
||||||
|
- Essai depuis les serveurs de stockage (retrieveData) en priorité
|
||||||
|
- Fallback vers les pairs (requestDataFromPeers) si non trouvé
|
||||||
|
- Extraction automatique des URLs de stockage depuis les rôles
|
||||||
- Scripts de test et validation du service de background sync
|
- Scripts de test et validation du service de background sync
|
||||||
|
- Test spécifique pour la récupération depuis le storage
|
||||||
- Documentation complète dans `docs/BACKGROUND_SYNC.md`
|
- Documentation complète dans `docs/BACKGROUND_SYNC.md`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import { Service } from './service';
|
import { Service } from './service';
|
||||||
import Database from './database.service';
|
import Database from './database.service';
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
|
import { retrieveData } from './storage.service';
|
||||||
|
|
||||||
export class BackgroundSyncService {
|
export class BackgroundSyncService {
|
||||||
private static instance: BackgroundSyncService;
|
private static instance: BackgroundSyncService;
|
||||||
@ -234,6 +235,17 @@ export class BackgroundSyncService {
|
|||||||
const roles = diff.roles;
|
const roles = diff.roles;
|
||||||
|
|
||||||
if (processesToRequest[processId]) {
|
if (processesToRequest[processId]) {
|
||||||
|
// D'abord essayer de récupérer depuis les serveurs de stockage
|
||||||
|
const retrievedFromStorage = await this.tryRetrieveFromStorage(hash, roles);
|
||||||
|
|
||||||
|
if (retrievedFromStorage) {
|
||||||
|
console.log(`✅ Data retrieved from storage for hash ${hash}`);
|
||||||
|
// Sauvegarder les données récupérées en base
|
||||||
|
await this.service.saveBufferToDb(hash, Buffer.from(retrievedFromStorage));
|
||||||
|
continue; // Passer au hash suivant
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas trouvé en storage, demander aux pairs
|
||||||
console.log(`🔄 Requesting data for hash ${hash} from process ${processId}`);
|
console.log(`🔄 Requesting data for hash ${hash} from process ${processId}`);
|
||||||
await this.service.requestDataFromPeers(processId, [stateId], [roles]);
|
await this.service.requestDataFromPeers(processId, [stateId], [roles]);
|
||||||
}
|
}
|
||||||
@ -248,6 +260,62 @@ export class BackgroundSyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Essaie de récupérer les données depuis les serveurs de stockage
|
||||||
|
*/
|
||||||
|
private async tryRetrieveFromStorage(hash: string, roles: any): Promise<ArrayBuffer | null> {
|
||||||
|
try {
|
||||||
|
// Extraire les URLs de stockage depuis les rôles
|
||||||
|
const storageUrls = this.extractStorageUrls(roles);
|
||||||
|
|
||||||
|
if (storageUrls.length === 0) {
|
||||||
|
console.log(`No storage URLs found for hash ${hash}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🔍 Trying to retrieve hash ${hash} from storage servers:`, storageUrls);
|
||||||
|
|
||||||
|
// Essayer de récupérer depuis les serveurs de stockage
|
||||||
|
const data = await retrieveData(storageUrls, hash);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
console.log(`✅ Successfully retrieved data for hash ${hash} from storage`);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
console.log(`❌ Data not found in storage for hash ${hash}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error retrieving data from storage for hash ${hash}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrait les URLs de stockage depuis les rôles
|
||||||
|
*/
|
||||||
|
private extractStorageUrls(roles: any): string[] {
|
||||||
|
const storageUrls = new Set<string>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (roles && typeof roles === 'object') {
|
||||||
|
for (const role of Object.values(roles)) {
|
||||||
|
if (role && typeof role === 'object' && 'storages' in role && Array.isArray((role as any).storages)) {
|
||||||
|
for (const storageUrl of (role as any).storages) {
|
||||||
|
if (typeof storageUrl === 'string' && storageUrl.trim()) {
|
||||||
|
storageUrls.add(storageUrl.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting storage URLs from roles:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(storageUrls);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force un scan immédiat (pour tests ou usage manuel)
|
* Force un scan immédiat (pour tests ou usage manuel)
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@ export class Service {
|
|||||||
private membersList: any = {};
|
private membersList: any = {};
|
||||||
private relayManager: RelayManager;
|
private relayManager: RelayManager;
|
||||||
private storages: string[] = []; // storage urls
|
private storages: string[] = []; // storage urls
|
||||||
|
private backgroundSync: any = null; // BackgroundSyncService
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
console.log('🔧 Service initialized');
|
console.log('🔧 Service initialized');
|
||||||
@ -1448,4 +1449,54 @@ export class Service {
|
|||||||
throw new Error(`Failed to dump device: ${e}`);
|
throw new Error(`Failed to dump device: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Démarre le service de surveillance en arrière-plan
|
||||||
|
*/
|
||||||
|
public async startBackgroundSync(): Promise<void> {
|
||||||
|
if (!this.backgroundSync) {
|
||||||
|
const { BackgroundSyncService } = await import('./background-sync.service');
|
||||||
|
this.backgroundSync = await BackgroundSyncService.getInstance();
|
||||||
|
}
|
||||||
|
await this.backgroundSync.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arrête le service de surveillance
|
||||||
|
*/
|
||||||
|
public stopBackgroundSync(): void {
|
||||||
|
if (this.backgroundSync) {
|
||||||
|
this.backgroundSync.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force un scan manuel des données manquantes
|
||||||
|
*/
|
||||||
|
public async forceDataScan(): Promise<string[]> {
|
||||||
|
if (!this.backgroundSync) {
|
||||||
|
const { BackgroundSyncService } = await import('./background-sync.service');
|
||||||
|
this.backgroundSync = await BackgroundSyncService.getInstance();
|
||||||
|
}
|
||||||
|
return await this.backgroundSync.forceScan();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient le statut du service de background sync
|
||||||
|
*/
|
||||||
|
public getBackgroundSyncStatus(): { isRunning: boolean; scanInterval: number } | null {
|
||||||
|
if (!this.backgroundSync) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.backgroundSync.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure l'intervalle de scan du background sync
|
||||||
|
*/
|
||||||
|
public setBackgroundSyncInterval(intervalMs: number): void {
|
||||||
|
if (this.backgroundSync) {
|
||||||
|
this.backgroundSync.setScanInterval(intervalMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,24 @@ export async function retrieveData(servers: string[], key: string): Promise<Arra
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
// Validate that we received an ArrayBuffer
|
// Handle both ArrayBuffer and Buffer (Node.js)
|
||||||
if (response.data instanceof ArrayBuffer) {
|
if (response.data instanceof ArrayBuffer) {
|
||||||
return response.data;
|
return response.data;
|
||||||
|
} else if (Buffer.isBuffer(response.data)) {
|
||||||
|
// Convert Buffer to ArrayBuffer
|
||||||
|
return response.data.buffer.slice(
|
||||||
|
response.data.byteOffset,
|
||||||
|
response.data.byteOffset + response.data.byteLength
|
||||||
|
);
|
||||||
|
} else if (response.data && typeof response.data === 'object' && 'buffer' in response.data) {
|
||||||
|
// Handle Uint8Array or similar typed arrays
|
||||||
|
const buffer = response.data.buffer;
|
||||||
|
return buffer.slice(
|
||||||
|
response.data.byteOffset,
|
||||||
|
response.data.byteOffset + response.data.byteLength
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.error('Server returned non-ArrayBuffer data:', typeof response.data);
|
console.error('Server returned unsupported data type:', typeof response.data, response.data?.constructor?.name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user