@shapediver/viewer.session-engine.session-engine 2.11.0 → 2.12.1
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.
- package/dist/implementation/OutputLoader.d.ts +4 -1
- package/dist/implementation/OutputLoader.d.ts.map +1 -1
- package/dist/implementation/OutputLoader.js +11 -4
- package/dist/implementation/OutputLoader.js.map +1 -1
- package/dist/implementation/SessionEngine.d.ts +11 -1
- package/dist/implementation/SessionEngine.d.ts.map +1 -1
- package/dist/implementation/SessionEngine.js +245 -126
- package/dist/implementation/SessionEngine.js.map +1 -1
- package/dist/implementation/dto/Output.d.ts +1 -1
- package/dist/implementation/dto/Output.d.ts.map +1 -1
- package/dist/implementation/dto/Output.js +4 -2
- package/dist/implementation/dto/Output.js.map +1 -1
- package/dist/interfaces/ISessionEngine.d.ts +7 -2
- package/dist/interfaces/ISessionEngine.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/implementation/OutputLoader.ts +16 -5
- package/src/implementation/SessionEngine.ts +271 -141
- package/src/implementation/dto/Output.ts +2 -2
- package/src/interfaces/ISessionEngine.ts +3 -2
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
latestVersion,
|
|
5
5
|
validate,
|
|
6
6
|
versions
|
|
7
|
-
|
|
7
|
+
} from '@shapediver/viewer.settings';
|
|
8
8
|
import {
|
|
9
9
|
create,
|
|
10
10
|
isGBResponseError,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
ShapeDiverResponseOutput,
|
|
22
22
|
ShapeDiverSdk,
|
|
23
23
|
ShapeDiverSdkConfigType
|
|
24
|
-
|
|
24
|
+
} from '@shapediver/sdk.geometry-api-sdk-v2';
|
|
25
25
|
import {
|
|
26
26
|
EventEngine,
|
|
27
27
|
EVENTTYPE,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
StateEngine,
|
|
37
37
|
SystemInfo,
|
|
38
38
|
UuidGenerator
|
|
39
|
-
|
|
39
|
+
} from '@shapediver/viewer.shared.services';
|
|
40
40
|
import { Export } from './dto/Export';
|
|
41
41
|
import { FileParameter } from './dto/FileParameter';
|
|
42
42
|
import { IExport } from '../interfaces/dto/IExport';
|
|
@@ -45,13 +45,13 @@ import { IOutput } from '../interfaces/dto/IOutput';
|
|
|
45
45
|
import { IParameter } from '../interfaces/dto/IParameter';
|
|
46
46
|
import { ISessionEngine, ISettingsSections, PARAMETER_TYPE } from '../interfaces/ISessionEngine';
|
|
47
47
|
import { ISessionTreeNode } from '../interfaces/ISessionTreeNode';
|
|
48
|
-
import { ITaskEvent, TASK_TYPE } from '@shapediver/viewer.shared.types';
|
|
48
|
+
import { IOutputEvent, ITaskEvent, TASK_TYPE } from '@shapediver/viewer.shared.types';
|
|
49
49
|
import {
|
|
50
50
|
ITree,
|
|
51
51
|
ITreeNode,
|
|
52
52
|
Tree,
|
|
53
53
|
TreeNode
|
|
54
|
-
|
|
54
|
+
} from '@shapediver/viewer.shared.node-tree';
|
|
55
55
|
import { Output } from './dto/Output';
|
|
56
56
|
import { OutputDelayException } from './OutputDelayException';
|
|
57
57
|
import { OutputLoader, OutputLoaderTaskEventInfo } from './OutputLoader';
|
|
@@ -62,7 +62,7 @@ import { vec3 } from 'gl-matrix';
|
|
|
62
62
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
63
63
|
|
|
64
64
|
export class SessionEngine implements ISessionEngine {
|
|
65
|
-
// #region Properties (
|
|
65
|
+
// #region Properties (44)
|
|
66
66
|
|
|
67
67
|
private readonly _eventEngine = EventEngine.instance;
|
|
68
68
|
private readonly _exports: { [key: string]: IExport; } = {};
|
|
@@ -84,7 +84,8 @@ export class SessionEngine implements ISessionEngine {
|
|
|
84
84
|
private readonly _ticket?: string;
|
|
85
85
|
private readonly _uuidGenerator = UuidGenerator.instance;
|
|
86
86
|
|
|
87
|
-
#
|
|
87
|
+
#customizationBusyModes: string[] = [];
|
|
88
|
+
#customizationProcess?: string;
|
|
88
89
|
#parameterHistory: {
|
|
89
90
|
[key: string]: {
|
|
90
91
|
value: unknown,
|
|
@@ -126,7 +127,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
126
127
|
private _viewerSettingsVersion: string = latestVersion;
|
|
127
128
|
private _viewerSettingsVersionBackend: string = latestVersion;
|
|
128
129
|
|
|
129
|
-
// #endregion Properties (
|
|
130
|
+
// #endregion Properties (44)
|
|
130
131
|
|
|
131
132
|
// #region Constructors (1)
|
|
132
133
|
|
|
@@ -267,7 +268,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
267
268
|
|
|
268
269
|
// #endregion Public Accessors (25)
|
|
269
270
|
|
|
270
|
-
// #region Public Methods (
|
|
271
|
+
// #region Public Methods (27)
|
|
271
272
|
|
|
272
273
|
public applySettings(response: ShapeDiverResponseDto, sections?: ISettingsSections) {
|
|
273
274
|
sections = sections || {};
|
|
@@ -317,7 +318,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
317
318
|
if (sections.session.parameter.hidden) this.parameters[p].hidden = settings.session[p].hidden || false;
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
if (response.parameters && response.parameters[p]) {
|
|
321
|
+
if (response.parameters && response.parameters[p] && !((this.parameters[p] instanceof FileParameter) || this.parameters[p].type.startsWith('s'))) {
|
|
321
322
|
if (sections.session.parameter.value) this.parameters[p].value = response.parameters[p].defval !== undefined ? response.parameters[p].defval : this.parameters[p].value;
|
|
322
323
|
}
|
|
323
324
|
}
|
|
@@ -409,6 +410,21 @@ export class SessionEngine implements ISessionEngine {
|
|
|
409
410
|
return this.#parameterHistoryForward.length > 0;
|
|
410
411
|
}
|
|
411
412
|
|
|
413
|
+
public cancelCustomization() {
|
|
414
|
+
if (this.#customizationProcess)
|
|
415
|
+
this.removeBusyMode(this.#customizationProcess);
|
|
416
|
+
|
|
417
|
+
for (const busyId of this.#customizationBusyModes) {
|
|
418
|
+
for (const r in this._stateEngine.renderingEngines) {
|
|
419
|
+
if (this._stateEngine.renderingEngines[r].busy.includes(busyId))
|
|
420
|
+
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(busyId), 1);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
this.#customizationBusyModes = [];
|
|
425
|
+
this.#customizationProcess = undefined;
|
|
426
|
+
}
|
|
427
|
+
|
|
412
428
|
public async close(retry = false): Promise<void> {
|
|
413
429
|
this.checkAvailability('close');
|
|
414
430
|
|
|
@@ -452,9 +468,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
452
468
|
|
|
453
469
|
this._logger.debugLow(`Session(${this.id}).customize: Customizing session.`);
|
|
454
470
|
|
|
455
|
-
|
|
456
|
-
if (!this.excludeViewports.includes(r))
|
|
457
|
-
this._stateEngine.renderingEngines[r].busy.push(customizationId);
|
|
471
|
+
this.addBusyMode(customizationId);
|
|
458
472
|
|
|
459
473
|
const eventFileUpload: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 0.1, data: { sessionId: this.id }, status: 'Uploading file parameters' };
|
|
460
474
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventFileUpload);
|
|
@@ -466,51 +480,14 @@ export class SessionEngine implements ISessionEngine {
|
|
|
466
480
|
fileParameterIds[parameterId] = await (<IFileParameter>this.parameters[parameterId]).upload();
|
|
467
481
|
|
|
468
482
|
// OPTION TO SKIP - PART 1a
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
472
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
473
|
-
|
|
474
|
-
this._logger.debug(`Session(${this.id}).customize: Session customization was exceeded by other customization request.`);
|
|
475
|
-
|
|
476
|
-
const eventCancel1a: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session customization was exceeded by other customization request' };
|
|
477
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel1a);
|
|
478
|
-
return new SessionTreeNode();
|
|
479
|
-
} else if (this._closed === true) {
|
|
480
|
-
for (const r in this._stateEngine.renderingEngines)
|
|
481
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
482
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
483
|
-
|
|
484
|
-
this._logger.debug(`Session(${this.id}).customize: Session was closed during customization request.`);
|
|
485
|
-
|
|
486
|
-
const eventCancel1a: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session was closed during customization request' };
|
|
487
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel1a);
|
|
488
|
-
return new SessionTreeNode();
|
|
489
|
-
}
|
|
483
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, TASK_TYPE.SESSION_CUSTOMIZATION, 1, { sessionId: this.id });
|
|
484
|
+
if (cancelResult) return cancelResult;
|
|
490
485
|
}
|
|
491
486
|
}
|
|
492
487
|
|
|
493
488
|
// OPTION TO SKIP - PART 1b
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
497
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
498
|
-
|
|
499
|
-
const eventCancel1b: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session customization was exceeded by other customization request' };
|
|
500
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel1b);
|
|
501
|
-
this._logger.debug(`Session(${this.id}).customize: Session customization was exceeded by other customization request.`);
|
|
502
|
-
return new SessionTreeNode();
|
|
503
|
-
} else if (this._closed === true) {
|
|
504
|
-
for (const r in this._stateEngine.renderingEngines)
|
|
505
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
506
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
507
|
-
|
|
508
|
-
this._logger.debug(`Session(${this.id}).customize: Session was closed during customization request.`);
|
|
509
|
-
|
|
510
|
-
const eventCancel1b: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session was closed during customization request' };
|
|
511
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel1b);
|
|
512
|
-
return new SessionTreeNode();
|
|
513
|
-
}
|
|
489
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, TASK_TYPE.SESSION_CUSTOMIZATION, 1, { sessionId: this.id });
|
|
490
|
+
if (cancelResult) return cancelResult;
|
|
514
491
|
|
|
515
492
|
// assign the uploaded parameters
|
|
516
493
|
for (const parameterId in fileParameterIds)
|
|
@@ -539,6 +516,8 @@ export class SessionEngine implements ISessionEngine {
|
|
|
539
516
|
const eventRequest: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 0.1, data: { sessionId: this.id }, status: 'Sending customization request' };
|
|
540
517
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventRequest);
|
|
541
518
|
|
|
519
|
+
const oldOutputVersions = this._outputLoader.getCurrentOutputVersions();
|
|
520
|
+
|
|
542
521
|
const newNode = await this.customizeInternal(() => this.#customizationProcess !== customizationId, {
|
|
543
522
|
eventId,
|
|
544
523
|
type: TASK_TYPE.SESSION_CUSTOMIZATION,
|
|
@@ -549,29 +528,32 @@ export class SessionEngine implements ISessionEngine {
|
|
|
549
528
|
data: { sessionId: this.id }
|
|
550
529
|
});
|
|
551
530
|
|
|
531
|
+
// OPTION TO SKIP - PART 2
|
|
532
|
+
const cancelResult2 = this.cancelProcess(customizationId, eventId, TASK_TYPE.SESSION_CUSTOMIZATION, 1, { sessionId: this.id });
|
|
533
|
+
if (cancelResult2) return cancelResult2;
|
|
534
|
+
|
|
535
|
+
const newOutputVersions = this._outputLoader.getCurrentOutputVersions();
|
|
536
|
+
|
|
552
537
|
const eventSceneUpdate: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 0.9, data: { sessionId: this.id }, status: 'Updating scene' };
|
|
553
538
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventSceneUpdate);
|
|
554
539
|
|
|
555
|
-
//
|
|
556
|
-
if (
|
|
557
|
-
for (const
|
|
558
|
-
if (
|
|
559
|
-
this.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
568
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
540
|
+
// call the update callbacks
|
|
541
|
+
if (waitForViewportUpdate === false) {
|
|
542
|
+
for (const outputId in this.outputs) {
|
|
543
|
+
if (oldOutputVersions[outputId] !== newOutputVersions[outputId]) {
|
|
544
|
+
this._eventEngine.emitEvent(EVENTTYPE.OUTPUT.OUTPUT_UPDATED, <IOutputEvent>{
|
|
545
|
+
outputId: outputId,
|
|
546
|
+
outputVersion: newOutputVersions[outputId],
|
|
547
|
+
newNode: newNode.children.find(c => c.name === outputId)!,
|
|
548
|
+
oldNode: oldNode.children.find(c => c.name === outputId)!
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
569
552
|
|
|
570
|
-
this.
|
|
553
|
+
await this.waitForUpdateCallbacks(newOutputVersions, oldOutputVersions, newNode, oldNode);
|
|
571
554
|
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
return new SessionTreeNode();
|
|
555
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, TASK_TYPE.SESSION_CUSTOMIZATION, 1, { sessionId: this.id });
|
|
556
|
+
if (cancelResult) return cancelResult;
|
|
575
557
|
}
|
|
576
558
|
|
|
577
559
|
// if this is not a call by the goBack or goForward functions, add the parameter values to the history and delete the forward history
|
|
@@ -605,9 +587,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
605
587
|
|
|
606
588
|
this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
|
|
607
589
|
|
|
608
|
-
|
|
609
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
610
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
590
|
+
this.removeBusyMode(customizationId);
|
|
611
591
|
|
|
612
592
|
this._logger.debug(`Session(${this.id}).customize: Session customized.`);
|
|
613
593
|
|
|
@@ -617,35 +597,49 @@ export class SessionEngine implements ISessionEngine {
|
|
|
617
597
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_END, eventEnd);
|
|
618
598
|
|
|
619
599
|
// update the viewports
|
|
620
|
-
if (waitForViewportUpdate)
|
|
600
|
+
if (waitForViewportUpdate) {
|
|
621
601
|
for (const r in this._stateEngine.renderingEngines)
|
|
622
602
|
if (!this.excludeViewports.includes(this._stateEngine.renderingEngines[r].id))
|
|
623
603
|
this._stateEngine.renderingEngines[r].update(`SessionEngine(${this.id}).customize`);
|
|
624
604
|
|
|
625
|
-
|
|
626
|
-
|
|
605
|
+
for (const outputId in this.outputs) {
|
|
606
|
+
if (oldOutputVersions[outputId] !== newOutputVersions[outputId]) {
|
|
607
|
+
this._eventEngine.emitEvent(EVENTTYPE.OUTPUT.OUTPUT_UPDATED, <IOutputEvent>{
|
|
608
|
+
outputId: outputId,
|
|
609
|
+
outputVersion: newOutputVersions[outputId],
|
|
610
|
+
newNode: newNode.children.find(c => c.name === outputId)!,
|
|
611
|
+
oldNode: oldNode.children.find(c => c.name === outputId)!
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
627
615
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
616
|
+
// call the update callbacks
|
|
617
|
+
await this.waitForUpdateCallbacks(newOutputVersions, oldOutputVersions, newNode, oldNode);
|
|
618
|
+
|
|
619
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, TASK_TYPE.SESSION_CUSTOMIZATION, 1, { sessionId: this.id });
|
|
620
|
+
if (cancelResult) return cancelResult;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (!waitForViewportUpdate) {
|
|
624
|
+
setTimeout(() => {
|
|
625
|
+
for (const r in this._stateEngine.renderingEngines)
|
|
626
|
+
if (!this.excludeViewports.includes(this._stateEngine.renderingEngines[r].id))
|
|
627
|
+
this._stateEngine.renderingEngines[r].update(`SessionEngine(${this.id}).customize`);
|
|
628
|
+
}, 0);
|
|
629
|
+
}
|
|
634
630
|
|
|
635
631
|
return this.node;
|
|
636
632
|
} catch (e) {
|
|
637
633
|
const eventCancel: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session customization failed' };
|
|
638
634
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel);
|
|
639
635
|
|
|
640
|
-
|
|
641
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
642
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
636
|
+
this.removeBusyMode(customizationId);
|
|
643
637
|
|
|
644
638
|
throw this._httpClient.convertError(e);
|
|
645
639
|
}
|
|
646
640
|
}
|
|
647
641
|
|
|
648
|
-
public async customizeParallel(parameterValues: { [key: string]: string }): Promise<
|
|
642
|
+
public async customizeParallel(parameterValues: { [key: string]: string }, loadOutputs = true): Promise<ISessionTreeNode | ShapeDiverResponseDto> {
|
|
649
643
|
const eventId = this._uuidGenerator.create();
|
|
650
644
|
|
|
651
645
|
const eventStart: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 0, data: { sessionId: this.id }, status: 'Customizing session' };
|
|
@@ -659,7 +653,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
659
653
|
for (const parameterId in this.parameters)
|
|
660
654
|
parameterSet[parameterId] = parameterValues[parameterId] !== undefined ? (' ' + parameterValues[parameterId]).slice(1) : this.parameters[parameterId].stringify();
|
|
661
655
|
|
|
662
|
-
const
|
|
656
|
+
const result = await this.customizeSession(parameterSet, () => false, {
|
|
663
657
|
eventId,
|
|
664
658
|
type: TASK_TYPE.SESSION_CUSTOMIZATION,
|
|
665
659
|
progressRange: {
|
|
@@ -667,12 +661,14 @@ export class SessionEngine implements ISessionEngine {
|
|
|
667
661
|
max: 1
|
|
668
662
|
},
|
|
669
663
|
data: { sessionId: this.id }
|
|
670
|
-
}, true);
|
|
671
|
-
|
|
664
|
+
}, true, loadOutputs);
|
|
665
|
+
|
|
666
|
+
if (result instanceof SessionTreeNode)
|
|
667
|
+
result.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
|
|
672
668
|
|
|
673
669
|
const eventEnd: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'Session customized' };
|
|
674
670
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_END, eventEnd);
|
|
675
|
-
return
|
|
671
|
+
return result;
|
|
676
672
|
}
|
|
677
673
|
|
|
678
674
|
public async goBack(): Promise<ITreeNode> {
|
|
@@ -772,6 +768,63 @@ export class SessionEngine implements ISessionEngine {
|
|
|
772
768
|
}
|
|
773
769
|
}
|
|
774
770
|
|
|
771
|
+
public async loadCachedOutputsParallel(outputMapping: { [key: string]: string }, taskEventInfo?: OutputLoaderTaskEventInfo, retry = false): Promise<{ [key: string]: ITreeNode | undefined }> {
|
|
772
|
+
this.checkAvailability();
|
|
773
|
+
// if there is already task event info, use it
|
|
774
|
+
// this happens after a retry
|
|
775
|
+
const eventId = taskEventInfo ? taskEventInfo.eventId : this._uuidGenerator.create();
|
|
776
|
+
const eventType = taskEventInfo ? taskEventInfo.type : TASK_TYPE.SESSION_OUTPUTS_LOADING;
|
|
777
|
+
const eventData = taskEventInfo ? taskEventInfo.data : { sessionId: this.id };
|
|
778
|
+
|
|
779
|
+
taskEventInfo = taskEventInfo ? taskEventInfo : {
|
|
780
|
+
eventId,
|
|
781
|
+
type: eventType,
|
|
782
|
+
progressRange: {
|
|
783
|
+
min: 0,
|
|
784
|
+
max: 1
|
|
785
|
+
},
|
|
786
|
+
data: eventData
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
try {
|
|
790
|
+
// send start event if this function was called initially
|
|
791
|
+
if (!taskEventInfo) {
|
|
792
|
+
const eventStart: ITaskEvent = { type: eventType, id: eventId, progress: 0, data: eventData, status: 'Loading cached outputs' };
|
|
793
|
+
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_START, eventStart);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// get the cached outputs
|
|
797
|
+
const responseDto = await this._sdk.output.getCache(this._sessionId!, outputMapping);
|
|
798
|
+
|
|
799
|
+
// create atomic output api objects for them
|
|
800
|
+
const outputs: {
|
|
801
|
+
[key: string]: IOutput;
|
|
802
|
+
} = {};
|
|
803
|
+
for (const outputId in responseDto.outputs) {
|
|
804
|
+
responseDto.outputs[outputId].id = outputId;
|
|
805
|
+
outputs[outputId] = new Output(<ShapeDiverResponseOutput>responseDto.outputs[outputId], this);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// process the output data
|
|
809
|
+
const node = await this._outputLoader.loadOutputs(this._responseDto!.model?.name || 'model', outputs, {}, taskEventInfo, false);
|
|
810
|
+
|
|
811
|
+
// send the end event once done
|
|
812
|
+
const eventEnd: ITaskEvent = { type: eventType, id: eventId, progress: 1, data: eventData, status: 'Loaded cached outputs' };
|
|
813
|
+
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_END, eventEnd);
|
|
814
|
+
|
|
815
|
+
// create a mapping with a dictionary for the id of the outputs
|
|
816
|
+
const outputNodeMapping: { [key: string]: ITreeNode | undefined } = {};
|
|
817
|
+
for (const outputId in outputMapping)
|
|
818
|
+
outputNodeMapping[outputId] = node.children.find(n => n.name === outputId);
|
|
819
|
+
|
|
820
|
+
return outputNodeMapping;
|
|
821
|
+
}
|
|
822
|
+
catch (e) {
|
|
823
|
+
await this.handleError(e, retry);
|
|
824
|
+
return await this.loadCachedOutputsParallel(outputMapping, taskEventInfo, true);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
775
828
|
/**
|
|
776
829
|
* Load the outputs and return the scene graph node of the result.
|
|
777
830
|
* In case the outputs have a delay property, another customization request with the parameter set is sent.
|
|
@@ -788,15 +841,8 @@ export class SessionEngine implements ISessionEngine {
|
|
|
788
841
|
try {
|
|
789
842
|
const node = await this._outputLoader.loadOutputs(this._responseDto!.model?.name || 'model', o, of, taskEventInfo);
|
|
790
843
|
node.data.push(new SessionData(this._responseDto!));
|
|
791
|
-
|
|
792
844
|
if (cancelRequest()) return node;
|
|
793
|
-
|
|
794
|
-
if (this._automaticSceneUpdate) this.removeFromSceneTree(this._node);
|
|
795
|
-
this._node = node;
|
|
796
|
-
if (this._automaticSceneUpdate && this._closed === false) this.addToSceneTree(this._node);
|
|
797
|
-
|
|
798
|
-
this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
|
|
799
|
-
|
|
845
|
+
node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
|
|
800
846
|
return node;
|
|
801
847
|
}
|
|
802
848
|
catch (e) {
|
|
@@ -1132,13 +1178,13 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1132
1178
|
|
|
1133
1179
|
this._logger.debugLow(`Session(${this.id}).updateOutputs: Updating Outputs.`);
|
|
1134
1180
|
|
|
1135
|
-
|
|
1136
|
-
if (!this.excludeViewports.includes(r))
|
|
1137
|
-
this._stateEngine.renderingEngines[r].busy.push(customizationId);
|
|
1181
|
+
this.addBusyMode(customizationId);
|
|
1138
1182
|
|
|
1139
1183
|
const eventRequest: ITaskEvent = { type: eventType, id: eventId, progress: taskEventInfo ? (taskEventInfo.progressRange.max - taskEventInfo.progressRange.min) * 0.1 + taskEventInfo.progressRange.min : 0.1, data: eventData, status: 'Loading outputs' };
|
|
1140
1184
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventRequest);
|
|
1141
1185
|
|
|
1186
|
+
const oldOutputVersions = this._outputLoader.getCurrentOutputVersions();
|
|
1187
|
+
|
|
1142
1188
|
const newNode = await this.loadOutputs(() => this.#customizationProcess !== customizationId, {
|
|
1143
1189
|
eventId,
|
|
1144
1190
|
type: eventType,
|
|
@@ -1149,29 +1195,33 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1149
1195
|
data: eventData
|
|
1150
1196
|
});
|
|
1151
1197
|
|
|
1198
|
+
const newOutputVersions = this._outputLoader.getCurrentOutputVersions();
|
|
1199
|
+
|
|
1152
1200
|
const eventSceneUpdate: ITaskEvent = { type: eventType, id: eventId, progress: taskEventInfo ? (taskEventInfo.progressRange.max - taskEventInfo.progressRange.min) * 0.9 + taskEventInfo.progressRange.min : 0.9, data: eventData, status: 'Updating scene' };
|
|
1153
1201
|
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventSceneUpdate);
|
|
1154
1202
|
|
|
1155
1203
|
// OPTION TO SKIP - PART 1
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1204
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, eventType, taskEventInfo ? (taskEventInfo.progressRange.max - taskEventInfo.progressRange.min) * 1 + taskEventInfo.progressRange.min : 1, eventData, newNode);
|
|
1205
|
+
if (cancelResult) return cancelResult;
|
|
1206
|
+
|
|
1207
|
+
// call the update callbacks
|
|
1208
|
+
if (waitForViewportUpdate === false) {
|
|
1209
|
+
for (const outputId in this.outputs) {
|
|
1210
|
+
if (oldOutputVersions[outputId] !== newOutputVersions[outputId]) {
|
|
1211
|
+
this._eventEngine.emitEvent(EVENTTYPE.OUTPUT.OUTPUT_UPDATED, {
|
|
1212
|
+
outputId: outputId,
|
|
1213
|
+
outputVersion: newOutputVersions[outputId],
|
|
1214
|
+
newNode: newNode.children.find(c => c.name === outputId)!,
|
|
1215
|
+
oldNode: oldNode.children.find(c => c.name === outputId)!
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1169
1219
|
|
|
1170
|
-
this.
|
|
1220
|
+
await this.waitForUpdateCallbacks(newOutputVersions, oldOutputVersions, newNode, oldNode);
|
|
1171
1221
|
|
|
1172
|
-
|
|
1173
|
-
this.
|
|
1174
|
-
|
|
1222
|
+
// OPTION TO SKIP - PART 2
|
|
1223
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, eventType, taskEventInfo ? (taskEventInfo.progressRange.max - taskEventInfo.progressRange.min) * 1 + taskEventInfo.progressRange.min : 1, eventData, newNode);
|
|
1224
|
+
if (cancelResult) return cancelResult;
|
|
1175
1225
|
}
|
|
1176
1226
|
|
|
1177
1227
|
if (this.automaticSceneUpdate) this.removeFromSceneTree(this.node);
|
|
@@ -1195,9 +1245,7 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1195
1245
|
this._warningCreator();
|
|
1196
1246
|
this.node.excludeViewports = JSON.parse(JSON.stringify(this._excludeViewports));
|
|
1197
1247
|
|
|
1198
|
-
|
|
1199
|
-
if (this._stateEngine.renderingEngines[r].busy.includes(customizationId))
|
|
1200
|
-
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(customizationId), 1);
|
|
1248
|
+
this.removeBusyMode(customizationId);
|
|
1201
1249
|
|
|
1202
1250
|
this._logger.debug(`Session(${this.id}).updateOutputs: Updated outputs.`);
|
|
1203
1251
|
|
|
@@ -1207,20 +1255,28 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1207
1255
|
}
|
|
1208
1256
|
|
|
1209
1257
|
// update the viewports
|
|
1210
|
-
if (waitForViewportUpdate)
|
|
1258
|
+
if (waitForViewportUpdate) {
|
|
1211
1259
|
for (const r in this._stateEngine.renderingEngines)
|
|
1212
1260
|
if (!this.excludeViewports.includes(this._stateEngine.renderingEngines[r].id))
|
|
1213
1261
|
this._stateEngine.renderingEngines[r].update(`SessionEngine(${this.id}).updateOutputs`);
|
|
1214
1262
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1263
|
+
for (const outputId in this.outputs) {
|
|
1264
|
+
if (oldOutputVersions[outputId] !== newOutputVersions[outputId]) {
|
|
1265
|
+
this._eventEngine.emitEvent(EVENTTYPE.OUTPUT.OUTPUT_UPDATED, {
|
|
1266
|
+
outputId: outputId,
|
|
1267
|
+
outputVersion: newOutputVersions[outputId],
|
|
1268
|
+
newNode: newNode.children.find(c => c.name === outputId)!,
|
|
1269
|
+
oldNode: oldNode.children.find(c => c.name === outputId)!
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1217
1273
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1274
|
+
await this.waitForUpdateCallbacks(newOutputVersions, oldOutputVersions, newNode, oldNode);
|
|
1275
|
+
|
|
1276
|
+
// OPTION TO SKIP - PART 3
|
|
1277
|
+
const cancelResult = this.cancelProcess(customizationId, eventId, eventType, taskEventInfo ? (taskEventInfo.progressRange.max - taskEventInfo.progressRange.min) * 1 + taskEventInfo.progressRange.min : 1, eventData, newNode);
|
|
1278
|
+
if (cancelResult) return cancelResult;
|
|
1279
|
+
}
|
|
1224
1280
|
|
|
1225
1281
|
return this.node;
|
|
1226
1282
|
}
|
|
@@ -1258,9 +1314,9 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1258
1314
|
}
|
|
1259
1315
|
}
|
|
1260
1316
|
|
|
1261
|
-
// #endregion Public Methods (
|
|
1317
|
+
// #endregion Public Methods (27)
|
|
1262
1318
|
|
|
1263
|
-
// #region Private Methods (
|
|
1319
|
+
// #region Private Methods (15)
|
|
1264
1320
|
|
|
1265
1321
|
private _saveSessionSettings() {
|
|
1266
1322
|
const parameters = this.parameters;
|
|
@@ -1332,11 +1388,45 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1332
1388
|
}
|
|
1333
1389
|
}
|
|
1334
1390
|
|
|
1391
|
+
private addBusyMode(busyId: string) {
|
|
1392
|
+
for (const r in this._stateEngine.renderingEngines) {
|
|
1393
|
+
if (!this.excludeViewports.includes(r)) {
|
|
1394
|
+
this._stateEngine.renderingEngines[r].busy.push(busyId);
|
|
1395
|
+
this.#customizationBusyModes.push(busyId);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1335
1400
|
private addToSceneTree(node: ITreeNode) {
|
|
1336
1401
|
this._sceneTree.addNode(node);
|
|
1337
1402
|
this._sceneTree.root.updateVersion();
|
|
1338
1403
|
}
|
|
1339
1404
|
|
|
1405
|
+
private cancelProcess(customizationId: string, eventId: string, eventType: TASK_TYPE, eventProgress: number, eventData: unknown, newNode: ITreeNode = new SessionTreeNode()): ITreeNode | undefined {
|
|
1406
|
+
if (this.#customizationProcess !== customizationId) {
|
|
1407
|
+
this.removeBusyMode(customizationId);
|
|
1408
|
+
|
|
1409
|
+
const eventCancel: ITaskEvent = {
|
|
1410
|
+
type: eventType,
|
|
1411
|
+
id: eventId,
|
|
1412
|
+
progress: eventProgress,
|
|
1413
|
+
data: eventData,
|
|
1414
|
+
status: 'The request was exceeded by another customization request'
|
|
1415
|
+
};
|
|
1416
|
+
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel);
|
|
1417
|
+
this._logger.debug(`Session(${this.id}).cancelProcess: The request was was exceeded by another request.`);
|
|
1418
|
+
return newNode;
|
|
1419
|
+
} else if ((this._closed as boolean) === true) {
|
|
1420
|
+
this.removeBusyMode(customizationId);
|
|
1421
|
+
|
|
1422
|
+
this._logger.debug(`Session(${this.id}).cancelProcess: The session was closed during the request.`);
|
|
1423
|
+
|
|
1424
|
+
const eventCancel: ITaskEvent = { type: TASK_TYPE.SESSION_CUSTOMIZATION, id: eventId, progress: 1, data: { sessionId: this.id }, status: 'The session was closed during the request.' };
|
|
1425
|
+
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_CANCEL, eventCancel);
|
|
1426
|
+
return new SessionTreeNode();
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1340
1430
|
private checkAvailability(action?: string, checkForModelId = false) {
|
|
1341
1431
|
if (!this._responseDto)
|
|
1342
1432
|
throw new ShapeDiverViewerSessionError('Session.checkAvailability: responseDto not available.');
|
|
@@ -1385,22 +1475,33 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1385
1475
|
}
|
|
1386
1476
|
|
|
1387
1477
|
private async customizeInternal(cancelRequest: () => boolean, taskEventInfo: OutputLoaderTaskEventInfo): Promise<ISessionTreeNode> {
|
|
1388
|
-
return this.customizeSession(this._parameterValues, cancelRequest, taskEventInfo)
|
|
1478
|
+
return this.customizeSession(this._parameterValues, cancelRequest, taskEventInfo) as Promise<ISessionTreeNode>;
|
|
1389
1479
|
}
|
|
1390
1480
|
|
|
1391
|
-
private async customizeSession(parameters: { [key: string]: string }, cancelRequest: () => boolean, taskEventInfo: OutputLoaderTaskEventInfo, parallel = false, retry = false): Promise<ISessionTreeNode> {
|
|
1481
|
+
private async customizeSession(parameters: { [key: string]: string }, cancelRequest: () => boolean, taskEventInfo: OutputLoaderTaskEventInfo, parallel = false, loadOutputs = true, retry = false): Promise<ISessionTreeNode | ShapeDiverResponseDto> {
|
|
1392
1482
|
this.checkAvailability('customize');
|
|
1393
1483
|
try {
|
|
1394
1484
|
this._performanceEvaluator.startSection('sessionResponse');
|
|
1395
1485
|
const responseDto = await this._sdk.utils.submitAndWaitForCustomization(this._sdk, this._sessionId!, parameters);
|
|
1396
1486
|
this._performanceEvaluator.endSection('sessionResponse');
|
|
1397
|
-
if (
|
|
1398
|
-
|
|
1399
|
-
|
|
1487
|
+
if (loadOutputs === true) {
|
|
1488
|
+
if (cancelRequest()) return new SessionTreeNode();
|
|
1489
|
+
if (parallel === true) {
|
|
1490
|
+
// special case, we load the outputs put don't add them to the scene
|
|
1491
|
+
return this.loadOutputsParallel(responseDto, cancelRequest, taskEventInfo);
|
|
1492
|
+
} else {
|
|
1493
|
+
// default case, we load the outputs and return the nodes
|
|
1494
|
+
this.updateResponseDto(responseDto);
|
|
1495
|
+
return this.loadOutputs(cancelRequest, taskEventInfo);
|
|
1496
|
+
}
|
|
1497
|
+
} else {
|
|
1498
|
+
// special case, we don't load the outputs and only return the responseDto
|
|
1499
|
+
return responseDto;
|
|
1500
|
+
}
|
|
1400
1501
|
} catch (e) {
|
|
1401
1502
|
await this.handleError(e, retry);
|
|
1402
1503
|
if (cancelRequest()) return new SessionTreeNode();
|
|
1403
|
-
return await this.customizeSession(parameters, cancelRequest, taskEventInfo, parallel, true);
|
|
1504
|
+
return await this.customizeSession(parameters, cancelRequest, taskEventInfo, parallel, loadOutputs, true);
|
|
1404
1505
|
}
|
|
1405
1506
|
}
|
|
1406
1507
|
|
|
@@ -1455,6 +1556,16 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1455
1556
|
}
|
|
1456
1557
|
}
|
|
1457
1558
|
|
|
1559
|
+
private removeBusyMode(busyId: string) {
|
|
1560
|
+
for (const r in this._stateEngine.renderingEngines) {
|
|
1561
|
+
if (this._stateEngine.renderingEngines[r].busy.includes(busyId))
|
|
1562
|
+
this._stateEngine.renderingEngines[r].busy.splice(this._stateEngine.renderingEngines[r].busy.indexOf(busyId), 1);
|
|
1563
|
+
|
|
1564
|
+
if (this.#customizationBusyModes.includes(busyId))
|
|
1565
|
+
this.#customizationBusyModes.splice(this.#customizationBusyModes.indexOf(busyId), 1);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1458
1569
|
private removeFromSceneTree(node: ITreeNode) {
|
|
1459
1570
|
this._sceneTree.removeNode(node);
|
|
1460
1571
|
this._sceneTree.root.updateVersion();
|
|
@@ -1585,5 +1696,24 @@ export class SessionEngine implements ISessionEngine {
|
|
|
1585
1696
|
}
|
|
1586
1697
|
}
|
|
1587
1698
|
|
|
1588
|
-
|
|
1699
|
+
private async waitForUpdateCallbacks(newOutputVersions: { [key: string]: string }, oldOutputVersions: { [key: string]: string }, newNode: ITreeNode, oldNode: ITreeNode) {
|
|
1700
|
+
// call the update callback function on the session
|
|
1701
|
+
if (this._updateCallback) await Promise.resolve(this._updateCallback(newNode, oldNode));
|
|
1702
|
+
|
|
1703
|
+
const promises = [];
|
|
1704
|
+
// call the update callback functions on the outputs
|
|
1705
|
+
for (const outputId in this.outputs) {
|
|
1706
|
+
if (oldOutputVersions[outputId] !== newOutputVersions[outputId]) {
|
|
1707
|
+
promises.push(
|
|
1708
|
+
this.outputs[outputId].triggerUpdateCallback(
|
|
1709
|
+
newNode.children.find(c => c.name === outputId)!,
|
|
1710
|
+
oldNode.children.find(c => c.name === outputId)!
|
|
1711
|
+
)
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
await Promise.all(promises);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
// #endregion Private Methods (15)
|
|
1589
1719
|
}
|