molstar
Version:
A comprehensive macromolecular library.
186 lines • 8.14 kB
JavaScript
/**
* 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 * as fs from 'fs';
import * as path from 'path';
import * as bodyParser from 'body-parser';
import { ModelServerConfig as Config, ModelServerConfig, mapSourceAndIdToFilename } from '../config';
import { ConsoleLogger } from '../../../mol-util/console-logger';
import { resolveJob } from './query';
import { JobManager, JobEntry } from './jobs';
import { normalizeRestQueryParams, normalizeRestCommonParams, QueryList } from './api';
import { getApiSchema, shortcutIconLink } from './api-schema';
import { swaggerUiAssetsHandler, swaggerUiIndexHandler } from '../../common/swagger-ui';
import { getMultiQuerySpecFilename } from './api-web-multiple';
import { SimpleResponseResultWriter, TarballResponseResultWriter } from '../utils/writer';
import { splitCamelCase } from '../../../mol-util/string';
function makePath(p) {
return Config.apiPrefix + '/' + p;
}
var responseMap = new Map();
function processNextJob() {
return __awaiter(this, void 0, void 0, function () {
var job, writer, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!JobManager.hasNext())
return [2 /*return*/];
job = JobManager.getNext();
responseMap.delete(job.id);
writer = job.writer;
_a.label = 1;
case 1:
_a.trys.push([1, 3, 4, 5]);
return [4 /*yield*/, resolveJob(job)];
case 2:
_a.sent();
return [3 /*break*/, 5];
case 3:
e_1 = _a.sent();
ConsoleLogger.errorId(job.id, '' + e_1);
writer.doError(404, '' + e_1);
return [3 /*break*/, 5];
case 4:
writer.end();
ConsoleLogger.logId(job.id, 'Query', 'Finished.');
setImmediate(processNextJob);
return [7 /*endfinally*/];
case 5: return [2 /*return*/];
}
});
});
}
export function createResultWriter(response, params) {
var filenameBase = params.entryId && params.queryName
? params.entryId + "_" + splitCamelCase(params.queryName.replace(/\s/g, '_'), '-').toLowerCase()
: "result";
return new SimpleResponseResultWriter(params.filename || filenameBase + "." + params.encoding, response, params.encoding === 'bcif', params.download);
}
function mapQuery(app, queryName, queryDefinition) {
function createJob(queryParams, req, res) {
var entryId = req.params.id;
var commonParams = normalizeRestCommonParams(req.query);
var resultWriterParams = { encoding: commonParams.encoding, download: !!commonParams.download, filename: commonParams.filename, entryId: entryId, queryName: queryName };
var jobId = JobManager.add({
entries: [JobEntry({
sourceId: commonParams.data_source || ModelServerConfig.defaultSource,
entryId: entryId,
queryName: queryName,
queryParams: queryParams,
modelNums: commonParams.model_nums,
copyAllCategories: !!commonParams.copy_all_categories,
transform: commonParams.transform
})],
writer: createResultWriter(res, resultWriterParams),
options: { binary: commonParams.encoding === 'bcif', encoding: commonParams.encoding }
});
responseMap.set(jobId, res);
if (JobManager.size === 1)
processNextJob();
}
app.get(makePath('v1/:id/' + queryName), function (req, res) {
var queryParams = normalizeRestQueryParams(queryDefinition, req.query);
createJob(queryParams, req, res);
});
app.post(makePath('v1/:id/' + queryName), function (req, res) {
var queryParams = req.body;
createJob(queryParams, req, res);
});
}
function serveStatic(req, res) {
var source = req.params.source === 'bcif'
? 'pdb-bcif'
: req.params.source === 'cif'
? 'pdb-cif'
: req.params.source;
var id = req.params.id;
var _a = mapSourceAndIdToFilename(source, id), fn = _a[0], format = _a[1];
var binary = format === 'bcif' || fn.indexOf('.bcif') > 0;
if (!fn || !fs.existsSync(fn)) {
res.status(404);
res.end();
return;
}
fs.readFile(fn, function (err, data) {
if (err) {
res.status(404);
res.end();
return;
}
var f = path.parse(fn);
res.writeHead(200, {
'Content-Type': binary ? 'application/octet-stream' : 'text/plain; charset=utf-8',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Requested-With',
'Content-Disposition': "inline; filename=\"" + f.name + f.ext + "\""
});
res.write(data);
res.end();
});
}
function createMultiJob(spec, res) {
var _a;
var writer = spec.asTarGz
? new TarballResponseResultWriter(getMultiQuerySpecFilename(), res)
: createResultWriter(res, { encoding: spec.encoding, download: !!spec.download, filename: spec.filename });
if (spec.queries.length > ModelServerConfig.maxQueryManyQueries) {
writer.doError(400, "query-many queries limit (" + ModelServerConfig.maxQueryManyQueries + ") exceeded.");
return;
}
var jobId = JobManager.add({
entries: spec.queries.map(function (q) { return JobEntry({
sourceId: q.data_source || ModelServerConfig.defaultSource,
entryId: q.entryId,
queryName: q.query,
queryParams: q.params || {},
modelNums: q.model_nums,
copyAllCategories: !!q.copy_all_categories
}); }),
writer: writer,
options: { binary: ((_a = spec.encoding) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'bcif', tarball: spec.asTarGz }
});
responseMap.set(jobId, res);
if (JobManager.size === 1)
processNextJob();
}
export function initWebApi(app) {
app.use(bodyParser.json({ limit: '1mb' }));
app.get(makePath('static/:source/:id'), function (req, res) { return serveStatic(req, res); });
app.get(makePath('v1/static/:source/:id'), function (req, res) { return serveStatic(req, res); });
app.get(makePath('v1/query-many'), function (req, res) {
var query = /\?query=(.*)$/.exec(req.url)[1];
var params = JSON.parse(decodeURIComponent(query));
createMultiJob(params, res);
});
app.post(makePath('v1/query-many'), function (req, res) {
var params = req.body;
req.setTimeout;
createMultiJob(params, res);
});
app.use(bodyParser.json({ limit: '20mb' }));
for (var _i = 0, QueryList_1 = QueryList; _i < QueryList_1.length; _i++) {
var q = QueryList_1[_i];
mapQuery(app, q.name, q.definition);
}
var schema = getApiSchema();
app.get(makePath('openapi.json'), function (req, res) {
res.writeHead(200, {
'Content-Type': 'application/json; charset=utf-8',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Requested-With'
});
res.end(JSON.stringify(schema));
});
app.use(makePath(''), swaggerUiAssetsHandler());
app.get(makePath(''), swaggerUiIndexHandler({
openapiJsonUrl: makePath('openapi.json'),
apiPrefix: Config.apiPrefix,
title: 'ModelServer API',
shortcutIconLink: shortcutIconLink
}));
}
//# sourceMappingURL=api-web.js.map