| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- import { ProjectSnapshot } from '@/infrastructure/project-snapshot'
- import { generateSHA1Hash } from '@/shared/utils/sha1'
- import { AdvancedReferenceSearchResult, Changes } from './types'
- import { debugConsole } from '@/utils/debugging'
- import type { ReferenceWorkerResponse } from './references.worker'
- const ONE_MB = 1024 * 1024
- const MAX_BIB_DATA_SIZE = 6 * ONE_MB
- export class ReferenceIndexer {
- private fileIndexHash: Map<string, string> = new Map()
- private worker: Worker
- private updateResolve: ((result: Set<string>) => void) | null = null
- private searchResolve:
- | ((result: AdvancedReferenceSearchResult) => void)
- | null = null
- constructor() {
- this.worker = new Worker(
- /* webpackChunkName: "references-worker" */
- new URL('./references.worker.ts', import.meta.url),
- { type: 'module' }
- )
- this.worker.addEventListener('message', evt => this.handleMessage(evt))
- }
- private handleMessage(event: MessageEvent) {
- const data = event.data as ReferenceWorkerResponse
- if (data.type === 'searchResult' && this.searchResolve) {
- this.searchResolve(data.result)
- this.searchResolve = null
- } else if (data.type === 'updateKeys' && this.updateResolve) {
- this.updateResolve(data.keys)
- this.updateResolve = null
- } else {
- debugConsole.warn('Received unknown message from worker:', data.type)
- }
- }
- async updateFromSnapshot(
- snapshot: Pick<
- ProjectSnapshot,
- | 'getDocPaths'
- | 'getDocContents'
- | 'getBinaryFilePathsWithHash'
- | 'getBinaryFileContents'
- >,
- {
- dataLimit = MAX_BIB_DATA_SIZE,
- signal,
- }: { dataLimit?: number; signal: AbortSignal }
- ): Promise<Set<string>> {
- const nextFileHashIndex = new Map(this.fileIndexHash)
- const previousPaths = new Set(this.fileIndexHash.keys())
- let dataBudget = dataLimit
- const docs = snapshot
- .getDocPaths()
- .filter(path => path.toLowerCase().endsWith('.bib'))
- const changes: Changes = { updates: [], deletes: [] }
- for (const path of docs) {
- previousPaths.delete(path)
- if (dataBudget <= 0) {
- continue
- }
- const content = snapshot.getDocContents(path)?.slice(0, dataBudget)
- if (content == null) {
- continue
- }
- dataBudget -= content.length
- const hash = generateSHA1Hash(content)
- const possibleMatch = nextFileHashIndex.get(path)
- if (possibleMatch === undefined || possibleMatch !== hash) {
- // New or changed file
- nextFileHashIndex.set(path, hash)
- changes.updates.push({ path, content })
- }
- }
- const files = snapshot
- .getBinaryFilePathsWithHash()
- .filter(({ path }) => path.toLowerCase().endsWith('.bib'))
- .sort((a, b) => a.size - b.size)
- for (const { path, hash, size } of files) {
- if (signal.aborted) {
- debugConsole.warn('Aborted indexing references due to signal')
- return new Set()
- }
- previousPaths.delete(path)
- if (nextFileHashIndex.get(path) === hash) {
- dataBudget -= size
- // Already indexed
- continue
- }
- if (dataBudget <= 0) {
- continue
- }
- const content = await snapshot.getBinaryFileContents(path, {
- maxSize: dataBudget,
- })
- dataBudget -= content.length
- nextFileHashIndex.set(path, hash)
- changes.updates.push({ path, content })
- }
- previousPaths.forEach(path => {
- // Deleted file
- changes.deletes.push(path)
- nextFileHashIndex.delete(path)
- })
- if (dataBudget <= 0) {
- debugConsole.warn('Data budget exceeded while updating references index')
- }
- this.fileIndexHash = nextFileHashIndex
- this.worker.postMessage({
- type: 'update',
- changes,
- })
- return new Promise(resolve => {
- this.updateResolve = resolve
- })
- }
- async search(query: string): Promise<AdvancedReferenceSearchResult> {
- this.worker.postMessage({ type: 'search', query })
- const { promise, resolve } =
- Promise.withResolvers<AdvancedReferenceSearchResult>()
- this.searchResolve = resolve
- return promise
- }
- }
|