api.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer)
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. import * as File from '../common/file'
  9. import execute from './query/execute'
  10. import * as Data from './query/data-model'
  11. import * as Logger from './utils/logger'
  12. import * as DataFormat from '../common/data-format'
  13. import ServerConfig from '../server-config'
  14. export function getOutputFilename(source: string, id: string, { asBinary, box, detail, forcedSamplingLevel }: Data.QueryParams) {
  15. function n(s: string) { return (s || '').replace(/[ \n\t]/g, '').toLowerCase() }
  16. function r(v: number) { return Math.round(10 * v) / 10; }
  17. const det = forcedSamplingLevel !== void 0
  18. ? `l${forcedSamplingLevel}`
  19. : `d${Math.min(Math.max(0, detail | 0), ServerConfig.limits.maxOutputSizeInVoxelCountByPrecisionLevel.length - 1)}`;
  20. const boxInfo = box.kind === 'Cell'
  21. ? 'cell'
  22. : `${box.kind === 'Cartesian' ? 'cartn' : 'frac'}_${r(box.a[0])}_${r(box.a[1])}_${r(box.a[2])}_${r(box.b[0])}_${r(box.b[1])}_${r(box.b[2])}`;
  23. return `${n(source)}_${n(id)}-${boxInfo}_${det}.${asBinary ? 'bcif' : 'cif'}`;
  24. }
  25. /** Reads the header and includes information about available detail levels */
  26. export async function getHeaderJson(filename: string | undefined, sourceId: string) {
  27. Logger.logPlain('Header', sourceId);
  28. try {
  29. if (!filename || !File.exists(filename)) {
  30. Logger.errorPlain(`Header ${sourceId}`, 'File not found.');
  31. return void 0;
  32. }
  33. const header = { ...await readHeader(filename, sourceId) } as DataFormat.Header;
  34. const { sampleCount } = header!.sampling[0];
  35. const maxVoxelCount = sampleCount[0] * sampleCount[1] * sampleCount[2];
  36. const precisions = ServerConfig.limits.maxOutputSizeInVoxelCountByPrecisionLevel
  37. .map((maxVoxels, precision) => ({ precision, maxVoxels }));
  38. const availablePrecisions = [];
  39. for (const p of precisions) {
  40. availablePrecisions.push(p);
  41. if (p.maxVoxels > maxVoxelCount) break;
  42. }
  43. (header as any).availablePrecisions = availablePrecisions;
  44. (header as any).isAvailable = true;
  45. return JSON.stringify(header, null, 2);
  46. } catch (e) {
  47. Logger.errorPlain(`Header ${sourceId}`, e);
  48. return void 0;
  49. }
  50. }
  51. export async function queryBox(params: Data.QueryParams, outputProvider: () => Data.QueryOutputStream) {
  52. return await execute(params, outputProvider);
  53. }
  54. async function readHeader(filename: string | undefined, sourceId: string) {
  55. let file: number | undefined = void 0;
  56. try {
  57. if (!filename) return void 0;
  58. file = await File.openRead(filename);
  59. const header = await DataFormat.readHeader(file);
  60. return header.header;
  61. } catch (e) {
  62. Logger.errorPlain(`Info ${sourceId}`, e);
  63. return void 0;
  64. } finally {
  65. File.close(file);
  66. }
  67. }