molstar
Version:
A comprehensive macromolecular library.
354 lines (353 loc) • 16.2 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveStructures = exports.resolveStructure = exports.readStructureWrapper = exports.readDataAndFrame = exports.StructureCache = exports.createStructureWrapperFromJobEntry = exports.StructureSourceType = void 0;
var tslib_1 = require("tslib");
var structure_1 = require("../../../mol-model/structure");
var performance_monitor_1 = require("../../../mol-util/performance-monitor");
var cache_1 = require("./cache");
var config_1 = require("../config");
var cif_1 = require("../../../mol-io/reader/cif");
var util = tslib_1.__importStar(require("util"));
var fs = tslib_1.__importStar(require("fs"));
var zlib = tslib_1.__importStar(require("zlib"));
var console_logger_1 = require("../../../mol-util/console-logger");
var mmcif_1 = require("../../../mol-model-formats/structure/mmcif");
var fetch_retry_1 = require("../utils/fetch-retry");
var mol_task_1 = require("../../../mol-task");
require('util.promisify').shim();
var StructureSourceType;
(function (StructureSourceType) {
StructureSourceType[StructureSourceType["File"] = 0] = "File";
StructureSourceType[StructureSourceType["Cache"] = 1] = "Cache";
})(StructureSourceType = exports.StructureSourceType || (exports.StructureSourceType = {}));
function createStructureWrapperFromJobEntry(entry, propertyProvider, allowCache) {
if (allowCache === void 0) { allowCache = true; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var ret_1, ret;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (allowCache && config_1.ModelServerConfig.cacheMaxSizeInBytes > 0) {
ret_1 = exports.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_1.ModelServerConfig.cacheMaxSizeInBytes > 0) {
exports.StructureCache.add(ret);
}
return [2 /*return*/, ret];
}
});
});
}
exports.createStructureWrapperFromJobEntry = createStructureWrapperFromJobEntry;
exports.StructureCache = new cache_1.Cache(function (s) { return s.key; }, function (s) { return s.approximateSize; });
var perf = new performance_monitor_1.PerformanceMonitor();
var readFileAsync = util.promisify(fs.readFile);
var unzipAsync = util.promisify(zlib.unzip);
function readFile(filename) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var isGz, input, data, i, data, _a;
var _b;
return tslib_1.__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 tslib_1.__awaiter(this, void 0, void 0, function () {
var comp, parsed;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
comp = cif_1.CIF.parse(data);
return [4 /*yield*/, comp.run()];
case 1:
parsed = _a.sent();
if (parsed.isError)
throw parsed;
return [2 /*return*/, parsed.result];
}
});
});
}
function readDataAndFrame(filename, key) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var data, isBinary, read, e_1, frame;
return tslib_1.__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();
console_logger_1.ConsoleLogger.error(key || filename, '' + e_1);
throw new Error("Could not read the file for '".concat(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 }];
}
});
});
}
exports.readDataAndFrame = readDataAndFrame;
function fetchDataAndFrame(jobId, uri, format, key) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var isBinary, data, response, input, _a, i, _b, _c, e_2, frame;
return tslib_1.__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]);
console_logger_1.ConsoleLogger.logId(jobId, 'Fetch', "".concat(uri));
return [4 /*yield*/, (0, fetch_retry_1.fetchRetry)(uri, 500, 3, function () { return console_logger_1.ConsoleLogger.logId(jobId, 'Fetch', "Retrying to fetch '".concat(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();
console_logger_1.ConsoleLogger.error(key || uri, '' + e_2);
throw new Error("Could not fetch the file for '".concat(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] : (0, config_1.mapSourceAndIdToFilename)(sourceId, entryId);
if (!mapped)
throw new Error("Cound not map '".concat(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 '".concat(key, "'."));
return readDataAndFrame(mapped[0], key);
}
function readStructureWrapper(key, sourceId, entryId, jobId, propertyProvider) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, data, frame, isBinary, trajectory, models, modelMap, i, m, ret;
return tslib_1.__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*/, (0, mmcif_1.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*/, mol_task_1.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];
}
});
});
}
exports.readStructureWrapper = readStructureWrapper;
function resolveStructure(wrapper, modelNum) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var model, structure, modelProps, _i, modelProps_1, p;
return tslib_1.__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_1.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];
}
});
});
}
exports.resolveStructure = resolveStructure;
function resolveStructures(wrapper, modelNums) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var ret, _i, _a, n, s;
return tslib_1.__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];
}
});
});
}
exports.resolveStructures = resolveStructures;
function tryAttach(key, promise) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var e_3;
return tslib_1.__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();
console_logger_1.ConsoleLogger.errorId(key, 'Custom prop:' + e_3);
return [3 /*break*/, 3];
case 3: return [2 /*return*/];
}
});
});
}