@shapediver/viewer.shared.services 1.15.7 → 2.0.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.
Files changed (77) hide show
  1. package/dist/converter/Converter.js +1 -1
  2. package/dist/converter/Converter.js.map +1 -1
  3. package/dist/dom-event-engine/DomEventEngine.d.ts +1 -2
  4. package/dist/dom-event-engine/DomEventEngine.d.ts.map +1 -1
  5. package/dist/dom-event-engine/DomEventEngine.js +1 -2
  6. package/dist/dom-event-engine/DomEventEngine.js.map +1 -1
  7. package/dist/event-engine/EventEngine.d.ts +3 -3
  8. package/dist/event-engine/EventEngine.d.ts.map +1 -1
  9. package/dist/event-engine/EventEngine.js +2 -2
  10. package/dist/event-engine/EventEngine.js.map +1 -1
  11. package/dist/event-engine/EventTypes.d.ts +20 -24
  12. package/dist/event-engine/EventTypes.d.ts.map +1 -1
  13. package/dist/event-engine/EventTypes.js +55 -85
  14. package/dist/event-engine/EventTypes.js.map +1 -1
  15. package/dist/http-client/HttpClient.d.ts.map +1 -1
  16. package/dist/http-client/HttpClient.js +5 -5
  17. package/dist/http-client/HttpClient.js.map +1 -1
  18. package/dist/index.d.ts +4 -4
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +10 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/input-validator/InputValidator.d.ts +3 -3
  23. package/dist/input-validator/InputValidator.d.ts.map +1 -1
  24. package/dist/input-validator/InputValidator.js +6 -2
  25. package/dist/input-validator/InputValidator.js.map +1 -1
  26. package/dist/logger/Logger.d.ts +16 -16
  27. package/dist/logger/Logger.d.ts.map +1 -1
  28. package/dist/logger/Logger.js +77 -76
  29. package/dist/logger/Logger.js.map +1 -1
  30. package/dist/logger/ShapeDiverError.d.ts +1 -1
  31. package/dist/logger/ShapeDiverError.d.ts.map +1 -1
  32. package/dist/logger/ShapeDiverError.js +1 -1
  33. package/dist/logger/ShapeDiverError.js.map +1 -1
  34. package/dist/logger/ShapeDiverViewerErrors.d.ts +24 -24
  35. package/dist/logger/ShapeDiverViewerErrors.d.ts.map +1 -1
  36. package/dist/logger/ShapeDiverViewerErrors.js +1 -1
  37. package/dist/logger/ShapeDiverViewerErrors.js.map +1 -1
  38. package/dist/performance-evaluator/PerformanceEvaluator.js +1 -1
  39. package/dist/performance-evaluator/PerformanceEvaluator.js.map +1 -1
  40. package/dist/settings-engine/SettingsEngine.d.ts +1 -1
  41. package/dist/settings-engine/SettingsEngine.d.ts.map +1 -1
  42. package/dist/settings-engine/SettingsEngine.js +16 -25
  43. package/dist/settings-engine/SettingsEngine.js.map +1 -1
  44. package/dist/state-engine/StateEngine.d.ts +7 -16
  45. package/dist/state-engine/StateEngine.d.ts.map +1 -1
  46. package/dist/state-engine/StateEngine.js +8 -21
  47. package/dist/state-engine/StateEngine.js.map +1 -1
  48. package/dist/system-info/SystemInfo.js +1 -1
  49. package/dist/system-info/SystemInfo.js.map +1 -1
  50. package/dist/type-check/TypeChecker.js +1 -1
  51. package/dist/type-check/TypeChecker.js.map +1 -1
  52. package/dist/uuid-generator/UuidGenerator.js +5 -5
  53. package/dist/uuid-generator/UuidGenerator.js.map +1 -1
  54. package/package.json +11 -8
  55. package/src/converter/Converter.ts +299 -0
  56. package/src/dom-event-engine/DomEventEngine.ts +334 -0
  57. package/src/dom-event-engine/IDomEventListener.ts +14 -0
  58. package/src/event-engine/EventEngine.ts +116 -0
  59. package/src/event-engine/EventTypes.ts +66 -0
  60. package/src/event-engine/interfaces/ICallback.ts +5 -0
  61. package/src/event-engine/interfaces/IEvent.ts +1 -0
  62. package/src/event-engine/interfaces/IListener.ts +8 -0
  63. package/src/http-client/HttpClient.ts +177 -0
  64. package/src/http-client/HttpResponse.ts +4 -0
  65. package/src/index.ts +82 -0
  66. package/src/input-validator/InputValidator.ts +100 -0
  67. package/src/logger/Logger.ts +297 -0
  68. package/src/logger/ShapeDiverError.ts +48 -0
  69. package/src/logger/ShapeDiverViewerErrors.ts +115 -0
  70. package/src/performance-evaluator/PerformanceEvaluator.ts +102 -0
  71. package/src/settings-engine/SettingsEngine.ts +176 -0
  72. package/src/state-engine/StateEngine.ts +73 -0
  73. package/src/state-engine/StatePromise.ts +54 -0
  74. package/src/system-info/SystemInfo.ts +117 -0
  75. package/src/type-check/TypeChecker.ts +13 -0
  76. package/src/uuid-generator/UuidGenerator.ts +41 -0
  77. package/tsconfig.json +17 -0
@@ -0,0 +1,116 @@
1
+ import { container, singleton } from 'tsyringe'
2
+
3
+ import { EVENTTYPE, MainEventTypes } from './EventTypes'
4
+ import { IListener } from './interfaces/IListener'
5
+ import { ICallback } from './interfaces/ICallback'
6
+ import { IEvent } from './interfaces/IEvent'
7
+ import { UuidGenerator } from '../uuid-generator/UuidGenerator'
8
+ import { Logger, LOGGING_TOPIC } from '../logger/Logger'
9
+
10
+ @singleton()
11
+ export class EventEngine {
12
+ // #region Properties (2)
13
+
14
+ protected readonly _uuidGenerator: UuidGenerator = <UuidGenerator>container.resolve(UuidGenerator);
15
+ protected readonly _logger: Logger = <Logger>container.resolve(Logger);
16
+ private _eventListeners: {
17
+ [key: string]: IListener[]
18
+ };
19
+
20
+ // #endregion Properties (2)
21
+
22
+ // #region Constructors (1)
23
+
24
+ constructor() {
25
+ this._eventListeners = {};
26
+ for (const type in EVENTTYPE) {
27
+ const subEventType = EVENTTYPE[type as keyof typeof EVENTTYPE];
28
+ this._eventListeners[type.toLowerCase()] = [];
29
+ for (const subtype in subEventType) {
30
+ this._eventListeners[subEventType[subtype as keyof typeof subEventType]] = [];
31
+ }
32
+ }
33
+ }
34
+
35
+ // #endregion Constructors (1)
36
+
37
+ private convertTypeToString(type: string | MainEventTypes): string {
38
+ let typeString: string = '';
39
+ if(typeof type === 'string') typeString = type;
40
+
41
+ for (const mainType in EVENTTYPE)
42
+ if(type === EVENTTYPE[mainType as keyof typeof EVENTTYPE])
43
+ typeString = mainType.toLowerCase();
44
+
45
+ if(!typeString || !this._eventListeners[typeString]) {
46
+ this._logger.warn(LOGGING_TOPIC.GENERAL, 'EventEngine.convertTypeToString: No valid type provided.');
47
+ return '';
48
+ }
49
+
50
+ return typeString;
51
+ }
52
+
53
+ // #region Public Methods (3)
54
+
55
+ /**
56
+ * Adds a listener that listenes to the provided type. If no valid type is specified, an error is thrown.
57
+ *
58
+ * @param type the type of the event
59
+ * @param cb the callback that should be called
60
+ * @returns an unique token to be able to remove the listener
61
+ */
62
+ public addListener(type: string | MainEventTypes, cb: ICallback): string {
63
+ const typeString: string = this.convertTypeToString(type);
64
+ if(!typeString) return '';
65
+ const token = this._uuidGenerator.create();
66
+ this._eventListeners[typeString]?.push({ token, cb });
67
+ return token;
68
+ }
69
+
70
+ /**
71
+ * Emits the event to all callbacks that listen to the type.
72
+ *
73
+ * @param type the type of the event
74
+ * @param event the event to emit
75
+ */
76
+ public emitEvent(type: string | MainEventTypes, event: IEvent): void {
77
+ const typeString: string = this.convertTypeToString(type);
78
+
79
+ if (this._eventListeners[typeString] && this._eventListeners[typeString].length !== 0)
80
+ for (let i = 0; i < this._eventListeners[typeString]!.length; i++)
81
+ this._eventListeners[typeString]![i].cb(event);
82
+
83
+ if(typeString.includes('.'))
84
+ this.emitEvent(typeString.substr(0, typeString.indexOf('.')), event);
85
+ }
86
+
87
+ /**
88
+ * Removes a listener with the specified token.
89
+ *
90
+ * @param token the token of the listener
91
+ * @returns result of the targeted operation
92
+ */
93
+ public removeListener(token: string): boolean {
94
+ for (const type in EVENTTYPE) {
95
+ const subEventType = EVENTTYPE[type as keyof typeof EVENTTYPE];
96
+ const typeLowerCase = type.toLowerCase();
97
+ for (let i = 0; i < this._eventListeners[typeLowerCase]!.length; i++) {
98
+ if (this._eventListeners[typeLowerCase]![i].token === token) {
99
+ this._eventListeners[typeLowerCase]!.splice(i, 1);
100
+ return true;
101
+ }
102
+ }
103
+ for (const subtype in subEventType) {
104
+ for (let i = 0; i < this._eventListeners[subEventType[subtype as keyof typeof subEventType]]!.length; i++) {
105
+ if (this._eventListeners[subEventType[subtype as keyof typeof subEventType]]![i].token === token) {
106
+ this._eventListeners[subEventType[subtype as keyof typeof subEventType]]!.splice(i, 1);
107
+ return true;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return false;
113
+ }
114
+
115
+ // #endregion Public Methods (3)
116
+ }
@@ -0,0 +1,66 @@
1
+ export enum EVENTTYPE_CAMERA {
2
+ CAMERA_START = "camera.start",
3
+ CAMERA_MOVE = "camera.move",
4
+ CAMERA_END = "camera.end",
5
+ }
6
+
7
+ export enum EVENTTYPE_RENDERING {
8
+ BEAUTY_RENDERING_FINISHED = "rendering.beautyRenderingFinished"
9
+ }
10
+
11
+ export enum EVENTTYPE_SCENE {
12
+ SCENE_BOUNDING_BOX_CHANGE = "scene.boundingBoxChange"
13
+ }
14
+
15
+ // VIEWPORT
16
+ // FRAMERATE
17
+ // RENDER_INFO
18
+ // RENDER_BEAUTY_START
19
+ // RENDER_BEAUTY_CANCEL
20
+ // RENDER_BEAUTY_END
21
+ // VISIBILITY_ON
22
+ // VISIBILITY_OFF
23
+
24
+ export enum EVENTTYPE_VIEWPORT {
25
+ BUSY_MODE_ON = "viewport.busy.on",
26
+ BUSY_MODE_OFF = "viewport.busy.off",
27
+ VIEWPORT_CREATED = "viewport.created",
28
+ VIEWPORT_UPDATED = "viewport.updated",
29
+ VIEWPORT_CLOSED = "viewport.closed"
30
+ }
31
+
32
+ export enum EVENTTYPE_SESSION {
33
+ SESSION_CREATED = "session.created",
34
+ SESSION_CUSTOMIZED = "session.customized",
35
+ SESSION_CLOSED = "session.closed",
36
+ SESSION_INITIAL_OUTPUTS_LOADED = 'session.initialOutputsLoaded'
37
+ }
38
+
39
+ export enum EVENTTYPE_TASK {
40
+ TASK_START = "task.start",
41
+ TASK_PROCESS = "task.process",
42
+ TASK_END = "task.end",
43
+ TASK_CANCEL = "task.cancel",
44
+ }
45
+
46
+ export enum EVENTTYPE_INTERACTION {
47
+ DRAG_START = "interaction.drag.start",
48
+ DRAG_MOVE = "interaction.drag.move",
49
+ DRAG_END = "interaction.drag.end",
50
+ HOVER_ON = "interaction.hover.on",
51
+ HOVER_OFF = "interaction.hover.off",
52
+ SELECT_ON = "interaction.select.on",
53
+ SELECT_OFF = "interaction.select.off",
54
+ }
55
+
56
+ export const EVENTTYPE = {
57
+ CAMERA: EVENTTYPE_CAMERA,
58
+ RENDERING: EVENTTYPE_RENDERING,
59
+ SCENE: EVENTTYPE_SCENE,
60
+ SESSION: EVENTTYPE_SESSION,
61
+ VIEWPORT: EVENTTYPE_VIEWPORT,
62
+ INTERACTION: EVENTTYPE_INTERACTION,
63
+ TASK: EVENTTYPE_TASK
64
+ };
65
+
66
+ export type MainEventTypes = typeof EVENTTYPE_CAMERA | typeof EVENTTYPE_RENDERING | typeof EVENTTYPE_SCENE | typeof EVENTTYPE_SESSION | typeof EVENTTYPE_VIEWPORT | typeof EVENTTYPE_INTERACTION | typeof EVENTTYPE_TASK;
@@ -0,0 +1,5 @@
1
+ import { IEvent } from './IEvent'
2
+
3
+ export interface ICallback {
4
+ (event: IEvent): void;
5
+ }
@@ -0,0 +1 @@
1
+ export interface IEvent {};
@@ -0,0 +1,8 @@
1
+ import { ICallback } from './ICallback'
2
+
3
+ export interface IListener {
4
+ // #region Properties (2)
5
+ cb: ICallback;
6
+ token: string;
7
+ // #endregion Properties (2)
8
+ }
@@ -0,0 +1,177 @@
1
+ import axios, { AxiosRequestConfig } from 'axios'
2
+ import { singleton } from 'tsyringe'
3
+ import { ShapeDiverViewerConnectionError } from '../logger/ShapeDiverViewerErrors';
4
+ import { HttpResponse } from './HttpResponse';
5
+
6
+ @singleton()
7
+ export class HttpClient {
8
+ // #region Properties (2)
9
+
10
+ private _dataCache: {
11
+ [key: string]: Promise<HttpResponse<any>>
12
+ } = {};
13
+
14
+ private _sessionLoading: {
15
+ [key: string]: {
16
+ getOutput: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
17
+ getTexture: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
18
+ getExport: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
19
+ downloadTexture: (sessionId: string, url: string) => Promise<[ArrayBuffer, string]>,
20
+ }
21
+ } = {};
22
+
23
+ // #endregion Properties (2)
24
+
25
+ // #region Constructors (1)
26
+
27
+ constructor() {
28
+ axios.interceptors.response.use(
29
+ response => {
30
+ return response;
31
+ },
32
+ error => {
33
+ throw new ShapeDiverViewerConnectionError(error.message, error.response.status, error);
34
+ });
35
+ axios.interceptors.request.use(
36
+ response => {
37
+ return response;
38
+ },
39
+ error => {
40
+ throw new ShapeDiverViewerConnectionError(error.message, undefined, error);
41
+ });
42
+ }
43
+
44
+ // #endregion Constructors (1)
45
+
46
+ // #region Public Methods (7)
47
+
48
+ private loadingCriterion(href: string): { sessionId: string, assetData: string, type: 'output' | 'export' | 'texture' } | undefined {
49
+ // searching for "/session/SESSION_ID/{'output' | 'export' | 'texture'}/ASSET_DATA"
50
+ const parts = href.split('/');
51
+ const sessionPartIndex = parts.indexOf('session');
52
+
53
+ // There have to be at exactly 4 parts, including the session
54
+ if (sessionPartIndex !== -1 && parts.length === sessionPartIndex + 4) {
55
+ const sessionId = parts[sessionPartIndex + 1];
56
+ // no such session has been registered, should never happen
57
+ if (!this._sessionLoading[sessionId]) return;
58
+
59
+ const type = parts[sessionPartIndex + 2];
60
+ // the type is not supported
61
+ if (type !== 'output' && type !== 'export' && type !== 'texture') return;
62
+
63
+ const assetData = parts[sessionPartIndex + 3];
64
+
65
+ return { sessionId, assetData, type };
66
+ }
67
+
68
+ return;
69
+ }
70
+
71
+ public addDataLoading(sessionId: string, callbacks: {
72
+ getOutput: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
73
+ getTexture: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
74
+ getExport: (sessionId: string, assetData: string) => Promise<[ArrayBuffer, string]>,
75
+ downloadTexture: (sessionId: string, url: string) => Promise<[ArrayBuffer, string]>,
76
+ }) {
77
+ this._sessionLoading[sessionId] = callbacks;
78
+ }
79
+
80
+ public async get(href: string, config: AxiosRequestConfig = { responseType: 'arraybuffer' }, textureLoading: boolean = false): Promise<HttpResponse<any>> {
81
+ const dataKey = btoa(href);
82
+ if (dataKey in this._dataCache) return await this._dataCache[dataKey];
83
+
84
+ const loadingInfo = this.loadingCriterion(href);
85
+ if (loadingInfo) {
86
+ switch (loadingInfo.type) {
87
+ case 'output':
88
+ this._dataCache[dataKey] = new Promise<HttpResponse<ArrayBuffer>>(resolve => {
89
+ this._sessionLoading[loadingInfo.sessionId]
90
+ .getOutput(loadingInfo.sessionId, loadingInfo.assetData)
91
+ .then(result => {
92
+ resolve({
93
+ data: result[0],
94
+ headers: {
95
+ 'content-type': result[1]
96
+ }
97
+ })
98
+ })
99
+
100
+ });
101
+ break;
102
+
103
+ case 'export':
104
+ this._dataCache[dataKey] = new Promise<HttpResponse<ArrayBuffer>>(resolve => {
105
+ this._sessionLoading[loadingInfo.sessionId]
106
+ .getExport(loadingInfo.sessionId, loadingInfo.assetData)
107
+ .then(result => {
108
+ resolve({
109
+ data: result[0],
110
+ headers: {
111
+ 'content-type': result[1]
112
+ }
113
+ })
114
+ })
115
+
116
+ });
117
+ break;
118
+
119
+ case 'texture':
120
+ this._dataCache[dataKey] = new Promise<HttpResponse<ArrayBuffer>>(resolve => {
121
+ this._sessionLoading[loadingInfo.sessionId]
122
+ .getTexture(loadingInfo.sessionId, loadingInfo.assetData)
123
+ .then(result => {
124
+ resolve({
125
+ data: result[0],
126
+ headers: {
127
+ 'content-type': result[1]
128
+ }
129
+ })
130
+ })
131
+
132
+ });
133
+ break;
134
+
135
+ default:
136
+ this._dataCache[dataKey] = axios(href, Object.assign({ method: 'get' }, config));
137
+ }
138
+ } else {
139
+ // separation texture vs something else...
140
+ if(textureLoading) {
141
+ // we can load blobs and data urls directly
142
+ // if no session is registered, we have to load the texture directly
143
+ if(href.startsWith('blob:') || href.startsWith('data:') || Object.values(this._sessionLoading).length === 0) {
144
+ this._dataCache[dataKey] = axios(href, Object.assign({ method: 'get' }, config));
145
+ } else {
146
+ // take first session to load a texture that is not session related
147
+ const sessionId = Object.keys(this._sessionLoading)[0];
148
+
149
+ this._dataCache[dataKey] = new Promise<HttpResponse<any>>(resolve => {
150
+ this._sessionLoading[sessionId].downloadTexture(sessionId, href).then((result) => {
151
+ resolve({
152
+ data: result[0],
153
+ headers: {
154
+ 'content-type': result[1]
155
+ }
156
+ })
157
+ });
158
+ });
159
+ }
160
+ } else {
161
+ this._dataCache[dataKey] = axios(href, Object.assign({ method: 'get' }, config));
162
+ }
163
+ }
164
+
165
+ return this._dataCache[dataKey];
166
+ }
167
+
168
+ public async loadTexture(href: string): Promise<HttpResponse<ArrayBuffer>> {
169
+ return this.get(href, undefined, true);
170
+ }
171
+
172
+ public removeDataLoading(sessionId: string) {
173
+ delete this._sessionLoading[sessionId];
174
+ }
175
+
176
+ // #endregion Public Methods (7)
177
+ }
@@ -0,0 +1,4 @@
1
+ export interface HttpResponse<T = any> {
2
+ data: T;
3
+ headers: any
4
+ }
package/src/index.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { EventEngine } from './event-engine/EventEngine'
2
+ import { EVENTTYPE, EVENTTYPE_CAMERA, EVENTTYPE_INTERACTION, EVENTTYPE_RENDERING, EVENTTYPE_SCENE, EVENTTYPE_SESSION, EVENTTYPE_TASK, EVENTTYPE_VIEWPORT, MainEventTypes } from './event-engine/EventTypes'
3
+ import { SettingsEngine } from './settings-engine/SettingsEngine'
4
+ import { StateEngine } from './state-engine/StateEngine'
5
+ import { SystemInfo } from './system-info/SystemInfo'
6
+ import { DomEventEngine } from './dom-event-engine/DomEventEngine'
7
+ import { IDomEventListener } from './dom-event-engine/IDomEventListener'
8
+ import { IEvent } from './event-engine/interfaces/IEvent'
9
+ import { Converter } from './converter/Converter'
10
+ import { HttpClient } from './http-client/HttpClient'
11
+ import { InputValidator } from './input-validator/InputValidator'
12
+ import { TypeChecker } from './type-check/TypeChecker'
13
+ import { UuidGenerator } from './uuid-generator/UuidGenerator'
14
+ import { PerformanceEvaluator } from './performance-evaluator/PerformanceEvaluator'
15
+ import { Logger, LOGGING_LEVEL, LOGGING_TOPIC } from './logger/Logger'
16
+ import { StatePromise } from './state-engine/StatePromise'
17
+ import { ShapeDiverViewerArError, ShapeDiverViewerCameraError, ShapeDiverViewerDataProcessingError, ShapeDiverViewerEnvironmentMapError, ShapeDiverViewerLightError, ShapeDiverViewerSessionError, ShapeDiverViewerSettingsError, ShapeDiverViewerUnknownError, ShapeDiverViewerValidationError, ShapeDiverViewerGeneralError, ShapeDiverViewerWebGLError } from './logger/ShapeDiverViewerErrors'
18
+ import { ShapeDiverError as ShapeDiverBackendError } from '@shapediver/sdk.geometry-api-sdk-v2'
19
+ import { ShapeDiverViewerError } from './logger/ShapeDiverError'
20
+ import { HttpResponse } from './http-client/HttpResponse'
21
+
22
+ export {
23
+ EventEngine, EVENTTYPE, MainEventTypes, IEvent,
24
+ EVENTTYPE_CAMERA, EVENTTYPE_RENDERING, EVENTTYPE_SCENE, EVENTTYPE_SESSION, EVENTTYPE_VIEWPORT, EVENTTYPE_INTERACTION, EVENTTYPE_TASK
25
+ }
26
+
27
+ export {
28
+ SettingsEngine
29
+ }
30
+
31
+ export {
32
+ StateEngine, StatePromise
33
+ }
34
+
35
+ export {
36
+ SystemInfo
37
+ }
38
+
39
+ export {
40
+ IDomEventListener, DomEventEngine
41
+ }
42
+
43
+ export {
44
+ HttpClient, HttpResponse
45
+ }
46
+
47
+ export {
48
+ UuidGenerator
49
+ }
50
+
51
+ export {
52
+ Converter
53
+ }
54
+
55
+ export {
56
+ TypeChecker
57
+ }
58
+
59
+ export {
60
+ InputValidator
61
+ }
62
+
63
+ export {
64
+ Logger, LOGGING_LEVEL, LOGGING_TOPIC,
65
+ ShapeDiverViewerError,
66
+ ShapeDiverViewerDataProcessingError,
67
+ ShapeDiverViewerEnvironmentMapError,
68
+ ShapeDiverViewerWebGLError,
69
+ ShapeDiverViewerSettingsError,
70
+ ShapeDiverViewerSessionError,
71
+ ShapeDiverViewerGeneralError,
72
+ ShapeDiverViewerUnknownError,
73
+ ShapeDiverViewerArError,
74
+ ShapeDiverViewerLightError,
75
+ ShapeDiverViewerCameraError,
76
+ ShapeDiverViewerValidationError,
77
+ ShapeDiverBackendError
78
+ }
79
+
80
+ export {
81
+ PerformanceEvaluator
82
+ }
@@ -0,0 +1,100 @@
1
+ import { container, singleton } from 'tsyringe'
2
+ import DOMPurify from 'dompurify';
3
+ import { Logger, LOGGING_TOPIC } from '../logger/Logger'
4
+ import { ShapeDiverViewerValidationError } from '../logger/ShapeDiverViewerErrors';
5
+ import { TypeChecker } from '../type-check/TypeChecker'
6
+
7
+ export type Types = 'string' | 'boolean' | 'function' |
8
+ 'HTMLCanvasElement' | 'enum' |
9
+ 'number' | 'factor' | 'positive' |
10
+ 'vec3' | 'mat4' | 'cubeMap' | 'array' | 'stringArray' | 'object' | 'file' | 'color';
11
+
12
+ @singleton()
13
+ export class InputValidator {
14
+
15
+ private readonly _logger: Logger = <Logger>container.resolve(Logger);
16
+ private readonly _typeChecker: TypeChecker = <TypeChecker>container.resolve(TypeChecker);
17
+
18
+ public validateAndError(topic: LOGGING_TOPIC, scope: string, value: any, type: Types, defined: boolean = true, enumValues: string[] = []) {
19
+ const res = this.validate(value, type, defined, enumValues);
20
+ if(res) return;
21
+
22
+ const error = new ShapeDiverViewerValidationError(`${scope}: Input could not be validated. ${value} is not of type ${type}.${defined === false ? ' (Can also be undefined)' : ''}`, value, type);
23
+ throw this._logger.handleError(LOGGING_TOPIC.GENERAL, 'InputValidator.validateAndError', error, false);
24
+ }
25
+
26
+ private validate(value: any, stringLiteral: Types, defined: boolean = true, enumValues: string[] = []): boolean {
27
+ if (defined === false && typeof value === 'undefined') return true;
28
+
29
+ switch (stringLiteral) {
30
+ case 'array':
31
+ if(Array.isArray(value)) return true;
32
+ break;
33
+ case 'string':
34
+ if(this._typeChecker.isTypeOf(value, 'string')) return true;
35
+ break;
36
+ case 'boolean':
37
+ if(this._typeChecker.isTypeOf(value, 'boolean')) return true;
38
+ break;
39
+ case 'function':
40
+ if(this._typeChecker.isTypeOf(value, 'function')) return true;
41
+ break;
42
+ case 'number':
43
+ if(this._typeChecker.isTypeOf(value, 'number') && !isNaN(value)) return true;
44
+ break;
45
+ case 'factor':
46
+ if(this._typeChecker.isTypeOf(value, 'number') && value >= 0 && value <= 1) return true;
47
+ break;
48
+ case 'positive':
49
+ if(this._typeChecker.isTypeOf(value, 'number') && value >= 0) return true;
50
+ break;
51
+ case 'HTMLCanvasElement':
52
+ if(this._typeChecker.isHTMLCanvasElement(value)) return true;
53
+ break;
54
+ case 'enum':
55
+ if(this._typeChecker.isTypeOf(value, 'string') && enumValues.includes(value)) return true;
56
+ break;
57
+ case 'vec3':
58
+ if (value.constructor === Float32Array)
59
+ value = Array.from(value);
60
+ if(Array.isArray(value) && this._typeChecker.isTypeOf(value[0], 'number') && this._typeChecker.isTypeOf(value[1], 'number') && this._typeChecker.isTypeOf(value[2], 'number')) return true;
61
+ break;
62
+ case 'cubeMap':
63
+ if(Array.isArray(value) && value.length === 6 && this._typeChecker.isTypeOf(value[0], 'string') && this._typeChecker.isTypeOf(value[1], 'string') && this._typeChecker.isTypeOf(value[2], 'string') && this._typeChecker.isTypeOf(value[3], 'string') && this._typeChecker.isTypeOf(value[4], 'string') && this._typeChecker.isTypeOf(value[5], 'string')) return true;
64
+ if(this._typeChecker.isTypeOf(value, 'string')) return true;
65
+ break;
66
+ case 'stringArray':
67
+ if(Array.isArray(value)) {
68
+ let check = true;
69
+ for(let i = 0; i < value.length; i++)
70
+ if(typeof value[i] !== 'string') check = false;
71
+ if (check === true) return true;
72
+ }
73
+ break;
74
+ case 'object':
75
+ if(this._typeChecker.isTypeOf(value, 'object')) return true;
76
+ break;
77
+ case 'file':
78
+ if(this._typeChecker.isTypeOf(value, 'string') || value instanceof File || value instanceof Blob) return true;
79
+ break;
80
+ case 'color':
81
+ if(this._typeChecker.isTypeOf(value, 'string') || (Array.isArray(value) && this._typeChecker.isTypeOf(value[0], 'number') && this._typeChecker.isTypeOf(value[1], 'number') && this._typeChecker.isTypeOf(value[2], 'number')) || this._typeChecker.isTypeOf(value, 'number')) return true;
82
+ break;
83
+ case 'mat4':
84
+ if (value.constructor === Float32Array)
85
+ value = Array.from(value);
86
+ if(Array.isArray(value) && this._typeChecker.isTypeOf(value[0], 'number') && this._typeChecker.isTypeOf(value[1], 'number') && this._typeChecker.isTypeOf(value[2], 'number') && this._typeChecker.isTypeOf(value[3], 'number')
87
+ && this._typeChecker.isTypeOf(value[4], 'number') && this._typeChecker.isTypeOf(value[5], 'number') && this._typeChecker.isTypeOf(value[6], 'number') && this._typeChecker.isTypeOf(value[7], 'number')
88
+ && this._typeChecker.isTypeOf(value[8], 'number') && this._typeChecker.isTypeOf(value[9], 'number') && this._typeChecker.isTypeOf(value[10], 'number') && this._typeChecker.isTypeOf(value[11], 'number')
89
+ && this._typeChecker.isTypeOf(value[12], 'number') && this._typeChecker.isTypeOf(value[13], 'number') && this._typeChecker.isTypeOf(value[14], 'number') && this._typeChecker.isTypeOf(value[15], 'number')) return true;
90
+ break;
91
+ default:
92
+ return false;
93
+ }
94
+ return false;
95
+ }
96
+
97
+ public sanitize(input: string): string {
98
+ return DOMPurify.sanitize(input);
99
+ }
100
+ }