Files
SteelBase/public/js/core/cache-manager.js

210 lines
6.5 KiB
JavaScript

/**
* CacheManager - Gerenciador central do sistema de cache
* Coordena IndexedDB, sincronização e acesso aos dados
*/
class CacheManager {
constructor(config = {}) {
this.dbName = config.dbName || 'AcoCalcProDB';
this.version = config.version || 1;
this.db = null;
this.config = {
debug: config.debug || false,
autoSync: config.autoSync || false,
cacheExpiry: config.cacheExpiry || (7 * 24 * 60 * 60 * 1000), // 7 dias
...config
};
this.stores = [
'cantoneiras',
'barras',
'barras_chatas',
'barras_roscadas',
'tubos_circulares',
'tubos_rhs',
'chapas',
'perfis_i',
'perfis_w',
'perfis_hp',
'_metadata',
'_config'
];
}
/**
* Inicializa o IndexedDB
*/
async init() {
return new Promise((resolve, reject) => {
if (!window.indexedDB) {
console.warn('⚠️ IndexedDB não disponível - usando fallback para CSV');
resolve(false);
return;
}
const request = indexedDB.open(this.dbName, this.version);
request.onerror = () => {
console.error('❌ Erro ao abrir IndexedDB:', request.error);
reject(request.error);
};
request.onsuccess = () => {
this.db = request.result;
if (this.config.debug) {
console.log('✅ IndexedDB inicializado:', this.dbName);
}
resolve(true);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Criar stores para cada tipo de perfil
this.stores.forEach(storeName => {
if (!db.objectStoreNames.contains(storeName)) {
const store = db.createObjectStore(storeName, { keyPath: 'id' });
// Criar índices para busca rápida
if (storeName !== '_metadata' && storeName !== '_config') {
store.createIndex('nome', 'nome', { unique: false });
store.createIndex('tipo', 'tipo', { unique: false });
}
if (this.config.debug) {
console.log(`✅ Store criada: ${storeName}`);
}
}
});
};
});
}
/**
* Verifica saúde do cache
*/
async checkHealth() {
if (!this.db) {
return {
healthy: false,
error: 'Database not initialized'
};
}
try {
const stats = {};
for (const storeName of this.stores) {
if (storeName.startsWith('_')) continue;
const count = await this.count(storeName);
const metadata = await this.getMetadata(storeName);
stats[storeName] = {
count,
lastSync: metadata?.lastSync || null,
size: metadata?.size || 0
};
}
return {
healthy: true,
stats,
totalSize: Object.values(stats).reduce((sum, s) => sum + s.size, 0)
};
} catch (error) {
return {
healthy: false,
error: error.message
};
}
}
/**
* Limpa todo o cache
*/
async clearAll() {
if (!this.db) {
throw new Error('Database not initialized');
}
const promises = this.stores
.filter(s => !s.startsWith('_'))
.map(storeName => this.clear(storeName));
await Promise.all(promises);
if (this.config.debug) {
console.log('✅ Todo o cache foi limpo');
}
}
/**
* Conta registros em uma store
*/
async count(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.count();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
/**
* Limpa uma store específica
*/
async clear(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.clear();
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
/**
* Busca metadados de um tipo
*/
async getMetadata(tipo) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['_metadata'], 'readonly');
const store = transaction.objectStore('_metadata');
const request = store.get(tipo);
request.onsuccess = () => resolve(request.result || null);
request.onerror = () => reject(request.error);
});
}
/**
* Salva metadados de um tipo
*/
async setMetadata(tipo, metadata) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['_metadata'], 'readwrite');
const store = transaction.objectStore('_metadata');
const request = store.put({ tipo, ...metadata });
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
/**
* Retorna estatísticas de uso
*/
getStats() {
return this.checkHealth();
}
}
// Exportar para uso global
window.CacheManager = CacheManager;
console.log('✅ CacheManager carregado');