@shapediver/viewer.session-engine.session-engine 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import { HttpClient, HttpResponse, PerformanceEvaluator, UuidGenerator, SystemIn
4
4
  import { OutputDelayException } from './OutputDelayException'
5
5
  import { OutputLoader } from './OutputLoader'
6
6
  import { SessionTreeNode } from './SessionTreeNode'
7
- import { ISessionEngine, PARAMETER_TYPE } from '../interfaces/ISessionEngine'
7
+ import { ISessionEngine, ISettingsSections, PARAMETER_TYPE } from '../interfaces/ISessionEngine'
8
8
  import { SessionData } from './SessionData'
9
9
  import { create, ShapeDiverError as ShapeDiverBackendError, ShapeDiverResponseErrorType, ShapeDiverRequestGltfUploadQueryConversion, ShapeDiverResponseDto, ShapeDiverResponseError, ShapeDiverResponseExport, ShapeDiverResponseExportDefinitionType, ShapeDiverResponseOutput, ShapeDiverResponseParameter, ShapeDiverSdk, ShapeDiverSdkConfigType, ShapeDiverResponseModelComputationStatus } from '@shapediver/sdk.geometry-api-sdk-v2'
10
10
  import { AxiosRequestConfig } from 'axios'
@@ -154,8 +154,8 @@ export class SessionEngine implements ISessionEngine {
154
154
  }
155
155
 
156
156
  public set excludeViewports(value: string[]) {
157
- this._excludeViewports = value;
158
- this._node.excludeViewports = value;
157
+ this._excludeViewports = JSON.parse(JSON.stringify(value));
158
+ this._node.excludeViewports = JSON.parse(JSON.stringify(value));
159
159
  }
160
160
 
161
161
  public get exports(): { [key: string]: IExport; } {
@@ -226,13 +226,7 @@ export class SessionEngine implements ISessionEngine {
226
226
 
227
227
  // #region Public Methods (22)
228
228
 
229
- public applySettings(response: ShapeDiverResponseDto, sections?: {
230
- session?: {
231
- parameter?: { displayname?: boolean | undefined; order?: boolean | undefined; hidden?: boolean | undefined; value?: boolean | undefined } | undefined;
232
- export?: { displayname?: boolean | undefined; order?: boolean | undefined; hidden?: boolean | undefined } | undefined
233
- } | undefined;
234
- viewport?: { ar?: boolean | undefined; scene?: boolean | undefined; camera?: boolean | undefined; light?: boolean | undefined; environment?: boolean | undefined; general?: boolean | undefined } | undefined
235
- }) {
229
+ public applySettings(response: ShapeDiverResponseDto, sections?: ISettingsSections) {
236
230
  try {
237
231
  sections = sections || {};
238
232
  if (sections.session === undefined) {
@@ -252,15 +246,15 @@ export class SessionEngine implements ISessionEngine {
252
246
  if ((<ShapeDiverResponseDto>response).viewer !== undefined) {
253
247
  config = (<ShapeDiverResponseDto>response).viewer!.config;
254
248
  } else {
255
- const error = new ShapeDiverViewerSettingsError('Api.applySettings: No config object available.');
256
- throw this._logger.handleError(LOGGING_TOPIC.SETTINGS, 'Api.applySettings', error);
249
+ const error = new ShapeDiverViewerSettingsError('Session.applySettings: No config object available.');
250
+ throw this._logger.handleError(LOGGING_TOPIC.SETTINGS, 'Session.applySettings', error);
257
251
  }
258
252
 
259
253
  try {
260
254
  validate(config)
261
255
  } catch (e) {
262
- const error = new ShapeDiverViewerSettingsError('Api.applySettings: Was not able to validate config object.');
263
- throw this._logger.handleError(LOGGING_TOPIC.SETTINGS, 'Api.applySettings', error);
256
+ const error = new ShapeDiverViewerSettingsError('Session.applySettings: Was not able to validate config object.');
257
+ throw this._logger.handleError(LOGGING_TOPIC.SETTINGS, 'Session.applySettings', error);
264
258
  }
265
259
 
266
260
  const settings = <ISettingsV3_1>convert(config, '3.1');
@@ -355,7 +349,7 @@ export class SessionEngine implements ISessionEngine {
355
349
 
356
350
  } catch (e) {
357
351
  if (e instanceof ShapeDiverViewerError || e instanceof ShapeDiverBackendError) throw e;
358
- throw this._logger.handleError(LOGGING_TOPIC.GENERAL, 'Api.applySettings', e);
352
+ throw this._logger.handleError(LOGGING_TOPIC.GENERAL, 'Session.applySettings', e);
359
353
  }
360
354
  }
361
355
 
@@ -526,7 +520,7 @@ export class SessionEngine implements ISessionEngine {
526
520
 
527
521
  this._warningCreator();
528
522
 
529
- this.node.excludeViewports = this._excludeViewports;
523
+ this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
530
524
 
531
525
  for (let r in this._stateEngine.renderingEngines)
532
526
  if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
@@ -553,9 +547,23 @@ export class SessionEngine implements ISessionEngine {
553
547
  }
554
548
  }
555
549
 
556
- public customizeParallel(parameterValues: { [key: string]: string }, force: boolean): Promise<ITreeNode> {
557
- // https://shapediver.atlassian.net/browse/SS-5408
558
- throw new Error('Method not implemented.')
550
+ public async customizeParallel(parameterValues: { [key: string]: string }): Promise<ITreeNode> {
551
+ try {
552
+ const parameterSet: {
553
+ [key: string]: string
554
+ } = {};
555
+
556
+ // create a set of the current validated parameter values
557
+ for (const parameterId in this.parameters)
558
+ parameterSet[parameterId] = parameterValues[parameterId] !== undefined ? (' ' + parameterValues[parameterId]).slice(1) : this.parameters[parameterId].stringify()
559
+
560
+ const newNode = await this.customizeSession(parameterSet, () => false, true);
561
+ newNode.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
562
+ return newNode;
563
+ } catch (e) {
564
+ if (e instanceof ShapeDiverViewerError || e instanceof ShapeDiverBackendError) throw e;
565
+ throw this._logger.handleError(LOGGING_TOPIC.SESSION, `Session(${this.id}).customize`, e);
566
+ }
559
567
  }
560
568
 
561
569
  public async goBack(): Promise<ITreeNode> {
@@ -616,7 +624,12 @@ export class SessionEngine implements ISessionEngine {
616
624
 
617
625
  try {
618
626
  this._performanceEvaluator.startSection('sessionResponse');
619
- this._responseDto = await this._sdk.session.init(this._ticket, parameterValues);
627
+
628
+ const parameterSet: { [key: string]: string } = {};
629
+ for (const parameterId in parameterValues)
630
+ parameterSet[parameterId] = (' ' + parameterValues[parameterId]).slice(1);
631
+
632
+ this._responseDto = await this._sdk.session.init(this._ticket, parameterSet);
620
633
  this._performanceEvaluator.endSection('sessionResponse');
621
634
 
622
635
  this._viewerSettings = this._responseDto.viewer?.config;
@@ -634,7 +647,7 @@ export class SessionEngine implements ISessionEngine {
634
647
  if (!this._modelId)
635
648
  throw new ShapeDiverViewerSessionError(`Session.init: Initialization of session failed. ResponseDto did not have a model.id.`)
636
649
 
637
- this.updateResponseDto(this._responseDto, parameterValues);
650
+ this.updateResponseDto(this._responseDto, parameterSet);
638
651
  this._initialized = true;
639
652
  } catch (e) {
640
653
  await this.handleError(LOGGING_TOPIC.SESSION, 'Session.init', e, retry);
@@ -642,6 +655,63 @@ export class SessionEngine implements ISessionEngine {
642
655
  }
643
656
  }
644
657
 
658
+
659
+ /**
660
+ * Load the outputs and return the scene graph node of the result.
661
+ * In case the outputs have a delay property, another customization request with the parameter set is sent.
662
+ *
663
+ * @param parameters the parameter set to update the session
664
+ * @param outputs the outputs to load
665
+ * @returns promise with a scene graph node
666
+ */
667
+ public async loadOutputsParallel(responseDto: ShapeDiverResponseDto, cancelRequest: () => boolean = () => false, retry = false): Promise<ISessionTreeNode> {
668
+ this.checkAvailability();
669
+
670
+ let outputs: {
671
+ [key: string]: IOutput;
672
+ } = {}
673
+ let outputsFreeze: {
674
+ [key: string]: boolean;
675
+ } = {}
676
+
677
+ for (let outputId in responseDto.outputs) {
678
+ responseDto.outputs[outputId].id = outputId;
679
+ if (this.outputsFreeze[outputId] === undefined) outputsFreeze[outputId] = false;
680
+ outputs[outputId] = new Output(<ShapeDiverResponseOutput>responseDto.outputs[outputId], this);
681
+ }
682
+
683
+ try {
684
+ const node = await this._outputLoader.loadOutputs(this._responseDto!.model?.name || 'model', outputs, outputsFreeze);
685
+ node.data.push(new SessionData(responseDto));
686
+ return node;
687
+ }
688
+ catch (e) {
689
+ if (e instanceof OutputDelayException) {
690
+ await this.timeout(e.delay);
691
+ } else {
692
+ await this.handleError(LOGGING_TOPIC.SESSION, 'Session.loadOutputsParallel', e, retry);
693
+ if (cancelRequest()) return new SessionTreeNode();
694
+ return await this.loadOutputsParallel(responseDto, cancelRequest, true);
695
+ }
696
+
697
+ if (cancelRequest()) return new SessionTreeNode();
698
+ let outputMapping: { [key: string]: string } = {};
699
+ for (let output in outputs)
700
+ outputMapping[output] = outputs[output].version;
701
+
702
+ try {
703
+ const responseDto = await this._sdk.output.getCache(this._sessionId!, outputMapping);
704
+ if (cancelRequest()) return new SessionTreeNode();
705
+ this.updateResponseDto(responseDto);
706
+ return await this.loadOutputsParallel(responseDto, cancelRequest);
707
+ } catch (e) {
708
+ await this.handleError(LOGGING_TOPIC.SESSION, 'Session.loadOutputsParallel', e, retry);
709
+ if (cancelRequest()) return new SessionTreeNode();
710
+ return await this.loadOutputsParallel(responseDto, cancelRequest, true);
711
+ }
712
+ }
713
+ }
714
+
645
715
  /**
646
716
  * Load the outputs and return the scene graph node of the result.
647
717
  * In case the outputs have a delay property, another customization request with the parameter set is sent.
@@ -656,7 +726,7 @@ export class SessionEngine implements ISessionEngine {
656
726
  const o = Object.assign({}, this._outputs);
657
727
  const of = Object.assign({}, this._outputsFreeze);
658
728
  try {
659
- const node = await this._outputLoader.loadOutputs(this._responseDto!, o, of);
729
+ const node = await this._outputLoader.loadOutputs(this._responseDto!.model?.name || 'model', o, of);
660
730
  node.data.push(new SessionData(this._responseDto!));
661
731
 
662
732
  if (cancelRequest()) return node;
@@ -665,7 +735,7 @@ export class SessionEngine implements ISessionEngine {
665
735
  this._node = node;
666
736
  if (this._automaticSceneUpdate) this._sceneTree.addNode(this._node);
667
737
 
668
- this.node.excludeViewports = this._excludeViewports;
738
+ this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
669
739
 
670
740
  return node;
671
741
  }
@@ -699,7 +769,10 @@ export class SessionEngine implements ISessionEngine {
699
769
  public async requestExport(exportId: string, parameters: { [key: string]: string }, maxWaitTime: number, retry = false): Promise<ShapeDiverResponseExport> {
700
770
  this.checkAvailability('export');
701
771
  try {
702
- const responseDto = await this._sdk.utils.submitAndWaitForExport(this._sdk, this._sessionId!, { exports: { id: exportId }, parameters }, maxWaitTime)
772
+ const parameterSet: { [key: string]: string } = {};
773
+ for (const parameterId in parameters)
774
+ parameterSet[parameterId] = (' ' + parameters[parameterId]).slice(1);
775
+ const responseDto = await this._sdk.utils.submitAndWaitForExport(this._sdk, this._sessionId!, { exports: { id: exportId }, parameters: parameterSet }, maxWaitTime)
703
776
  this.updateResponseDto(responseDto);
704
777
  return this.exports[exportId];
705
778
  } catch (e) {
@@ -708,6 +781,33 @@ export class SessionEngine implements ISessionEngine {
708
781
  }
709
782
  }
710
783
 
784
+ public resetSettings(sections?: ISettingsSections): void {
785
+ if (!this._responseDto) {
786
+ const error = new ShapeDiverViewerSessionError(`Session.resetSettings: responseDto not available.`);
787
+ throw this._logger.handleError(LOGGING_TOPIC.SESSION, 'Session.resetSettings', error);
788
+ }
789
+ try {
790
+ sections = sections || {};
791
+ if (sections.session === undefined) {
792
+ sections.session = {
793
+ parameter: { displayname: true, order: true, hidden: true },
794
+ export: { displayname: true, order: true, hidden: true }
795
+ };
796
+ }
797
+ if (sections.session.parameter === undefined)
798
+ sections.session.parameter = { displayname: true, order: true, hidden: true, value: true };
799
+ if (sections.session.export === undefined)
800
+ sections.session.export = { displayname: true, order: true, hidden: true };
801
+ if (sections.viewport === undefined)
802
+ sections.viewport = { ar: true, scene: true, camera: true, light: true, environment: true, general: true };
803
+
804
+ return this.applySettings(this._responseDto, sections);
805
+ } catch (e) {
806
+ if (e instanceof ShapeDiverViewerError || e instanceof ShapeDiverBackendError) throw e;
807
+ throw this._logger.handleError(LOGGING_TOPIC.GENERAL, 'Session.resetSettings', e);
808
+ }
809
+ }
810
+
711
811
  public async saveDefaultParameterValues(): Promise<boolean> {
712
812
  try {
713
813
  this._logger.debugLow(LOGGING_TOPIC.SESSION, `Session(${this.id}).saveDefaultParameters: Saving default parameters.`);
@@ -944,7 +1044,7 @@ export class SessionEngine implements ISessionEngine {
944
1044
  this.exports[exportId].updateExport();
945
1045
 
946
1046
  this._warningCreator();
947
- this.node.excludeViewports = this.excludeViewports;
1047
+ this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
948
1048
 
949
1049
  for (let r in this._stateEngine.renderingEngines)
950
1050
  if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
@@ -1100,19 +1200,19 @@ export class SessionEngine implements ISessionEngine {
1100
1200
  return this.customizeSession(this._parameterValues, cancelRequest);
1101
1201
  }
1102
1202
 
1103
- private async customizeSession(parameters: { [key: string]: string }, cancelRequest: () => boolean, retry = false): Promise<ISessionTreeNode> {
1203
+ private async customizeSession(parameters: { [key: string]: string }, cancelRequest: () => boolean, parallel = false, retry = false): Promise<ISessionTreeNode> {
1104
1204
  this.checkAvailability('customize');
1105
1205
  try {
1106
1206
  this._performanceEvaluator.startSection('sessionResponse');
1107
1207
  const responseDto = await this._sdk.utils.submitAndWaitForCustomization(this._sdk, this._sessionId!, parameters);
1108
1208
  this._performanceEvaluator.endSection('sessionResponse');
1109
1209
  if (cancelRequest()) return new SessionTreeNode();
1110
- this.updateResponseDto(responseDto);
1111
- return this.loadOutputs(cancelRequest);
1210
+ if (parallel === false) this.updateResponseDto(responseDto);
1211
+ return parallel === false ? this.loadOutputs(cancelRequest) : this.loadOutputsParallel(responseDto, cancelRequest);
1112
1212
  } catch (e) {
1113
1213
  await this.handleError(LOGGING_TOPIC.SESSION, 'Session.customizeSession', e, retry);
1114
1214
  if (cancelRequest()) return new SessionTreeNode();
1115
- return await this.customizeSession(parameters, cancelRequest, true);
1215
+ return await this.customizeSession(parameters, cancelRequest, parallel, true);
1116
1216
  }
1117
1217
  }
1118
1218
 
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SessionEngine } from './implementation/SessionEngine'
2
- import { ISessionEngine, PARAMETER_TYPE, PARAMETER_VISUALIZATION } from './interfaces/ISessionEngine'
2
+ import { ISessionEngine, ISettingsSections, PARAMETER_TYPE, PARAMETER_VISUALIZATION } from './interfaces/ISessionEngine'
3
3
  import { SessionOutputData } from './implementation/SessionOutputData'
4
4
  import { SessionData } from './implementation/SessionData'
5
5
  import { ISessionData } from './interfaces/ISessionData'
@@ -14,7 +14,7 @@ import { IOutput, ShapeDiverResponseOutputChunk, ShapeDiverResponseOutputContent
14
14
  import { IParameter } from './interfaces/dto/IParameter'
15
15
 
16
16
  export {
17
- ISessionData, SessionData, ISessionOutputData, SessionOutputData
17
+ ISessionData, SessionData, ISessionOutputData, SessionOutputData, ISettingsSections
18
18
  }
19
19
 
20
20
  export {
@@ -59,6 +59,44 @@ export enum PARAMETER_VISUALIZATION {
59
59
  DIAL = 'dial',
60
60
  TEXT = 'text'
61
61
  }
62
+
63
+ export interface ISettingsSections {
64
+ session?: {
65
+ parameter?: {
66
+ /** Option to update the displayname of the parameters (default: false) */
67
+ displayname?: boolean,
68
+ /** Option to update the order of the parameters (default: false) */
69
+ order?: boolean,
70
+ /** Option to update the hidden state of the parameters (default: false) */
71
+ hidden?: boolean,
72
+ /** Option to update the value of the parameters (default: false) */
73
+ value?: boolean
74
+ },
75
+ export?: {
76
+ /** Option to update the displayname of the exports (default: false) */
77
+ displayname?: boolean,
78
+ /** Option to update the order of the exports (default: false) */
79
+ order?: boolean,
80
+ /** Option to update the hidden state of the exports (default: false) */
81
+ hidden?: boolean
82
+ }
83
+ },
84
+ viewport?: {
85
+ /** Option to update the ar settings (default: false) */
86
+ ar?: boolean,
87
+ /** Option to update the scene settings (default: false) */
88
+ scene?: boolean,
89
+ /** Option to update the camera settings (default: false) */
90
+ camera?: boolean,
91
+ /** Option to update the light settings (default: false) */
92
+ light?: boolean,
93
+ /** Option to update the environment settings (default: false) */
94
+ environment?: boolean
95
+ /** Option to update the general settings (default: false) */
96
+ general?: boolean
97
+ }
98
+ };
99
+
62
100
  export interface ISessionEngine {
63
101
  // #region Properties (11)
64
102
 
@@ -79,39 +117,19 @@ export interface ISessionEngine {
79
117
 
80
118
  // #region Public Methods (18)
81
119
 
82
- applySettings(response: ShapeDiverResponseDto, sections?: {
83
- session?: {
84
- parameter?: {
85
- displayname?: boolean,
86
- order?: boolean,
87
- hidden?: boolean,
88
- value?: boolean
89
- },
90
- export?: {
91
- displayname?: boolean,
92
- order?: boolean,
93
- hidden?: boolean
94
- }
95
- },
96
- viewport?: {
97
- scene?: boolean,
98
- camera?: boolean,
99
- light?: boolean,
100
- environment?: boolean
101
- }
102
- }): void;
120
+ applySettings(response: ShapeDiverResponseDto, sections?: ISettingsSections): void;
103
121
  canGoBack(): boolean;
104
122
  canGoForward(): boolean;
105
123
  close(): Promise<void>;
106
124
  customize(force: boolean): Promise<ITreeNode>;
107
- customizeParallel(parameterValues: { [key: string]: string }, force: boolean): Promise<ITreeNode>;
125
+ customizeParallel(parameterValues: { [key: string]: string }): Promise<ITreeNode>;
108
126
  goBack(): Promise<ITreeNode>;
109
127
  goForward(): Promise<ITreeNode>;
110
- init(parameterValues?: {
111
- [key: string]: string;
112
- }): Promise<void>;
128
+ init(parameterValues?: { [key: string]: string; }): Promise<void>;
113
129
  loadOutputs(cancelRequest: () => boolean): Promise<ITreeNode>;
130
+ loadOutputsParallel(responseDto: ShapeDiverResponseDto, cancelRequest: () => boolean): Promise<ITreeNode>;
114
131
  requestExport(exportId: string, parameters: { [key: string]: string }, maxWaitTime: number): Promise<ShapeDiverResponseExport>;
132
+ resetSettings(sections?: ISettingsSections): void;
115
133
  saveDefaultParameterValues(): Promise<boolean>;
116
134
  saveSettings(viewportId?: string): Promise<boolean>;
117
135
  saveUiProperties(): Promise<boolean>;