import { createEffect, createRoot, createSignal } from 'solid-js'; import PouchDB from 'pouchdb'; import indexeddb from 'pouchdb-adapter-indexeddb'; import { sleep, until } from '../lib/async-wait'; import { isEqual } from 'lodash'; PouchDB.plugin(indexeddb); declare global { var localDb: any; var db: any; var remoteDb: any; var currentAccount: any; var sync: any; } const [state, setState] = createSignal({}); export { state }; export const watchDbLegacy = async () => { createRoot(async (dispose) => { console.log({ caller: 'watchDbLegacy' }); db = globalThis.db; localDb = globalThis.localDb; const [status, setStatus] = createSignal({}); const [syncState, setSyncState] = createSignal({}); const updateStatus = async () => { const dbInfo = await db.info(); const localDbInfo = await localDb.info(); const remoteDbInfo = globalThis.remoteDb ? await remoteDb.info() : undefined; const tasks = PouchDB.activeTasks.list(); const newStatus = { ...status(), tasks, dbInfo, localDbInfo, remoteDbInfo, // date: new Date(), }; if (!isEqual(status(), newStatus)) { setStatus(newStatus); } }; createEffect(() => { console.log({ caller: 'watchDbLegacy', state: state(), status: status(), syncState: syncState(), sync, }); }); createEffect(() => { const newState = { ...state(), dbName: status()?.dbInfo?.db_name, localUpdateSeq: status()?.dbInfo?.update_seq, remoteUrl: status()?.remoteDbInfo?.host, sync: syncState(), }; if (!isEqual(newState, state())) { setState(newState); } }); updateStatus(); if (globalThis.sync) { globalThis.sync .on('change', function (info) { // handle change console.log({ caller: 'Sync / change', info }); if (info.direction === 'push') { setSyncState({ ...syncState(), lastSeq: info.change.last_seq }); } }) .on('paused', function (err) { // replication paused (e.g. replication up to date, user went offline) setSyncState({ ...syncState(), paused: true }); console.log({ caller: 'Sync / paused', err }); }) .on('active', function () { // replicate resumed (e.g. new changes replicating, user went back online) setSyncState({ ...syncState(), paused: false }); console.log({ caller: 'Sync / active' }); }) .on('denied', function (err) { // a document failed to replicate (e.g. due to permissions) console.error({ caller: 'Sync / denied', err }); }) .on('complete', function (info) { // handle complete console.log({ caller: 'Sync / complete', info }); }) .on('error', function (err) { // handle error console.error({ caller: 'Sync / error', err }); }); } const timerId = setInterval(updateStatus, 15000); // db.compact(); const openIDb = (name: string) => new Promise((resolve, reject) => { const iDb = indexedDB.open(name); iDb.onerror = (event: any) => { console.error({ caller: 'watchDbLegacy', message: 'open db error', target: event.target, }); reject(event.target.errorCode); }; iDb.onsuccess = (event: any) => { resolve(event.target.result); }; }); const getAll = (store: any) => new Promise((resolve, reject) => { const request = store.getAll(); request.onerror = (event: any) => { console.error({ caller: 'watchDbLegacy', message: 'getAll error', target: event.target, }); reject(event.target.errorCode); }; request.onsuccess = (event: any) => { resolve(event.target.result as any[]); }; }); const getDeletedDocs = async () => { const iDb = (await openIDb(`_pouch_${state().dbName}`)) as IDBDatabase; const bySequence = iDb.transaction('docs', 'readonly'); const store = bySequence.objectStore('docs'); const allDocs = (await getAll(store)) as any[]; iDb.close(); const docs = allDocs .filter( (doc) => !doc.id.startsWith('_local') && doc.deleted === 1 && doc.seq <= state()?.sync?.lastSeq ) .map((doc) => ({ id: doc.id, rev: doc.rev })); // console.log({ // caller: 'watchDbLegacy / getDeletedDocs', // // bySequence, // // store, // // allDocs, // docs, // state: state(), // }); return docs; }; while (true) { await until( () => state()?.sync?.paused && state()?.sync?.lastSeq >= state()?.localUpdateSeq, 1000 ); console.log({ caller: 'watchDbLegacy / ready to purge after sync ' }); const deletedDocs = await getDeletedDocs(); if (deletedDocs.length > 0) { console.log({ caller: 'watchDbLegacy / purge', // bySequence, // store, // allDocs, deletedDocs, state: state(), }); deletedDocs.forEach(async (doc) => { await sleep(500); try { await db.purge(doc.id, doc.rev); } catch (err) { console.log({ caller: 'watchDbLegacy / purge', doc, err, }); } }); } await sleep(60000); } }); };