« get me outta code hell

client: stub search index download progress - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2024-05-15 21:32:50 -0300
committer(quasar) nebula <qznebula@protonmail.com>2024-05-31 12:11:54 -0300
commitfec9c6556e181fc68068eae3db9e8ec81208221d (patch)
treea0c9f26b6bd89a1841839382b6f35cd60eb9a7d9
parent5d1151d352a092bd27c982ffde3ce2dfd093ddbb (diff)
client: stub search index download progress
-rw-r--r--src/static/js/client.js108
-rw-r--r--src/static/js/search-worker.js39
2 files changed, 141 insertions, 6 deletions
diff --git a/src/static/js/client.js b/src/static/js/client.js
index dab1ea37..769a4212 100644
--- a/src/static/js/client.js
+++ b/src/static/js/client.js
@@ -3447,6 +3447,17 @@ const wikiSearchInfo = initInfo('wikiSearchInfo', {
 
     workerActionCounter: 0,
     workerActionPromiseResolverMap: new Map(),
+
+    downloads: Object.create(null),
+  },
+
+  event: {
+    whenDownloadBegins: [],
+    whenDownloadsBegin: [],
+
+    whenDownloadProgresses: [],
+
+    whenDownloadEnds: [],
   },
 });
 
@@ -3481,6 +3492,18 @@ function handleSearchWorkerMessage(message) {
       handleSearchWorkerResultMessage(message);
       break;
 
+    case 'download-begun':
+      handleSearchWorkerDownloadBegunMessage(message);
+      break;
+
+    case 'download-progress':
+      handleSearchWorkerDownloadProgressMessage(message);
+      break;
+
+    case 'download-complete':
+      handleSearchWorkerDownloadCompleteMessage(message);
+      break;
+
     default:
       console.warn(`Unknown message kind "${message.data.kind}" <- from search worker`);
       break;
@@ -3545,6 +3568,70 @@ function handleSearchWorkerResultMessage(message) {
   state.workerActionPromiseResolverMap.delete(id);
 }
 
+function handleSearchWorkerDownloadBegunMessage(message) {
+  const {event} = wikiSearchInfo;
+  const {context: contextKey, keys} = message.data;
+
+  const context = getSearchWorkerDownloadContext(contextKey, true);
+
+  for (const key of keys) {
+    context[key] = 0.00;
+
+    dispatchInternalEvent(event, 'whenDownloadBegins', {
+      context: contextKey,
+      key,
+    });
+  }
+
+  dispatchInternalEvent(event, 'whenDownloadsBegin', {
+    context: contextKey,
+    keys,
+  });
+}
+
+function handleSearchWorkerDownloadProgressMessage(message) {
+  const {event} = wikiSearchInfo;
+  const {context: contextKey, key, progress} = message.data;
+
+  const context = getSearchWorkerDownloadContext(contextKey);
+
+  context[key] = progress;
+
+  dispatchInternalEvent(event, 'whenDownloadProgresses', {
+    context: contextKey,
+    key,
+    progress,
+  });
+}
+
+function handleSearchWorkerDownloadCompleteMessage(message) {
+  const {event} = wikiSearchInfo;
+  const {context: contextKey, key} = message.data;
+
+  const context = getSearchWorkerDownloadContext(contextKey);
+
+  context[key] = 1.00;
+
+  dispatchInternalEvent(event, 'whenDownloadEnds', {
+    context: contextKey,
+    key,
+  });
+}
+
+function getSearchWorkerDownloadContext(context, initialize = false) {
+  const {state} = wikiSearchInfo;
+
+  if (context in state.downloads) {
+    return state.downloads[context];
+  }
+
+  if (!initialize) {
+    return null;
+  }
+
+  return state.downloads[context] = Object.create(null);
+}
+
 async function postSearchWorkerAction(action, options) {
   const {state} = wikiSearchInfo;
 
@@ -3643,6 +3730,16 @@ function getSidebarSearchReferences() {
     findString('group-result-kind');
 }
 
+function addSidebarSearchInternalListeners() {
+  const info = sidebarSearchInfo;
+
+  if (!info.searchBox) return;
+
+  wikiSearchInfo.event.whenDownloadsBegin.push(updateSidebarSearchStatus);
+  wikiSearchInfo.event.whenDownloadProgresses.push(updateSidebarSearchStatus);
+  wikiSearchInfo.event.whenDownloadEnds.push(updateSidebarSearchStatus);
+}
+
 function mutateSidebarSearchContent() {
   const info = sidebarSearchInfo;
 
@@ -3787,6 +3884,16 @@ function clearSidebarSearch() {
   hideSidebarSearchResults();
 }
 
+function updateSidebarSearchStatus() {
+  const info = sidebarSearchInfo;
+  const {state} = info;
+
+  const searchIndexDownloads =
+    getSearchWorkerDownloadContext('search-indexes');
+
+  console.log('Display:', searchIndexDownloads);
+}
+
 function showSidebarSearchResults(results) {
   const info = sidebarSearchInfo;
 
@@ -4002,6 +4109,7 @@ function hideSidebarSearchResults() {
 }
 
 clientSteps.getPageReferences.push(getSidebarSearchReferences);
+clientSteps.addInternalListeners.push(addSidebarSearchInternalListeners);
 clientSteps.mutatePageContent.push(mutateSidebarSearchContent);
 clientSteps.addPageListeners.push(addSidebarSearchListeners);
 clientSteps.initializeState.push(initializeSidebarSearchState);
diff --git a/src/static/js/search-worker.js b/src/static/js/search-worker.js
index c2bdcaee..9a7827da 100644
--- a/src/static/js/search-worker.js
+++ b/src/static/js/search-worker.js
@@ -14,6 +14,7 @@ import {
 } from '../shared-util/sugar.js';
 
 import {loadDependency} from './module-import-shims.js';
+import {fetchWithProgress} from './xhr-util.js';
 
 // Will be loaded from dependencies.
 let decompress;
@@ -24,7 +25,7 @@ let idb;
 let status = null;
 let indexes = null;
 
-globalThis.onmessage = handleWindowMessage;
+onmessage = handleWindowMessage;
 postStatus('alive');
 
 Promise.all([
@@ -158,6 +159,8 @@ async function main() {
 
   const [indexData, idbIndexData] = await background;
 
+  delete idbIndexData.generic;
+
   const keysNeedingFetch =
     (idbIndexData
       ? Object.keys(indexData)
@@ -170,10 +173,34 @@ async function main() {
     Object.keys(indexData)
       .filter(key => !keysNeedingFetch.includes(key))
 
+  if (!empty(keysNeedingFetch)) {
+    postMessage({
+      kind: 'download-begun',
+      context: 'search-indexes',
+      keys: keysNeedingFetch,
+    });
+  }
+
   const fetchPromises =
-    keysNeedingFetch
-      .map(key => rebase(key + '.json.msgpack'))
-      .map(url => fetch(url));
+    keysNeedingFetch.map(key =>
+      fetchWithProgress(
+        rebase(key + '.json.msgpack'),
+        progress => {
+          postMessage({
+            kind: 'download-progress',
+            context: 'search-indexes',
+            progress: progress / 1.00,
+            key,
+          });
+        }).then(response => {
+            postMessage({
+              kind: 'download-complete',
+              context: 'search-indexes',
+              key,
+            });
+
+            return response;
+          }));
 
   const fetchBlobPromises =
     fetchPromises
@@ -316,14 +343,14 @@ async function handleWindowActionMessage(message) {
 
 function postStatus(newStatus) {
   status = newStatus;
-  globalThis.postMessage({
+  postMessage({
     kind: 'status',
     status: newStatus,
   });
 }
 
 function postActionResult(id, status, value) {
-  globalThis.postMessage({
+  postMessage({
     kind: 'result',
     id,
     status,