|
@@ -12,7 +12,7 @@ import CIF from 'mol-io/reader/cif'
|
|
import { PluginContext } from 'mol-plugin/context';
|
|
import { PluginContext } from 'mol-plugin/context';
|
|
import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
import { StateTransformer } from 'mol-state';
|
|
import { StateTransformer } from 'mol-state';
|
|
-import { readFromFile } from 'mol-util/data-source';
|
|
|
|
|
|
+import { readFromFile, ajaxGetMany } from 'mol-util/data-source';
|
|
import * as CCP4 from 'mol-io/reader/ccp4/parser'
|
|
import * as CCP4 from 'mol-io/reader/ccp4/parser'
|
|
import * as DSN6 from 'mol-io/reader/dsn6/parser'
|
|
import * as DSN6 from 'mol-io/reader/dsn6/parser'
|
|
|
|
|
|
@@ -47,6 +47,52 @@ const Download = PluginStateTransform.BuiltIn({
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+export { DownloadBlob }
|
|
|
|
+type DownloadBlob = typeof DownloadBlob
|
|
|
|
+const DownloadBlob = PluginStateTransform.BuiltIn({
|
|
|
|
+ name: 'download-blob',
|
|
|
|
+ display: { name: 'Download Blob', description: 'Download multiple string or binary data from the specified URLs.' },
|
|
|
|
+ from: SO.Root,
|
|
|
|
+ to: SO.Data.Blob,
|
|
|
|
+ params: {
|
|
|
|
+ sources: PD.ObjectList({
|
|
|
|
+ id: PD.Text('', { label: 'Unique ID' }),
|
|
|
|
+ url: PD.Text('https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif', { description: 'Resource URL. Must be the same domain or support CORS.' }),
|
|
|
|
+ isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })),
|
|
|
|
+ canFail: PD.makeOptional(PD.Boolean(false, { description: 'Indicate whether the download can fail and not be included in the blob as a result.' }))
|
|
|
|
+ }, e => `${e.id}: ${e.url}`),
|
|
|
|
+ maxConcurrency: PD.makeOptional(PD.Numeric(4, { min: 1, max: 12, step: 1 }, { description: 'The maximum number of concurrent downloads.' }))
|
|
|
|
+ }
|
|
|
|
+})({
|
|
|
|
+ apply({ params }, plugin: PluginContext) {
|
|
|
|
+ return Task.create('Download Blob', async ctx => {
|
|
|
|
+ const entries: SO.Data.BlobEntry[] = [];
|
|
|
|
+ const data = await ajaxGetMany(ctx, params.sources, params.maxConcurrency || 4);
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
|
+ const r = data[i], src = params.sources[i];
|
|
|
|
+ if (r.kind === 'error') plugin.log.warn(`Download ${r.id} (${src.url}) failed: ${r.error}`);
|
|
|
|
+ else {
|
|
|
|
+ entries.push(src.isBinary
|
|
|
|
+ ? { id: r.id, kind: 'binary', data: r.result as Uint8Array }
|
|
|
|
+ : { id: r.id, kind: 'string', data: r.result as string });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return new SO.Data.Blob(entries, { label: 'Data Blob', description: `${entries.length} ${entries.length === 1 ? 'entry' : 'entries'}` });
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ // TODO: ??
|
|
|
|
+ // update({ oldParams, newParams, b }) {
|
|
|
|
+ // return 0 as any;
|
|
|
|
+ // // if (oldParams.url !== newParams.url || oldParams.isBinary !== newParams.isBinary) return StateTransformer.UpdateResult.Recreate;
|
|
|
|
+ // // if (oldParams.label !== newParams.label) {
|
|
|
|
+ // // (b.label as string) = newParams.label || newParams.url;
|
|
|
|
+ // // return StateTransformer.UpdateResult.Updated;
|
|
|
|
+ // // }
|
|
|
|
+ // // return StateTransformer.UpdateResult.Unchanged;
|
|
|
|
+ // }
|
|
|
|
+});
|
|
|
|
+
|
|
export { ReadFile }
|
|
export { ReadFile }
|
|
type ReadFile = typeof ReadFile
|
|
type ReadFile = typeof ReadFile
|
|
const ReadFile = PluginStateTransform.BuiltIn({
|
|
const ReadFile = PluginStateTransform.BuiltIn({
|
|
@@ -78,6 +124,50 @@ const ReadFile = PluginStateTransform.BuiltIn({
|
|
isSerializable: () => ({ isSerializable: false, reason: 'Cannot serialize user loaded files.' })
|
|
isSerializable: () => ({ isSerializable: false, reason: 'Cannot serialize user loaded files.' })
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+export { ParseBlob }
|
|
|
|
+type ParseBlob = typeof ParseBlob
|
|
|
|
+const ParseBlob = PluginStateTransform.BuiltIn({
|
|
|
|
+ name: 'parse-blob',
|
|
|
|
+ display: { name: 'Parse Blob', description: 'Parse multiple data enties' },
|
|
|
|
+ from: SO.Data.Blob,
|
|
|
|
+ to: SO.Format.Blob,
|
|
|
|
+ params: {
|
|
|
|
+ formats: PD.ObjectList({
|
|
|
|
+ id: PD.Text('', { label: 'Unique ID' }),
|
|
|
|
+ format: PD.Select<'cif'>('cif', [['cif', 'cif']])
|
|
|
|
+ }, e => `${e.id}: ${e.format}`)
|
|
|
|
+ }
|
|
|
|
+})({
|
|
|
|
+ apply({ a, params }, plugin: PluginContext) {
|
|
|
|
+ return Task.create('Parse Blob', async ctx => {
|
|
|
|
+ const map = new Map<string, string>();
|
|
|
|
+ for (const f of params.formats) map.set(f.id, f.format);
|
|
|
|
+
|
|
|
|
+ const entries: SO.Format.BlobEntry[] = [];
|
|
|
|
+
|
|
|
|
+ for (const e of a.data) {
|
|
|
|
+ if (!map.has(e.id)) continue;
|
|
|
|
+
|
|
|
|
+ const parsed = await (e.kind === 'string' ? CIF.parse(e.data) : CIF.parseBinary(e.data)).runInContext(ctx);
|
|
|
|
+ if (parsed.isError) throw new Error(`${e.id}: ${parsed.message}`);
|
|
|
|
+ entries.push({ id: e.id, kind: 'cif', data: parsed.result });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return new SO.Format.Blob(entries, { label: 'Format Blob', description: `${entries.length} ${entries.length === 1 ? 'entry' : 'entries'}` });
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ // TODO: ??
|
|
|
|
+ // update({ oldParams, newParams, b }) {
|
|
|
|
+ // return 0 as any;
|
|
|
|
+ // // if (oldParams.url !== newParams.url || oldParams.isBinary !== newParams.isBinary) return StateTransformer.UpdateResult.Recreate;
|
|
|
|
+ // // if (oldParams.label !== newParams.label) {
|
|
|
|
+ // // (b.label as string) = newParams.label || newParams.url;
|
|
|
|
+ // // return StateTransformer.UpdateResult.Updated;
|
|
|
|
+ // // }
|
|
|
|
+ // // return StateTransformer.UpdateResult.Unchanged;
|
|
|
|
+ // }
|
|
|
|
+});
|
|
|
|
+
|
|
export { ParseCif }
|
|
export { ParseCif }
|
|
type ParseCif = typeof ParseCif
|
|
type ParseCif = typeof ParseCif
|
|
const ParseCif = PluginStateTransform.BuiltIn({
|
|
const ParseCif = PluginStateTransform.BuiltIn({
|