From c8644c88176f6fe7adb5369dcdcc69408a3ac86b Mon Sep 17 00:00:00 2001 From: Eric van der Vlist Date: Sat, 4 Mar 2023 16:07:22 +0100 Subject: [PATCH] Replacing URLs by user ids in origins --- src/db-admin/health-legacy.ts | 92 ++++++++++++++++++++--------------- src/db/gpx.ts | 7 +-- src/lib/user-id.ts | 36 ++++++++++++++ 3 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 src/lib/user-id.ts diff --git a/src/db-admin/health-legacy.ts b/src/db-admin/health-legacy.ts index 62ae5bb..710c84f 100644 --- a/src/db-admin/health-legacy.ts +++ b/src/db-admin/health-legacy.ts @@ -4,6 +4,7 @@ import indexeddb from 'pouchdb-adapter-indexeddb'; import { sleep, until } from '../lib/async-wait'; import { isEqual } from 'lodash'; +import { dbUrlToUserId } from '../lib/user-id'; PouchDB.plugin(indexeddb); @@ -109,53 +110,64 @@ export const watchDbLegacy = async () => { const findDocumentsWithoutOrigin = async () => { const allDocs = await db.allDocs({ include_docs: true }); return allDocs.rows - .filter((row: any) => !row.doc.origin) + .filter( + (row: any) => + !row.doc.origin || !row.doc.origin.match(/^@([^>]+)>(.+)$/) + ) .map((row: any) => row.doc._id); }; + const updateDocumentsWithoutOrigin = async () => { + const documentsWithoutOrigin = await findDocumentsWithoutOrigin(); + console.log({ + caller: 'watchDbLegacy / addOrigin', + remoteUrl: state().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: state().remoteUrl, + docId, + doc, + }); + try { + db.put({ ...doc, origin: dbUrlToUserId(state().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; + } + } + } + } + }; + + if (!!state().remoteUrl) { + await updateDocumentsWithoutOrigin(); + } + 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; - } - } - } - } + await updateDocumentsWithoutOrigin(); } }); diff --git a/src/db/gpx.ts b/src/db/gpx.ts index a392a1b..c5276f6 100644 --- a/src/db/gpx.ts +++ b/src/db/gpx.ts @@ -7,6 +7,7 @@ import { state } from '../db-admin/health-legacy'; import { lat2tile, lon2tile, rectanglesIntersect } from '../lib/geo'; import { findStartTime } from '../lib/gpx'; import getUri, { intToGpxId, intToTrkptId } from '../lib/ids'; +import { dbUrlToUserId } from '../lib/user-id'; import { get, getDocsByType, getFamily, put, putAll } from './lib'; export const emptyGpx: Gpx = { @@ -127,7 +128,7 @@ const prune = ( _id: getUri(key, subId), type: key, to, - origin: state().remoteUrl, + origin: dbUrlToUserId(state().remoteUrl), doc: subObjects[index], }); prune(subId, subObjects[index], previousIds, {}, docs, to); @@ -202,14 +203,14 @@ export const pruneAndSaveImportedGpx = async (params: any) => { { _id: getUri('gpx', gpxId), type: 'gpx', - origin: state().remoteUrl, + origin: dbUrlToUserId(state().remoteUrl), doc: gpx, // a new GPX isn't to... }, { _id: getUri('extensions', gpxId), type: 'extensions', - origin: state().remoteUrl, + origin: dbUrlToUserId(state().remoteUrl), doc: {}, }, ]; diff --git a/src/lib/user-id.ts b/src/lib/user-id.ts new file mode 100644 index 0000000..826ef10 --- /dev/null +++ b/src/lib/user-id.ts @@ -0,0 +1,36 @@ +export const userId = (params: { username: string; database: string }) => { + const { username, database } = params; + const dbUrl = new URL(database); + return `@${username}>${dbUrl.hostname}`; +}; + +export const parseUserId = (id: string) => { + const matches = id.match(/^@([^>]+)>(.+)$/); + if (!matches) { + return null; + } + return { username: matches[1], database: matches[2] }; +}; + +function hex2a(hex: string) { + var str = ''; + for (var i = 0; i < hex.length; i += 2) { + var v = parseInt(hex.substr(i, 2), 16); + if (v) str += String.fromCharCode(v); + } + return str; +} + +export const parseDbUrl = (urlString: string) => { + origin; + const url = new URL(urlString); + const match = url.pathname.match(/\/userdb-(.*)\//); + if (!match || match.length < 2) { + return { username: '', database: url.hostname }; + } + const [_, encodedUser] = match; + return { username: hex2a(encodedUser), database: urlString }; +}; + +export const dbUrlToUserId = (urlString: string) => + userId(parseDbUrl(urlString));