UNPKG

@speckle/objectloader2

Version:

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

120 lines (102 loc) 3.54 kB
import AsyncGeneratorQueue from '../helpers/asyncGeneratorQueue.js' import { Downloader, Database } from './interfaces.js' import { CustomLogger, Base, Item } from '../types/types.js' import { CacheOptions, ObjectLoader2Options } from './options.js' import { DefermentManager } from '../helpers/defermentManager.js' import { CacheReader } from '../helpers/cacheReader.js' import { CachePump } from '../helpers/cachePump.js' import AggregateQueue from '../helpers/aggregateQueue.js' import { ObjectLoader2Factory } from './objectLoader2Factory.js' export class ObjectLoader2 { #rootId: string #logger: CustomLogger #database: Database #downloader: Downloader #pump: CachePump #cache: CacheReader #deferments: DefermentManager #gathered: AsyncGeneratorQueue<Item> #root?: Item = undefined constructor(options: ObjectLoader2Options) { this.#rootId = options.rootId this.#logger = options.logger || console.log const cacheOptions: CacheOptions = { logger: this.#logger, maxCacheReadSize: 10_000, maxCacheWriteSize: 10_000, maxWriteQueueSize: 40_000, maxCacheBatchWriteWait: 3_000, maxCacheBatchReadWait: 3_000 } this.#gathered = new AsyncGeneratorQueue() this.#database = options.database this.#deferments = new DefermentManager({ maxSizeInMb: 2_000, // 2 GBs ttlms: 15_000, // 15 seconds logger: this.#logger }) this.#cache = new CacheReader(this.#database, this.#deferments, cacheOptions) this.#pump = new CachePump( this.#database, this.#gathered, this.#deferments, cacheOptions ) this.#downloader = options.downloader } async disposeAsync(): Promise<void> { await Promise.all([ this.#downloader.disposeAsync(), this.#cache.disposeAsync(), this.#pump.disposeAsync() ]) this.#deferments.dispose() } async getRootObject(): Promise<Item | undefined> { if (!this.#root) { this.#root = (await this.#database.getAll([this.#rootId]))[0] if (!this.#root) { this.#root = await this.#downloader.downloadSingle() } } return this.#root } async getObject(params: { id: string }): Promise<Base> { return await this.#cache.getObject({ id: params.id }) } async getTotalObjectCount(): Promise<number> { const rootObj = await this.getRootObject() const totalChildrenCount = Object.keys(rootObj?.base.__closure || {}).length return totalChildrenCount + 1 //count the root } async *getObjectIterator(): AsyncGenerator<Base> { const rootItem = await this.getRootObject() if (rootItem === undefined) { this.#logger('No root object found!') return } //only for root this.#pump.add(rootItem) yield rootItem.base if (!rootItem.base.__closure) return //sort the closures by their values descending const sortedClosures = Object.entries(rootItem.base.__closure).sort( (a, b) => b[1] - a[1] ) const children = sortedClosures.map((x) => x[0]) const total = children.length this.#downloader.initializePool({ results: new AggregateQueue(this.#gathered, this.#pump), total }) for await (const item of this.#pump.gather(children, this.#downloader)) { yield item.base } } static createFromObjects(objects: Base[]): ObjectLoader2 { return ObjectLoader2Factory.createFromObjects(objects) } static createFromJSON(json: string): ObjectLoader2 { return ObjectLoader2Factory.createFromJSON(json) } }