Initial commit SteelBase - Oficiais e Funcionando
This commit is contained in:
209
js/core/cache-manager.js
Normal file
209
js/core/cache-manager.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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');
|
||||
Reference in New Issue
Block a user