|
@@ -4,35 +4,18 @@
|
|
|
* @author David Sehnal <david.sehnal@gmail.com>
|
|
|
*/
|
|
|
|
|
|
-import { UUID } from 'mol-util';
|
|
|
-import { getQueryByName, normalizeQueryParams, QueryDefinition } from './api';
|
|
|
-import { getStructure, StructureWrapper } from './structure-wrapper';
|
|
|
-import Config from '../config';
|
|
|
-import { Progress, now } from 'mol-task';
|
|
|
-import { ConsoleLogger } from 'mol-util/console-logger';
|
|
|
-import Writer from 'mol-io/writer/writer';
|
|
|
-import { CifWriter } from 'mol-io/writer/cif'
|
|
|
-import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
|
|
|
-import { StructureSelection, StructureQuery } from 'mol-model/structure';
|
|
|
-import Version from '../version'
|
|
|
import { Column } from 'mol-data/db';
|
|
|
+import { CifWriter } from 'mol-io/writer/cif';
|
|
|
+import { StructureQuery, StructureSelection } from 'mol-model/structure';
|
|
|
+import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
|
|
|
+import { now, Progress } from 'mol-task';
|
|
|
+import { ConsoleLogger } from 'mol-util/console-logger';
|
|
|
import { PerformanceMonitor } from 'mol-util/performance-monitor';
|
|
|
-
|
|
|
-export interface ResponseFormat {
|
|
|
- isBinary: boolean
|
|
|
-}
|
|
|
-
|
|
|
-export interface Request {
|
|
|
- id: UUID,
|
|
|
- datetime_utc: string,
|
|
|
-
|
|
|
- sourceId: '_local_' | string,
|
|
|
- entryId: string,
|
|
|
-
|
|
|
- queryDefinition: QueryDefinition,
|
|
|
- normalizedParams: any,
|
|
|
- responseFormat: ResponseFormat
|
|
|
-}
|
|
|
+import Config from '../config';
|
|
|
+import Version from '../version';
|
|
|
+import { Job } from './jobs';
|
|
|
+import { getStructure, StructureWrapper } from './structure-wrapper';
|
|
|
+import CifField = CifWriter.Field
|
|
|
|
|
|
export interface Stats {
|
|
|
structure: StructureWrapper,
|
|
@@ -40,66 +23,58 @@ export interface Stats {
|
|
|
encodeTimeMs: number
|
|
|
}
|
|
|
|
|
|
-export function createRequest(sourceId: '_local_' | string, entryId: string, queryName: string, params: any): Request {
|
|
|
- const queryDefinition = getQueryByName(queryName);
|
|
|
- if (!queryDefinition) throw new Error(`Query '${queryName}' is not supported.`);
|
|
|
-
|
|
|
- const normalizedParams = normalizeQueryParams(queryDefinition, params);
|
|
|
-
|
|
|
- return {
|
|
|
- id: UUID.create(),
|
|
|
- datetime_utc: `${new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')}`,
|
|
|
- sourceId,
|
|
|
- entryId,
|
|
|
- queryDefinition,
|
|
|
- normalizedParams,
|
|
|
- responseFormat: { isBinary: !!params.binary }
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
const perf = new PerformanceMonitor();
|
|
|
|
|
|
-export async function resolveRequest(req: Request, writer: Writer) {
|
|
|
- ConsoleLogger.logId(req.id, 'Query', 'Starting.');
|
|
|
-
|
|
|
- const wrappedStructure = await getStructure(req.sourceId, req.entryId);
|
|
|
-
|
|
|
- perf.start('query');
|
|
|
- const structure = req.queryDefinition.structureTransform
|
|
|
- ? await req.queryDefinition.structureTransform(req.normalizedParams, wrappedStructure.structure)
|
|
|
- : wrappedStructure.structure;
|
|
|
- const query = req.queryDefinition.query(req.normalizedParams, structure);
|
|
|
- const result = StructureSelection.unionStructure(await StructureQuery.asTask(query, structure).run(abortingObserver, 250));
|
|
|
- perf.end('query');
|
|
|
-
|
|
|
- ConsoleLogger.logId(req.id, 'Query', 'Query finished.');
|
|
|
-
|
|
|
- const encoder = CifWriter.createEncoder({ binary: req.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
|
|
|
-
|
|
|
- perf.start('encode');
|
|
|
- encoder.startDataBlock(structure.units[0].model.label.toUpperCase());
|
|
|
- encoder.writeCategory(_model_server_result, [req]);
|
|
|
- encoder.writeCategory(_model_server_params, [req]);
|
|
|
-
|
|
|
- // encoder.setFilter(mmCIF_Export_Filters.onlyPositions);
|
|
|
- encode_mmCIF_categories(encoder, result);
|
|
|
- // encoder.setFilter();
|
|
|
- perf.end('encode');
|
|
|
-
|
|
|
- ConsoleLogger.logId(req.id, 'Query', 'Encoded.');
|
|
|
-
|
|
|
- const stats: Stats = {
|
|
|
- structure: wrappedStructure,
|
|
|
- queryTimeMs: perf.time('query'),
|
|
|
- encodeTimeMs: perf.time('encode')
|
|
|
- };
|
|
|
+export async function resolveJob(job: Job): Promise<CifWriter.Encoder<any>> {
|
|
|
+ ConsoleLogger.logId(job.id, 'Query', 'Starting.');
|
|
|
+
|
|
|
+ const wrappedStructure = await getStructure(job);
|
|
|
+
|
|
|
+ try {
|
|
|
+ const encoder = CifWriter.createEncoder({ binary: job.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
|
|
|
+ perf.start('query');
|
|
|
+ const structure = job.queryDefinition.structureTransform
|
|
|
+ ? await job.queryDefinition.structureTransform(job.normalizedParams, wrappedStructure.structure)
|
|
|
+ : wrappedStructure.structure;
|
|
|
+ const query = job.queryDefinition.query(job.normalizedParams, structure);
|
|
|
+ const result = await StructureSelection.unionStructure(StructureQuery.run(query, structure, Config.maxQueryTimeInMs));
|
|
|
+ perf.end('query');
|
|
|
+
|
|
|
+ ConsoleLogger.logId(job.id, 'Query', 'Query finished.');
|
|
|
+
|
|
|
+ perf.start('encode');
|
|
|
+ encoder.startDataBlock(structure.units[0].model.label.toUpperCase());
|
|
|
+ encoder.writeCategory(_model_server_result, [job]);
|
|
|
+ encoder.writeCategory(_model_server_params, [job]);
|
|
|
+
|
|
|
+ // encoder.setFilter(mmCIF_Export_Filters.onlyPositions);
|
|
|
+ encode_mmCIF_categories(encoder, result);
|
|
|
+ // encoder.setFilter();
|
|
|
+ perf.end('encode');
|
|
|
+
|
|
|
+ const stats: Stats = {
|
|
|
+ structure: wrappedStructure,
|
|
|
+ queryTimeMs: perf.time('query'),
|
|
|
+ encodeTimeMs: perf.time('encode')
|
|
|
+ };
|
|
|
+
|
|
|
+ encoder.writeCategory(_model_server_stats, [stats]);
|
|
|
+ encoder.encode();
|
|
|
+ ConsoleLogger.logId(job.id, 'Query', 'Encoded.');
|
|
|
+ return encoder;
|
|
|
+ } catch (e) {
|
|
|
+ ConsoleLogger.errorId(job.id, e);
|
|
|
+ return doError(job, e);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- encoder.writeCategory(_model_server_stats, [stats]);
|
|
|
+function doError(job: Job, e: any) {
|
|
|
+ const encoder = CifWriter.createEncoder({ binary: job.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
|
|
|
+ encoder.writeCategory(_model_server_result, [job]);
|
|
|
+ encoder.writeCategory(_model_server_params, [job]);
|
|
|
+ encoder.writeCategory(_model_server_error, ['' + e]);
|
|
|
encoder.encode();
|
|
|
-
|
|
|
- encoder.writeTo(writer);
|
|
|
-
|
|
|
- ConsoleLogger.logId(req.id, 'Query', 'Written.');
|
|
|
+ return encoder;
|
|
|
}
|
|
|
|
|
|
const maxTime = Config.maxQueryTimeInMs;
|
|
@@ -109,8 +84,6 @@ export function abortingObserver(p: Progress) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-import CifField = CifWriter.Field
|
|
|
-
|
|
|
function string<T>(name: string, str: (data: T, i: number) => string, isSpecified?: (data: T) => boolean): CifField<number, T> {
|
|
|
if (isSpecified) {
|
|
|
return CifField.str(name, (i, d) => str(d, i), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
|
|
@@ -122,13 +95,13 @@ function int32<T>(name: string, value: (data: T) => number): CifField<number, T>
|
|
|
return CifField.int(name, (i, d) => value(d));
|
|
|
}
|
|
|
|
|
|
-const _model_server_result_fields: CifField<number, Request>[] = [
|
|
|
- string<Request>('request_id', ctx => '' + ctx.id),
|
|
|
- string<Request>('datetime_utc', ctx => ctx.datetime_utc),
|
|
|
- string<Request>('server_version', ctx => Version),
|
|
|
- string<Request>('query_name', ctx => ctx.queryDefinition.name),
|
|
|
- string<Request>('source_id', ctx => ctx.sourceId),
|
|
|
- string<Request>('entry_id', ctx => ctx.entryId),
|
|
|
+const _model_server_result_fields: CifField<any, Job>[] = [
|
|
|
+ string<Job>('job_id', ctx => '' + ctx.id),
|
|
|
+ string<Job>('datetime_utc', ctx => ctx.datetime_utc),
|
|
|
+ string<Job>('server_version', ctx => Version),
|
|
|
+ string<Job>('query_name', ctx => ctx.queryDefinition.name),
|
|
|
+ string<Job>('source_id', ctx => ctx.sourceId),
|
|
|
+ string<Job>('entry_id', ctx => ctx.entryId),
|
|
|
];
|
|
|
|
|
|
const _model_server_params_fields: CifField<number, string[]>[] = [
|
|
@@ -136,6 +109,10 @@ const _model_server_params_fields: CifField<number, string[]>[] = [
|
|
|
string<string[]>('value', (ctx, i) => ctx[i][1])
|
|
|
];
|
|
|
|
|
|
+const _model_server_error_fields: CifField<number, string>[] = [
|
|
|
+ string<string>('message', (ctx, i) => ctx)
|
|
|
+];
|
|
|
+
|
|
|
const _model_server_stats_fields: CifField<number, Stats>[] = [
|
|
|
int32<Stats>('io_time_ms', ctx => ctx.structure.info.readTime | 0),
|
|
|
int32<Stats>('parse_time_ms', ctx => ctx.structure.info.parseTime | 0),
|
|
@@ -144,18 +121,22 @@ const _model_server_stats_fields: CifField<number, Stats>[] = [
|
|
|
int32<Stats>('encode_time_ms', ctx => ctx.encodeTimeMs | 0)
|
|
|
];
|
|
|
|
|
|
-
|
|
|
-const _model_server_result: CifWriter.Category<Request> = {
|
|
|
+const _model_server_result: CifWriter.Category<Job> = {
|
|
|
name: 'model_server_result',
|
|
|
- instance: (request) => ({ data: request, fields: _model_server_result_fields, rowCount: 1 })
|
|
|
+ instance: (job) => ({ data: job, fields: _model_server_result_fields, rowCount: 1 })
|
|
|
+};
|
|
|
+
|
|
|
+const _model_server_error: CifWriter.Category<string> = {
|
|
|
+ name: 'model_server_error',
|
|
|
+ instance: (message) => ({ data: message, fields: _model_server_error_fields, rowCount: 1 })
|
|
|
};
|
|
|
|
|
|
-const _model_server_params: CifWriter.Category<Request> = {
|
|
|
+const _model_server_params: CifWriter.Category<Job> = {
|
|
|
name: 'model_server_params',
|
|
|
- instance(request) {
|
|
|
+ instance(job) {
|
|
|
const params: string[][] = [];
|
|
|
- for (const k of Object.keys(request.normalizedParams)) {
|
|
|
- params.push([k, '' + request.normalizedParams[k]]);
|
|
|
+ for (const k of Object.keys(job.normalizedParams)) {
|
|
|
+ params.push([k, '' + job.normalizedParams[k]]);
|
|
|
}
|
|
|
return {
|
|
|
data: params,
|