@speckle/objectloader2
Version:
This is an updated objectloader for the Speckle viewer written in typescript
113 lines • 4.35 kB
JavaScript
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