UNPKG

molstar

Version:

A comprehensive macromolecular library.

346 lines 15.3 kB
/** * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { __awaiter, __generator } from "tslib"; import { Structure } from '../../../mol-model/structure'; import { PerformanceMonitor } from '../../../mol-util/performance-monitor'; import { Cache } from './cache'; import { ModelServerConfig as Config, mapSourceAndIdToFilename } from '../config'; import { CIF } from '../../../mol-io/reader/cif'; import * as util from 'util'; import * as fs from 'fs'; import * as zlib from 'zlib'; import { ConsoleLogger } from '../../../mol-util/console-logger'; import { trajectoryFromMmCIF } from '../../../mol-model-formats/structure/mmcif'; import { fetchRetry } from '../utils/fetch-retry'; import { Task } from '../../../mol-task'; require('util.promisify').shim(); export var StructureSourceType; (function (StructureSourceType) { StructureSourceType[StructureSourceType["File"] = 0] = "File"; StructureSourceType[StructureSourceType["Cache"] = 1] = "Cache"; })(StructureSourceType || (StructureSourceType = {})); export function createStructureWrapperFromJobEntry(entry, propertyProvider, allowCache) { if (allowCache === void 0) { allowCache = true; } return __awaiter(this, void 0, void 0, function () { var ret_1, ret; return __generator(this, function (_a) { switch (_a.label) { case 0: if (allowCache && Config.cacheMaxSizeInBytes > 0) { ret_1 = StructureCache.get(entry.key); if (ret_1) return [2 /*return*/, ret_1]; } return [4 /*yield*/, readStructureWrapper(entry.key, entry.sourceId, entry.entryId, entry.job.id, propertyProvider)]; case 1: ret = _a.sent(); if (allowCache && Config.cacheMaxSizeInBytes > 0) { StructureCache.add(ret); } return [2 /*return*/, ret]; } }); }); } export var StructureCache = new Cache(function (s) { return s.key; }, function (s) { return s.approximateSize; }); var perf = new PerformanceMonitor(); var readFileAsync = util.promisify(fs.readFile); var unzipAsync = util.promisify(zlib.unzip); function readFile(filename) { return __awaiter(this, void 0, void 0, function () { var isGz, input, data, i, data, _a; var _b; return __generator(this, function (_c) { switch (_c.label) { case 0: isGz = /\.gz$/i.test(filename); if (!filename.match(/\.bcif/)) return [3 /*break*/, 4]; return [4 /*yield*/, readFileAsync(filename)]; case 1: input = _c.sent(); if (!isGz) return [3 /*break*/, 3]; return [4 /*yield*/, unzipAsync(input)]; case 2: input = _c.sent(); _c.label = 3; case 3: data = new Uint8Array(input.byteLength); for (i = 0; i < input.byteLength; i++) data[i] = input[i]; return [2 /*return*/, { data: data, isBinary: true }]; case 4: if (!isGz) return [3 /*break*/, 7]; _a = unzipAsync; return [4 /*yield*/, readFileAsync(filename)]; case 5: return [4 /*yield*/, _a.apply(void 0, [_c.sent()])]; case 6: data = _c.sent(); return [2 /*return*/, { data: data.toString('utf8'), isBinary: false }]; case 7: _b = {}; return [4 /*yield*/, readFileAsync(filename, 'utf8')]; case 8: return [2 /*return*/, (_b.data = _c.sent(), _b.isBinary = false, _b)]; } }); }); } function parseCif(data) { return __awaiter(this, void 0, void 0, function () { var comp, parsed; return __generator(this, function (_a) { switch (_a.label) { case 0: comp = CIF.parse(data); return [4 /*yield*/, comp.run()]; case 1: parsed = _a.sent(); if (parsed.isError) throw parsed; return [2 /*return*/, parsed.result]; } }); }); } export function readDataAndFrame(filename, key) { return __awaiter(this, void 0, void 0, function () { var data, isBinary, read, e_1, frame; return __generator(this, function (_a) { switch (_a.label) { case 0: perf.start('read'); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, readFile(filename)]; case 2: read = _a.sent(); data = read.data; isBinary = read.isBinary; return [3 /*break*/, 4]; case 3: e_1 = _a.sent(); ConsoleLogger.error(key || filename, '' + e_1); throw new Error("Could not read the file for '" + (key || filename) + "' from disk."); case 4: perf.end('read'); perf.start('parse'); return [4 /*yield*/, parseCif(data)]; case 5: frame = (_a.sent()).blocks[0]; perf.end('parse'); return [2 /*return*/, { data: data, frame: frame, isBinary: isBinary }]; } }); }); } function fetchDataAndFrame(jobId, uri, format, key) { return __awaiter(this, void 0, void 0, function () { var isBinary, data, response, input, _a, i, _b, _c, e_2, frame; return __generator(this, function (_d) { switch (_d.label) { case 0: perf.start('read'); isBinary = format.startsWith('bcif'); _d.label = 1; case 1: _d.trys.push([1, 11, , 12]); ConsoleLogger.logId(jobId, 'Fetch', "" + uri); return [4 /*yield*/, fetchRetry(uri, 500, 3, function () { return ConsoleLogger.logId(jobId, 'Fetch', "Retrying to fetch '" + uri + "'"); })]; case 2: response = _d.sent(); if (!format.endsWith('.gz')) return [3 /*break*/, 5]; _a = unzipAsync; return [4 /*yield*/, response.arrayBuffer()]; case 3: return [4 /*yield*/, _a.apply(void 0, [_d.sent()])]; case 4: input = _d.sent(); if (isBinary) { data = new Uint8Array(input.byteLength); for (i = 0; i < input.byteLength; i++) data[i] = input[i]; } else { data = input.toString('utf8'); } return [3 /*break*/, 10]; case 5: if (!isBinary) return [3 /*break*/, 7]; _c = Uint8Array.bind; return [4 /*yield*/, response.arrayBuffer()]; case 6: _b = new (_c.apply(Uint8Array, [void 0, _d.sent()]))(); return [3 /*break*/, 9]; case 7: return [4 /*yield*/, response.text()]; case 8: _b = _d.sent(); _d.label = 9; case 9: data = _b; _d.label = 10; case 10: return [3 /*break*/, 12]; case 11: e_2 = _d.sent(); ConsoleLogger.error(key || uri, '' + e_2); throw new Error("Could not fetch the file for '" + (key || uri) + "'."); case 12: perf.end('read'); perf.start('parse'); return [4 /*yield*/, parseCif(data)]; case 13: frame = (_d.sent()).blocks[0]; perf.end('parse'); return [2 /*return*/, { data: data, frame: frame, isBinary: isBinary }]; } }); }); } function readOrFetch(jobId, key, sourceId, entryId) { var mapped = sourceId === '_local_' ? [entryId] : mapSourceAndIdToFilename(sourceId, entryId); if (!mapped) throw new Error("Cound not map '" + key + "' for a resource."); var uri = mapped[0].toLowerCase(); if (uri.startsWith('http://') || uri.startsWith('https://') || uri.startsWith('ftp://')) { return fetchDataAndFrame(jobId, mapped[0], (mapped[1] || 'cif').toLowerCase(), key); } if (!fs.existsSync(mapped[0])) throw new Error("Could not find source file for '" + key + "'."); return readDataAndFrame(mapped[0], key); } export function readStructureWrapper(key, sourceId, entryId, jobId, propertyProvider) { return __awaiter(this, void 0, void 0, function () { var _a, data, frame, isBinary, trajectory, models, modelMap, i, m, ret; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, readOrFetch(jobId || '', key, sourceId, entryId)]; case 1: _a = _b.sent(), data = _a.data, frame = _a.frame, isBinary = _a.isBinary; perf.start('createModel'); return [4 /*yield*/, trajectoryFromMmCIF(frame).run()]; case 2: trajectory = _b.sent(); perf.end('createModel'); models = []; modelMap = new Map(); i = 0; _b.label = 3; case 3: if (!(i < trajectory.frameCount)) return [3 /*break*/, 6]; return [4 /*yield*/, Task.resolveInContext(trajectory.getFrameAtIndex(i))]; case 4: m = _b.sent(); models.push(m); modelMap.set(m.modelNum, m); _b.label = 5; case 5: i++; return [3 /*break*/, 3]; case 6: ret = { info: { sourceType: StructureSourceType.File, readTime: perf.time('read'), parseTime: perf.time('parse'), createModelTime: perf.time('createModel'), attachPropsTime: 0, sourceId: sourceId, entryId: entryId }, isBinary: isBinary, key: key, approximateSize: typeof data === 'string' ? 2 * data.length : data.length, models: models, modelMap: modelMap, structureModelMap: new Map(), cifFrame: frame, propertyProvider: propertyProvider, cache: Object.create(null) }; return [2 /*return*/, ret]; } }); }); } export function resolveStructure(wrapper, modelNum) { return __awaiter(this, void 0, void 0, function () { var model, structure, modelProps, _i, modelProps_1, p; return __generator(this, function (_a) { switch (_a.label) { case 0: if (typeof modelNum === 'undefined') modelNum = wrapper.models[0].modelNum; if (wrapper.structureModelMap.has(modelNum)) return [2 /*return*/, wrapper.structureModelMap.get(modelNum)]; if (!wrapper.modelMap.has(modelNum)) { return [2 /*return*/, void 0]; } model = wrapper.modelMap.get(modelNum); structure = Structure.ofModel(model); if (!wrapper.propertyProvider) return [3 /*break*/, 4]; modelProps = wrapper.propertyProvider(model, wrapper.cache); _i = 0, modelProps_1 = modelProps; _a.label = 1; case 1: if (!(_i < modelProps_1.length)) return [3 /*break*/, 4]; p = modelProps_1[_i]; return [4 /*yield*/, tryAttach(wrapper.key, p)]; case 2: _a.sent(); _a.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/, structure]; } }); }); } export function resolveStructures(wrapper, modelNums) { return __awaiter(this, void 0, void 0, function () { var ret, _i, _a, n, s; return __generator(this, function (_b) { switch (_b.label) { case 0: ret = []; _i = 0, _a = modelNums || wrapper.models.map(function (m) { return m.modelNum; }); _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; n = _a[_i]; return [4 /*yield*/, resolveStructure(wrapper, n)]; case 2: s = _b.sent(); if (s) ret.push(s); _b.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/, ret]; } }); }); } function tryAttach(key, promise) { return __awaiter(this, void 0, void 0, function () { var e_3; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, promise]; case 1: _a.sent(); return [3 /*break*/, 3]; case 2: e_3 = _a.sent(); ConsoleLogger.errorId(key, 'Custom prop:' + e_3); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); } //# sourceMappingURL=structure-wrapper.js.map