Visitar URL original
feat(front): use file system api for tiles caching · ThatOpen/engine_components@07bdbd3 · GitHub
Skip to content

Commit 07bdbd3

Browse files
committed
feat(front): use file system api for tiles caching
1 parent cca21a6 commit 07bdbd3

7 files changed

Lines changed: 137 additions & 22 deletions

File tree

‎packages/front/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@thatopen/components-front",
33
"description": "Collection of frontend tools to author BIM apps.",
4-
"version": "2.3.0-alpha.1",
4+
"version": "2.3.0-alpha.2",
55
"author": "That Open Company",
66
"contributors": [
77
"Antonio Gonzalez Viegas (https://github.com/agviegas)",

‎packages/front/src/fragments/Highlighter/index.ts‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,7 @@ export interface HighlighterConfig {
4444
/**
4545
* This component allows highlighting and selecting fragments in a 3D scene. 📕 [Tutorial](https://docs.thatopen.com/Tutorials/Components/Front/Highlighter). 📘 [API](https://docs.thatopen.com/api/@thatopen/components-front/classes/Highlighter).
4646
*/
47-
export class Highlighter
48-
extends OBC.Component
49-
implements OBC.Disposable, OBC.Configurable<HighlighterConfig>
50-
{
47+
export class Highlighter extends OBC.Component implements OBC.Disposable {
5148
/**
5249
* A unique identifier for the component.
5350
* This UUID is used to register the component within the Components system.

‎packages/front/src/fragments/IfcStreamer/example.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ world.scene.three.background = null;
7171

7272
const loader = components.get(OBCF.IfcStreamer);
7373
loader.world = world;
74-
loader.dbCleaner.enabled = true;
7574

7675
/* MD
7776
Now, we need to set the base URL where the streamer needs to look for the tiles. In our case, we'll use the tiles we have prepared in our repository, but this should also work with your own backend.

‎packages/front/src/fragments/IfcStreamer/index.ts‎

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import * as FRAG from "@thatopen/fragments";
33
import * as OBC from "@thatopen/components";
44
import {
55
GeometryCullerRenderer,
6-
StreamFileDatabase,
6+
// StreamFileDatabase,
77
StreamPropertiesSettings,
88
StreamedInstances,
99
StreamedInstance,
1010
StreamLoaderSettings,
11-
StreamerDbCleaner,
11+
// StreamerDbCleaner,
12+
StreamerFileDb,
1213
} from "./src";
1314

1415
export * from "./src";
@@ -64,8 +65,6 @@ export class IfcStreamer extends OBC.Component implements OBC.Disposable {
6465
*/
6566
useCache = true;
6667

67-
dbCleaner: StreamerDbCleaner;
68-
6968
fetch = async (url: string) => {
7069
return fetch(url);
7170
};
@@ -79,7 +78,7 @@ export class IfcStreamer extends OBC.Component implements OBC.Disposable {
7978
{ data: FRAG.StreamedGeometries; time: number }
8079
>();
8180

82-
private _fileCache = new StreamFileDatabase();
81+
private _fileDB = new StreamerFileDb();
8382

8483
private _url: string | null = null;
8584

@@ -170,13 +169,9 @@ export class IfcStreamer extends OBC.Component implements OBC.Disposable {
170169
constructor(components: OBC.Components) {
171170
super(components);
172171
this.components.add(IfcStreamer.uuid, this);
173-
this.dbCleaner = new StreamerDbCleaner(this._fileCache);
174172

175173
const fragments = this.components.get(OBC.FragmentsManager);
176174
fragments.onFragmentsDisposed.add(this.disposeStreamedGroup);
177-
178-
// const hardlyGeometry = new THREE.BoxGeometry();
179-
// this._hardlySeenGeometries = new THREE.InstancedMesh();
180175
}
181176

182177
/** {@link OBC.Disposable.dispose} */
@@ -393,7 +388,7 @@ export class IfcStreamer extends OBC.Component implements OBC.Disposable {
393388
* @returns A Promise that resolves when the cache is cleared.
394389
*/
395390
async clearCache() {
396-
await this._fileCache.delete();
391+
await this._fileDB.clear();
397392
}
398393

399394
/**
@@ -489,18 +484,17 @@ export class IfcStreamer extends OBC.Component implements OBC.Disposable {
489484
// If this file is in the local cache, get it
490485
if (this.useCache) {
491486
// Add or update this file to clean it up from indexedDB automatically later
492-
this.dbCleaner.update(url);
487+
// this.dbCleaner.update(url);
493488

494-
const found = await this._fileCache.files.get(url);
489+
const found = await this._fileDB.get(url);
495490

496491
if (found) {
497-
bytes = found.file;
492+
bytes = found;
498493
} else {
499494
const fetched = await this.fetch(url);
500495
const buffer = await fetched.arrayBuffer();
501496
bytes = new Uint8Array(buffer);
502-
// await this._fileCache.files.delete(url);
503-
this._fileCache.files.add({ file: bytes, id: url });
497+
await this._fileDB.add(url, bytes);
504498
}
505499
} else {
506500
const fetched = await this.fetch(url);

‎packages/front/src/fragments/IfcStreamer/src/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from "./geometry-culler-renderer";
22
export * from "./streamer-db";
33
export * from "./types";
44
export * from "./streamer-db-cleaner";
5+
export * from "./streamer-file-db";
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
export class StreamerFileDb {
2+
baseDirectory = "that-open-company-streaming";
3+
4+
maxDeadTime = 60000;
5+
6+
private _memoryCleanTime = 10000;
7+
8+
get memoryCleanTime() {
9+
return this._memoryCleanTime;
10+
}
11+
12+
set memoryCleanTime(value: number) {
13+
this._memoryCleanTime = value;
14+
this.dispose();
15+
this.setupMemoryCleanup();
16+
}
17+
18+
private _intervalID: number | null = null;
19+
20+
private _isCleaningMemory = false;
21+
22+
constructor() {
23+
this.setupMemoryCleanup();
24+
}
25+
26+
async get(name: string) {
27+
const encodedName = this.encodeName(name);
28+
const baseDir = await this.getDir(this.baseDirectory);
29+
try {
30+
const fileHandle = await baseDir.getFileHandle(encodedName);
31+
const file = await fileHandle.getFile();
32+
this.updateLastAccessTime(encodedName);
33+
const buffer = await file.arrayBuffer();
34+
return new Uint8Array(buffer);
35+
} catch (e) {
36+
return null;
37+
}
38+
}
39+
40+
async add(name: string, buffer: Uint8Array) {
41+
const encodedName = this.encodeName(name);
42+
const baseDir = await this.getDir(this.baseDirectory);
43+
const fileHandle = await baseDir.getFileHandle(encodedName, {
44+
create: true,
45+
});
46+
47+
const writable = await fileHandle.createWritable();
48+
await writable.write(buffer);
49+
await writable.close();
50+
this.updateLastAccessTime(encodedName);
51+
}
52+
53+
async clear() {
54+
const baseDir = await this.getDir(this.baseDirectory);
55+
// @ts-ignore
56+
for await (const [name] of baseDir.entries()) {
57+
await baseDir.removeEntry(name);
58+
}
59+
}
60+
61+
dispose() {
62+
if (this._intervalID !== null) {
63+
window.clearInterval(this._intervalID);
64+
}
65+
}
66+
67+
private setupMemoryCleanup() {
68+
this._intervalID = window.setInterval(
69+
this.cleanMemory,
70+
this.memoryCleanTime,
71+
);
72+
}
73+
74+
private cleanMemory = async () => {
75+
if (this._isCleaningMemory) {
76+
return;
77+
}
78+
this._isCleaningMemory = true;
79+
80+
const rootDir = await this.getDir(this.baseDirectory);
81+
82+
const filesToDelete = new Set<string>();
83+
84+
const now = new Date().getTime();
85+
86+
// @ts-ignore
87+
for await (const entry of rootDir.values()) {
88+
const serializedLastAccessed = localStorage.getItem(entry.name) || "0";
89+
const lastAccess = parseInt(serializedLastAccessed, 10);
90+
91+
const deadTime = now - lastAccess;
92+
93+
if (deadTime > this.maxDeadTime) {
94+
filesToDelete.add(entry.name);
95+
localStorage.removeItem(entry.name);
96+
}
97+
}
98+
99+
for (const name of filesToDelete) {
100+
console.log(`deleted: ${name}`);
101+
rootDir.removeEntry(name);
102+
}
103+
104+
this._isCleaningMemory = false;
105+
};
106+
107+
private async getDir(path: string) {
108+
const root = await navigator.storage.getDirectory();
109+
return root.getDirectoryHandle(path, {
110+
create: true,
111+
});
112+
}
113+
114+
private encodeName(name: string) {
115+
const illegalChars = /[\\/:*?"<>|]/g;
116+
return name.replace(illegalChars, "ñ");
117+
}
118+
119+
private updateLastAccessTime(encodedName: string) {
120+
const now = new Date().getTime().toString();
121+
localStorage.setItem(encodedName, now);
122+
}
123+
}

‎packages/front/tsconfig.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@
3434
"excludeProtected": true,
3535
"excludeReferences": true
3636
},
37-
}
37+
}
38+

0 commit comments

Comments
 (0)