molstar
Version:
A comprehensive macromolecular library.
207 lines (206 loc) • 7.94 kB
JavaScript
/**
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import * as argparse from 'argparse';
import { ObjectKeys } from '../../mol-util/type-helpers';
import { VOLUME_SERVER_HEADER } from './server/version';
import * as fs from 'fs';
const DefaultServerConfig = {
apiPrefix: '/VolumeServer',
defaultPort: 1337,
shutdownTimeoutMinutes: 24 * 60, /* a day */
shutdownTimeoutVarianceMinutes: 60,
idMap: [],
healthCheckPath: [],
};
function addLimitsArgs(parser) {
parser.add_argument('--maxRequestBlockCount', {
default: DefaultLimitsConfig.maxRequestBlockCount,
metavar: 'COUNT',
help: `Maximum number of blocks that could be read in 1 query.
This is somewhat tied to the maxOutputSizeInVoxelCountByPrecisionLevel
in that the <maximum number of voxel> = maxRequestBlockCount * <block size>^3.
The default block size is 96 which corresponds to 28,311,552 voxels with 32 max blocks.`
});
parser.add_argument('--maxFractionalBoxVolume', {
default: DefaultLimitsConfig.maxFractionalBoxVolume,
metavar: 'VOLUME',
help: `The maximum fractional volume of the query box (to prevent queries that are too big).`
});
parser.add_argument('--maxOutputSizeInVoxelCountByPrecisionLevel', {
nargs: '+',
default: DefaultLimitsConfig.maxOutputSizeInVoxelCountByPrecisionLevel,
metavar: 'LEVEL',
help: `What is the (approximate) maximum desired size in voxel count by precision level
Rule of thumb: <response gzipped size> in [<voxel count> / 8, <voxel count> / 4].
The maximum number of voxels is tied to maxRequestBlockCount.`
});
}
function addServerArgs(parser) {
parser.add_argument('--apiPrefix', {
default: DefaultServerConfig.apiPrefix,
metavar: 'PREFIX',
help: `Specify the prefix of the API, i.e. <host>/<apiPrefix>/<API queries>`
});
parser.add_argument('--defaultPort', {
default: DefaultServerConfig.defaultPort,
metavar: 'PORT',
type: 'int',
help: `Specify the port the server is running on`
});
parser.add_argument('--shutdownTimeoutMinutes', {
default: DefaultServerConfig.shutdownTimeoutMinutes,
metavar: 'TIME',
type: 'int',
help: `0 for off, server will shut down after this amount of minutes.`
});
parser.add_argument('--shutdownTimeoutVarianceMinutes', {
default: DefaultServerConfig.shutdownTimeoutVarianceMinutes,
metavar: 'VARIANCE',
type: 'int',
help: `modifies the shutdown timer by +/- timeoutVarianceMinutes (to avoid multiple instances shutting at the same time)`
});
parser.add_argument('--idMap', {
nargs: 2,
action: 'append',
metavar: ['TYPE', 'PATH'],
help: [
'Map `id`s for a `type` to a file path or URL.',
'Example: x-ray \'../../data/mdb/xray/${id}-ccp4.mdb\'',
'',
' - JS expressions can be used inside ${}, e.g. \'${id.substr(1, 2)}/${id}.mdb\'',
' - Can be specified multiple times.',
' - The `TYPE` variable (e.g. `x-ray`) is arbitrary and depends on how you plan to use the server.',
' By default, Mol* Viewer uses `x-ray` and `em`, but any particular use case may vary. ',
' - If using URL, it can be http://, https://, gs:// or file:// protocol.',
].join('\n'),
});
parser.add_argument('--healthCheckPath', {
default: DefaultServerConfig.healthCheckPath,
action: 'append',
metavar: 'PATH',
help: `File path(s) to use for health-checks. Will test if all files are accessible and report a failed health-check if that's not the case.`,
});
}
function addJsonConfigArgs(parser) {
parser.add_argument('--cfg', {
help: [
'JSON config file path',
'If a property is not specified, cmd line param/OS variable/default value are used.'
].join('\n'),
required: false,
});
parser.add_argument('--printCfg', { help: 'Print current config for validation and exit.', required: false, action: 'store_true' });
parser.add_argument('--cfgTemplate', { help: 'Prints default JSON config template to be modified and exits.', required: false, action: 'store_true' });
}
export const ServerConfig = { ...DefaultServerConfig };
function setServerConfig(config) {
for (const k of ObjectKeys(ServerConfig)) {
if (config[k] !== void 0)
ServerConfig[k] = config[k];
}
}
function validateServerConfig() {
if (!ServerConfig.idMap || ServerConfig.idMap.length === 0) {
throw new Error(`Please provide 'idMap' configuration. See [-h] for available options.`);
}
}
const DefaultLimitsConfig = {
maxRequestBlockCount: 32,
maxFractionalBoxVolume: 1024,
maxOutputSizeInVoxelCountByPrecisionLevel: [
0.5 * 1024 * 1024, // ~ 80*80*80
1 * 1024 * 1024,
2 * 1024 * 1024,
4 * 1024 * 1024,
8 * 1024 * 1024,
16 * 1024 * 1024, // ~ 256*256*256
24 * 1024 * 1024
]
};
export const LimitsConfig = { ...DefaultLimitsConfig };
function setLimitsConfig(config) {
for (const k of ObjectKeys(LimitsConfig)) {
if (config[k] !== void 0)
LimitsConfig[k] = config[k];
}
}
function setConfig(config) {
setServerConfig(config);
setLimitsConfig(config);
}
const ServerConfigTemplate = {
...DefaultServerConfig,
idMap: [
['x-ray', './path-to-xray-data/${id.substr(1, 2)}/${id}.mdb'],
['em', './path-to-em-data/emd-${id}.mdb']
],
...DefaultLimitsConfig
};
export function configureServer() {
const parser = new argparse.ArgumentParser({
// version: VOLUME_SERVER_VERSION,
add_help: true,
description: VOLUME_SERVER_HEADER
});
addJsonConfigArgs(parser);
addServerArgs(parser);
addLimitsArgs(parser);
const config = parser.parse_args();
if (!!config.cfgTemplate) {
console.log(JSON.stringify(ServerConfigTemplate, null, 2));
process.exit(0);
}
try {
setConfig(config); // sets the config for global use
if (config.cfg) {
const cfg = JSON.parse(fs.readFileSync(config.cfg, 'utf8'));
setConfig(cfg);
}
if (config.printCfg) {
console.log(JSON.stringify({ ...ServerConfig, ...LimitsConfig }, null, 2));
process.exit(0);
}
validateServerConfig();
}
catch (e) {
console.error('' + e);
process.exit(1);
}
}
export function configureLocal() {
const parser = new argparse.ArgumentParser({
// version: VOLUME_SERVER_VERSION,
add_help: true,
description: VOLUME_SERVER_HEADER
});
parser.add_argument('--jobs', { help: `Path to a JSON file with job specification.`, required: false });
parser.add_argument('--jobsTemplate', { help: 'Print example template for jobs.json and exit.', required: false, action: 'store_true' });
addJsonConfigArgs(parser);
addLimitsArgs(parser);
const config = parser.parse_args();
if (config.cfgTemplate) {
console.log(JSON.stringify(DefaultLimitsConfig, null, 2));
process.exit(0);
}
try {
setLimitsConfig(config); // sets the config for global use
if (config.cfg) {
const cfg = JSON.parse(fs.readFileSync(config.cfg, 'utf8'));
setLimitsConfig(cfg);
}
if (config.printCfg) {
console.log(JSON.stringify(LimitsConfig, null, 2));
process.exit(0);
}
return config;
}
catch (e) {
console.error('' + e);
process.exit(1);
}
}