dyomedea/src/db-admin/health-legacy.ts

283 lines
8.0 KiB
TypeScript
Raw Normal View History

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<any>({});
export { state };
export const watchDbLegacy = async () => {
createRoot(async (dispose) => {
2023-02-12 13:41:19 +00:00
console.log({ caller: 'watchDbLegacy / start' });
2023-02-12 13:47:03 +00:00
const { db, localDb, remoteDb, sync, currentAccount } = globalThis;
const [status, setStatus] = createSignal<any>({});
const [syncState, setSyncState] = createSignal<any>({});
2023-02-12 20:23:30 +00:00
const [remoteUrl, setRemoteUrl] = createSignal<string>();
const updateStatus = async () => {
const dbInfo = await db.info();
const localDbInfo = await localDb.info();
2023-02-12 20:23:30 +00:00
const remoteDbInfo = 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();
2023-02-12 13:47:03 +00:00
if (sync) {
sync
.on('change', function (info) {
// handle change
2023-02-12 13:10:56 +00:00
// 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 });
2023-02-12 13:10:56 +00:00
// console.log({ caller: 'Sync / paused', err });
})
.on('active', function () {
// replicate resumed (e.g. new changes replicating, user went back online)
setSyncState({ ...syncState(), paused: false });
2023-02-12 13:10:56 +00:00
// 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);
2023-02-12 20:23:30 +00:00
const findDocumentsWithoutOrigin = async () => {
const allDocs = await db.allDocs({ include_docs: true });
return allDocs.rows
.filter((row: any) => !row.doc.origin)
.map((row: any) => row.doc._id);
};
createEffect(async () => {
if (!!state().remoteUrl && remoteUrl() !== state().remoteUrl) {
setRemoteUrl(state().remoteUrl);
// Check documents and update without origin
const documentsWithoutOrigin = await findDocumentsWithoutOrigin();
console.log({
caller: 'watchDbLegacy / addOrigin',
remoteUrl: remoteUrl(),
nbDocumentsWithoutOrigin: documentsWithoutOrigin.length,
});
for (const docId of documentsWithoutOrigin) {
while (true) {
await sleep(100);
const doc = await db.get(docId);
console.log({
caller: 'watchDbLegacy / addOrigin',
remoteUrl: remoteUrl(),
docId,
doc,
});
try {
db.put({ ...doc, origin: remoteUrl() });
break;
} catch (error) {
if (error.name === 'conflict') {
console.log({
caller: 'watchDbLegacy / addOrigin',
docId,
doc,
error,
});
} else {
console.error({
caller: 'watchDbLegacy / addOrigin',
docId,
doc,
error,
});
break;
}
}
}
}
}
});
// 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 ' });
2023-02-13 08:59:41 +00:00
try {
const localPurges = await db.get('_local/purges');
localPurges._deleted = true;
await db.put(localPurges);
} catch (error) {
console.warn({ caller: 'watchDbLegacy / _local/purges', error });
}
const deletedDocs = await getDeletedDocs();
2023-02-13 09:11:46 +00:00
let i = 0;
if (deletedDocs.length > 0) {
console.log({
caller: 'watchDbLegacy / purge',
// bySequence,
// store,
// allDocs,
deletedDocs,
state: state(),
});
2023-02-12 13:41:19 +00:00
for (const doc of deletedDocs) {
2023-02-12 14:20:41 +00:00
await sleep(10);
try {
await db.purge(doc.id, doc.rev);
} catch (err) {
console.log({
caller: 'watchDbLegacy / purge',
doc,
err,
});
}
2023-02-12 13:41:19 +00:00
i = i + 1;
if (i % 10 === 0) {
console.log({
caller: 'watchDbLegacy / purge',
nbDeletedDocs: i,
nbDocsToDelete: deletedDocs.length,
doc,
});
}
2023-02-13 09:14:34 +00:00
if (i === 1000) {
break;
}
2023-02-12 13:41:19 +00:00
}
}
2023-02-13 09:11:46 +00:00
if (i !== deletedDocs.length) {
await sleep(60000);
}
}
});
};