UNPKG

@speckle/objectloader2

Version:

This is an updated objectloader for the Speckle viewer written in typescript

113 lines 4.35 kB
import AggregateQueue from '../queues/aggregateQueue.js'; import AsyncGeneratorQueue from '../queues/asyncGeneratorQueue.js'; import { take } from '../types/functions.js'; import { ObjectLoader2Factory } from './objectLoader2Factory.js'; import { CacheReader } from './stages/cacheReader.js'; import { CacheWriter } from './stages/cacheWriter.js'; const MAX_CLOSURES_TO_TAKE = 100; const EXPECTED_CLOSURE_VALUE = 100; export class ObjectLoader2 { #rootId; #logger; #database; #downloader; #cacheReader; #cacheWriter; #deferments; #gathered; #root = undefined; #isRootStored = false; constructor(options) { this.#rootId = options.rootId; this.#logger = options.logger || (() => { }); this.#logger('ObjectLoader2 initialized with rootId:', this.#rootId); const cacheOptions = { logger: this.#logger, maxCacheReadSize: 10_000, maxCacheWriteSize: 10_000, maxWriteQueueSize: 40_000, maxCacheBatchWriteWait: 100, //100 ms, next to nothing! maxCacheBatchReadWait: 100 //100 ms, next to nothing! }; this.#gathered = new AsyncGeneratorQueue(); this.#database = options.database; this.#deferments = options.deferments; this.#downloader = options.downloader; this.#cacheReader = new CacheReader(this.#database, this.#deferments, this.#logger, cacheOptions); this.#cacheReader.initializeQueue(this.#gathered, this.#downloader); this.#cacheWriter = new CacheWriter(this.#database, this.#logger, this.#deferments, cacheOptions, (id) => { this.#cacheReader.requestItem(id); }); } async disposeAsync() { await Promise.all([ this.#gathered.disposeAsync(), this.#downloader.disposeAsync(), this.#cacheWriter.disposeAsync(), this.#cacheReader.disposeAsync() ]); this.#deferments.dispose(); } async getRootObject() { if (!this.#root) { this.#root = (await this.#database.getAll([this.#rootId]))[0]; if (!this.#root) { this.#root = await this.#downloader.downloadSingle(); } else { this.#isRootStored = true; } } return this.#root; } async getObject(params) { return await this.#cacheReader.getObject({ id: params.id }); } async getTotalObjectCount() { const rootObj = await this.getRootObject(); const totalChildrenCount = Object.keys(rootObj?.base?.__closure || {}).length; return totalChildrenCount + 1; //count the root } async *getObjectIterator() { const rootItem = await this.getRootObject(); if (rootItem?.base === undefined) { this.#logger('No root object found!'); return; } if (!rootItem.base.__closure) { yield rootItem.base; return; } //sort the closures by their values descending const sortedClosures = Object.entries(rootItem.base.__closure ?? []).sort((a, b) => b[1] - a[1]); this.#logger('calculated closures: ', !take(sortedClosures.values(), MAX_CLOSURES_TO_TAKE).every((x) => x[1] === EXPECTED_CLOSURE_VALUE)); const children = sortedClosures.map((x) => x[0]); const total = children.length + 1; // +1 for the root object this.#downloader.initialize({ results: new AggregateQueue(this.#gathered, this.#cacheWriter), total }); //only for root this.#gathered.add(rootItem); this.#cacheReader.requestAll(children); let count = 0; for await (const item of this.#gathered.consume()) { yield item.base; //always defined, as we add it to the queue count++; if (count >= total) { break; } } if (!this.#isRootStored) { await this.#database.putAll([rootItem]); this.#isRootStored = true; } } static createFromObjects(objects) { return ObjectLoader2Factory.createFromObjects(objects); } static createFromJSON(json) { return ObjectLoader2Factory.createFromJSON(json); } } //# sourceMappingURL=objectLoader2.js.map