Browse Source

basic asset manager for file objects

Alexander Rose 5 years ago
parent
commit
9400f27f82

+ 19 - 2
src/mol-plugin-state/transforms/data.ts

@@ -18,6 +18,7 @@ import * as DSN6 from '../../mol-io/reader/dsn6/parser';
 import * as PLY from '../../mol-io/reader/ply/parser';
 import { parsePsf } from '../../mol-io/reader/psf/parser';
 import { isTypedArray } from '../../mol-data/db/column-helpers';
+import { AssetManager } from '../../mol-plugin/util/asset-manager';
 
 export { Download };
 type Download = typeof Download
@@ -149,10 +150,26 @@ const ReadFile = PluginStateTransform.BuiltIn({
                 plugin.log.error('No file(s) selected');
                 return StateObject.Null;
             }
-            const data = await readFromFile(p.file, p.isBinary ? 'binary' : 'string').runInContext(ctx);
-            return p.isBinary
+
+            let file: File;
+            if (AssetManager.isItem(p.file)) {
+                if (!plugin.managers.asset.has(p.file.id)) {
+                    throw new Error(`No asset found for '${p.file.name}'`);
+                }
+                file = plugin.managers.asset.get(p.file.id)!;
+                // will be added again below with new id
+                plugin.managers.asset.remove(p.file.id);
+            } else {
+                file = p.file;
+            }
+
+            const data = await readFromFile(file, p.isBinary ? 'binary' : 'string').runInContext(ctx);
+            const o = p.isBinary
                 ? new SO.Data.Binary(data as Uint8Array, { label: p.label ? p.label : p.file.name })
                 : new SO.Data.String(data as string, { label: p.label ? p.label : p.file.name });
+
+            plugin.managers.asset.set(o.id, file);
+            return o;
         });
     },
     update({ oldParams, newParams, b }) {

+ 3 - 1
src/mol-plugin/context.ts

@@ -53,6 +53,7 @@ import { TaskManager } from './util/task-manager';
 import { PluginToastManager } from './util/toast';
 import { ViewportScreenshotHelper } from './util/viewport-screenshot';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
+import { AssetManager } from './util/asset-manager';
 
 export class PluginContext {
     runTask = <T>(task: Task<T>) => this.tasks.run(task);
@@ -150,7 +151,8 @@ export class PluginContext {
         interactivity: void 0 as any as InteractivityManager,
         camera: new CameraManager(this),
         lociLabels: void 0 as any as LociLabelManager,
-        toast: new PluginToastManager(this)
+        toast: new PluginToastManager(this),
+        asset: new AssetManager(this)
     } as const
 
     readonly customModelProperties = new CustomProperty.Registry<Model>();

+ 73 - 0
src/mol-plugin/util/asset-manager.ts

@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { UUID } from '../../mol-util';
+import { PluginContext } from '../context';
+import { iterableToArray } from '../../mol-data/util';
+
+export { AssetManager };
+
+class AssetManager {
+    private files = new Map<UUID, File>()
+    private ids = new Map<File, UUID>()
+
+    get list() {
+        return iterableToArray(this.ids.entries());
+    }
+
+    set(id: UUID, file: File) {
+        this.files.set(id, file);
+        this.ids.set(file, id);
+    }
+
+    remove(id: UUID) {
+        if (this.files.has(id)) {
+            const file = this.files.get(id)!;
+            this.files.delete(id);
+            this.ids.delete(file);
+        }
+    }
+
+    has(id: UUID) {
+        return this.files.has(id);
+    }
+
+    get(id: UUID) {
+        return this.files.get(id);
+    }
+
+    /** For use with `JSON.stringify` */
+    replacer = (key: string, value: any) => {
+        if (value instanceof File) {
+            const id = this.ids.get(value);
+            if (!id) {
+                // TODO throw?
+                console.warn(`No asset found for '${value.name}'`);
+            }
+            return id ? AssetManager.Item(id, value.name) : {};
+        } else {
+            return value;
+        }
+    }
+
+    constructor(public ctx: PluginContext) {
+        ctx.state.data.events.object.removed.subscribe(e => {
+            const id = e.obj?.id;
+            if (id) ctx.managers.asset.remove(id);
+        });
+    }
+}
+
+namespace AssetManager {
+    export type Item = { kind: 'asset-item', id: UUID, name: string };
+    export function Item(id: UUID, name: string): Item {
+        return { kind: 'asset-item', id, name };
+    }
+
+    export function isItem(x?: any): x is Item {
+        return !!x && x?.kind === 'asset-item';
+    }
+}