@openhps/protobuf 1.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 (137) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +165 -0
  3. package/dist/cjs/InternalProtobufDeserializer.js +152 -0
  4. package/dist/cjs/InternalProtobufDeserializer.js.map +1 -0
  5. package/dist/cjs/InternalProtobufSerializer.js +137 -0
  6. package/dist/cjs/InternalProtobufSerializer.js.map +1 -0
  7. package/dist/cjs/ProtobufSerializer.js +136 -0
  8. package/dist/cjs/ProtobufSerializer.js.map +1 -0
  9. package/dist/cjs/bin/generator.js +107 -0
  10. package/dist/cjs/bin/generator.js.map +1 -0
  11. package/dist/cjs/decorators/index.js +4 -0
  12. package/dist/cjs/decorators/index.js.map +1 -0
  13. package/dist/cjs/decorators/options.js +3 -0
  14. package/dist/cjs/decorators/options.js.map +1 -0
  15. package/dist/cjs/generator/ObjectGenerator.js +316 -0
  16. package/dist/cjs/generator/ObjectGenerator.js.map +1 -0
  17. package/dist/cjs/generator/ProjectGenerator.js +120 -0
  18. package/dist/cjs/generator/ProjectGenerator.js.map +1 -0
  19. package/dist/cjs/generator/ProtobufGenerator.js +31 -0
  20. package/dist/cjs/generator/ProtobufGenerator.js.map +1 -0
  21. package/dist/cjs/generator/ServiceGenerator.js +14 -0
  22. package/dist/cjs/generator/ServiceGenerator.js.map +1 -0
  23. package/dist/cjs/generator/constants.js +21 -0
  24. package/dist/cjs/generator/constants.js.map +1 -0
  25. package/dist/cjs/generator/index.js +7 -0
  26. package/dist/cjs/generator/index.js.map +1 -0
  27. package/dist/cjs/generator/types.js +3 -0
  28. package/dist/cjs/generator/types.js.map +1 -0
  29. package/dist/cjs/index.js +6 -0
  30. package/dist/cjs/index.js.map +1 -0
  31. package/dist/esm/InternalProtobufDeserializer.js +147 -0
  32. package/dist/esm/InternalProtobufDeserializer.js.map +1 -0
  33. package/dist/esm/InternalProtobufSerializer.js +132 -0
  34. package/dist/esm/InternalProtobufSerializer.js.map +1 -0
  35. package/dist/esm/ProtobufSerializer.js +131 -0
  36. package/dist/esm/ProtobufSerializer.js.map +1 -0
  37. package/dist/esm/bin/generator.js +104 -0
  38. package/dist/esm/bin/generator.js.map +1 -0
  39. package/dist/esm/decorators/index.js +2 -0
  40. package/dist/esm/decorators/index.js.map +1 -0
  41. package/dist/esm/decorators/options.js +2 -0
  42. package/dist/esm/decorators/options.js.map +1 -0
  43. package/dist/esm/generator/ObjectGenerator.js +311 -0
  44. package/dist/esm/generator/ObjectGenerator.js.map +1 -0
  45. package/dist/esm/generator/ProjectGenerator.js +115 -0
  46. package/dist/esm/generator/ProjectGenerator.js.map +1 -0
  47. package/dist/esm/generator/ProtobufGenerator.js +27 -0
  48. package/dist/esm/generator/ProtobufGenerator.js.map +1 -0
  49. package/dist/esm/generator/ServiceGenerator.js +10 -0
  50. package/dist/esm/generator/ServiceGenerator.js.map +1 -0
  51. package/dist/esm/generator/constants.js +18 -0
  52. package/dist/esm/generator/constants.js.map +1 -0
  53. package/dist/esm/generator/index.js +4 -0
  54. package/dist/esm/generator/index.js.map +1 -0
  55. package/dist/esm/generator/types.js +2 -0
  56. package/dist/esm/generator/types.js.map +1 -0
  57. package/dist/esm/index.js +3 -0
  58. package/dist/esm/index.js.map +1 -0
  59. package/dist/esm5/InternalProtobufDeserializer.js +147 -0
  60. package/dist/esm5/InternalProtobufDeserializer.js.map +1 -0
  61. package/dist/esm5/InternalProtobufSerializer.js +132 -0
  62. package/dist/esm5/InternalProtobufSerializer.js.map +1 -0
  63. package/dist/esm5/ProtobufSerializer.js +131 -0
  64. package/dist/esm5/ProtobufSerializer.js.map +1 -0
  65. package/dist/esm5/bin/generator.js +104 -0
  66. package/dist/esm5/bin/generator.js.map +1 -0
  67. package/dist/esm5/decorators/index.js +2 -0
  68. package/dist/esm5/decorators/index.js.map +1 -0
  69. package/dist/esm5/decorators/options.js +2 -0
  70. package/dist/esm5/decorators/options.js.map +1 -0
  71. package/dist/esm5/generator/ObjectGenerator.js +311 -0
  72. package/dist/esm5/generator/ObjectGenerator.js.map +1 -0
  73. package/dist/esm5/generator/ProjectGenerator.js +115 -0
  74. package/dist/esm5/generator/ProjectGenerator.js.map +1 -0
  75. package/dist/esm5/generator/ProtobufGenerator.js +27 -0
  76. package/dist/esm5/generator/ProtobufGenerator.js.map +1 -0
  77. package/dist/esm5/generator/ServiceGenerator.js +10 -0
  78. package/dist/esm5/generator/ServiceGenerator.js.map +1 -0
  79. package/dist/esm5/generator/constants.js +18 -0
  80. package/dist/esm5/generator/constants.js.map +1 -0
  81. package/dist/esm5/generator/index.js +4 -0
  82. package/dist/esm5/generator/index.js.map +1 -0
  83. package/dist/esm5/generator/types.js +2 -0
  84. package/dist/esm5/generator/types.js.map +1 -0
  85. package/dist/esm5/index.js +3 -0
  86. package/dist/esm5/index.js.map +1 -0
  87. package/dist/types/InternalProtobufDeserializer.d.ts +9 -0
  88. package/dist/types/InternalProtobufDeserializer.d.ts.map +1 -0
  89. package/dist/types/InternalProtobufSerializer.d.ts +23 -0
  90. package/dist/types/InternalProtobufSerializer.d.ts.map +1 -0
  91. package/dist/types/ProtobufSerializer.d.ts +32 -0
  92. package/dist/types/ProtobufSerializer.d.ts.map +1 -0
  93. package/dist/types/bin/generator.d.ts +3 -0
  94. package/dist/types/bin/generator.d.ts.map +1 -0
  95. package/dist/types/decorators/index.d.ts +2 -0
  96. package/dist/types/decorators/index.d.ts.map +1 -0
  97. package/dist/types/decorators/options.d.ts +30 -0
  98. package/dist/types/decorators/options.d.ts.map +1 -0
  99. package/dist/types/generator/ObjectGenerator.d.ts +22 -0
  100. package/dist/types/generator/ObjectGenerator.d.ts.map +1 -0
  101. package/dist/types/generator/ProjectGenerator.d.ts +17 -0
  102. package/dist/types/generator/ProjectGenerator.d.ts.map +1 -0
  103. package/dist/types/generator/ProtobufGenerator.d.ts +26 -0
  104. package/dist/types/generator/ProtobufGenerator.d.ts.map +1 -0
  105. package/dist/types/generator/ServiceGenerator.d.ts +7 -0
  106. package/dist/types/generator/ServiceGenerator.d.ts.map +1 -0
  107. package/dist/types/generator/constants.d.ts +3 -0
  108. package/dist/types/generator/constants.d.ts.map +1 -0
  109. package/dist/types/generator/index.d.ts +4 -0
  110. package/dist/types/generator/index.d.ts.map +1 -0
  111. package/dist/types/generator/types.d.ts +5 -0
  112. package/dist/types/generator/types.d.ts.map +1 -0
  113. package/dist/types/index.d.ts +3 -0
  114. package/dist/types/index.d.ts.map +1 -0
  115. package/dist/web/openhps-protobuf.es.js +15165 -0
  116. package/dist/web/openhps-protobuf.es.js.map +1 -0
  117. package/dist/web/openhps-protobuf.es.min.js +2 -0
  118. package/dist/web/openhps-protobuf.es.min.js.map +1 -0
  119. package/dist/web/openhps-protobuf.js +16722 -0
  120. package/dist/web/openhps-protobuf.js.map +1 -0
  121. package/dist/web/openhps-protobuf.min.js +2 -0
  122. package/dist/web/openhps-protobuf.min.js.map +1 -0
  123. package/package.json +96 -0
  124. package/src/InternalProtobufDeserializer.ts +245 -0
  125. package/src/InternalProtobufSerializer.ts +212 -0
  126. package/src/ProtobufSerializer.ts +168 -0
  127. package/src/bin/generator.ts +131 -0
  128. package/src/decorators/index.ts +1 -0
  129. package/src/decorators/options.ts +30 -0
  130. package/src/generator/ObjectGenerator.ts +377 -0
  131. package/src/generator/ProjectGenerator.ts +130 -0
  132. package/src/generator/ProtobufGenerator.ts +49 -0
  133. package/src/generator/ServiceGenerator.ts +11 -0
  134. package/src/generator/constants.ts +19 -0
  135. package/src/generator/index.ts +3 -0
  136. package/src/generator/types.ts +4 -0
  137. package/src/index.ts +2 -0
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@openhps/protobuf",
3
+ "version": "1.0.0",
4
+ "description": "OpenHPS Protocol Buffer Generator",
5
+ "main": "dist/cjs/bin/generator.js",
6
+ "bin": {
7
+ "openhps-protobuf": "./dist/cjs/bin/generator.js"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "scripts": {
13
+ "benchmark:1": "ts-node test/bench/serialization.bench.ts",
14
+ "benchmark:2": "ts-node test/bench/socket.bench.ts",
15
+ "benchmark:3": "ts-node test/bench/mqtt.bench.ts",
16
+ "start": "node dist/cjs/bin/generator.js",
17
+ "start:debug": "ts-node src/bin/generator.ts",
18
+ "test": "mocha --config test/.mocharc.json",
19
+ "cover": "nyc mocha --config test/.mocharc.json && nyc report --reporter=cobertura",
20
+ "cover:ci": "nyc mocha --config test/.mocharc.json --reporter mocha-junit-reporter && nyc report --reporter=cobertura",
21
+ "lint": "eslint src/**",
22
+ "clean": "shx rm -rf ./dist && shx rm -rf ./docs/out",
23
+ "build": "npm run clean && npm-run-all --parallel build:ts:* && npm run build:webpack",
24
+ "build:quick": "npm-run-all --parallel build:ts:* && npm run build:webpack",
25
+ "build:typedoc": "typedoc --options docs/typedoc.json",
26
+ "build:ts:cjs": "tsc --build ./tsconfig/tsconfig.bundle.cjs.json",
27
+ "build:ts:esm": "tsc --build ./tsconfig/tsconfig.bundle.esm.json",
28
+ "build:ts:esm5": "tsc --build ./tsconfig/tsconfig.bundle.esm5.json",
29
+ "build:ts:types": "tsc --build ./tsconfig/tsconfig.bundle.types.json",
30
+ "build:webpack": "npm-run-all --parallel build:webpack:*",
31
+ "build:webpack:prod": "webpack --env prod --",
32
+ "build:webpack:dev": "webpack --env dev --",
33
+ "publish:development": "npm run bump:beta && npm publish --tag dev",
34
+ "publish:beta": "npm run bump:beta && npm publish --tag beta",
35
+ "publish:release": "npm run bump:beta && npm publish --tag latest",
36
+ "bump:development": "standard-version --prerelease alpha -m 'chore(alpha): %s' --author='ci <ci@openhps.org>'",
37
+ "bump:beta": "standard-version --prerelease beta -m 'chore(beta): %s' --author='ci <ci@openhps.org>'",
38
+ "bump:release": "standard-version -m 'chore(release): %s' --author='ci <ci@openhps.org>'"
39
+ },
40
+ "files": [
41
+ "dist/**/*",
42
+ "src/**/*",
43
+ "LICENSE"
44
+ ],
45
+ "author": "Maxim Van de Wynckel",
46
+ "license": "Apache-2.0",
47
+ "devDependencies": {
48
+ "@commitlint/cli": "^19.3.0",
49
+ "@commitlint/config-conventional": "^19.2.2",
50
+ "@openhps/core": "^0.7.2",
51
+ "@openhps/mqtt": "^0.1.9",
52
+ "@openhps/rdf": "^0.4.64",
53
+ "@openhps/rf": "^0.1.62",
54
+ "@openhps/socket": "^0.1.8",
55
+ "@types/benchmark": "^2.1.5",
56
+ "@types/chai": "^4.3.16",
57
+ "@types/fs-extra": "^11.0.4",
58
+ "@types/long": "^5.0.0",
59
+ "@types/mocha": "^10.0.6",
60
+ "@types/node": "^20.14.2",
61
+ "@typescript-eslint/eslint-plugin": ">=7.13.0",
62
+ "@typescript-eslint/parser": ">=7.13.0",
63
+ "benchmark": "^2.1.4",
64
+ "buffer": "^6.0.3",
65
+ "eslint": "^8.56.0",
66
+ "eslint-config-prettier": "^9.1.0",
67
+ "eslint-plugin-deprecation": "^2.0.0",
68
+ "eslint-plugin-import": "^2.29.1",
69
+ "eslint-plugin-jsdoc": "^48.0.3",
70
+ "eslint-plugin-prettier": "^5.1.3",
71
+ "husky": "^9.0.11",
72
+ "mocha": "^10.4.0",
73
+ "mocha-junit-reporter": "^2.2.1",
74
+ "npm-run-all": "^4.1.5",
75
+ "nyc": "^17.0.0",
76
+ "prettier": "^3.3.2",
77
+ "reflect-metadata": ">=0.2.2",
78
+ "shx": "^0.3.4",
79
+ "standard-version": "^9.5.0",
80
+ "ts-node": "^10.9.2",
81
+ "typedoc": ">=0.25.13",
82
+ "typescript": "^5.4.5",
83
+ "webpack": "^5.92.0",
84
+ "webpack-cli": "^5.1.4",
85
+ "wkt": "^0.1.1"
86
+ },
87
+ "dependencies": {
88
+ "@inquirer/prompts": "^5.0.5",
89
+ "chai": "^4",
90
+ "chalk": "4.x",
91
+ "fs-extra": "^11.2.0",
92
+ "long": "^5.2.3",
93
+ "protobufjs": "^7.3.2",
94
+ "yargs": "^17.7.2"
95
+ }
96
+ }
@@ -0,0 +1,245 @@
1
+ import {
2
+ ConcreteTypeDescriptor,
3
+ Deserializer,
4
+ IndexedObject,
5
+ MapTypeDescriptor,
6
+ ObjectMemberMetadata,
7
+ ObjectMetadata,
8
+ Serializable,
9
+ TypeDescriptor,
10
+ TypedJSON,
11
+ UUID,
12
+ } from '@openhps/core';
13
+ import * as protobuf from 'protobufjs';
14
+ import { AnyT, JsonObjectMetadata } from 'typedjson';
15
+
16
+ export class InternalProtobufDeserializer extends Deserializer {
17
+ protected static primitiveWrapper: protobuf.Type;
18
+
19
+ constructor() {
20
+ super();
21
+
22
+ InternalProtobufDeserializer.primitiveWrapper = new protobuf.Type('PrimitiveWrapperMessage');
23
+ InternalProtobufDeserializer.primitiveWrapper.add(new protobuf.Field('value', 1, 'string'));
24
+
25
+ this.setDeserializationStrategy(Number, (object: any) => {
26
+ if (typeof object === 'number') {
27
+ return object;
28
+ } else if (typeof object === 'string') {
29
+ return Number(object);
30
+ } else if (object.toNumber) {
31
+ return object.toNumber();
32
+ }
33
+ return object;
34
+ });
35
+ this.setDeserializationStrategy(
36
+ Map,
37
+ (
38
+ object: any,
39
+ typeDescriptor: MapTypeDescriptor,
40
+ knownTypes: Map<string, Serializable<any>>,
41
+ memberName: string,
42
+ deserializer: Deserializer,
43
+ memberOptions?: ObjectMemberMetadata,
44
+ serializerOptions?: any,
45
+ ) => {
46
+ const result = new Map();
47
+ Object.keys(object).forEach((key) => {
48
+ result.set(
49
+ key,
50
+ deserializer.convertSingleValue(
51
+ object[key],
52
+ typeDescriptor.valueType,
53
+ knownTypes,
54
+ memberName,
55
+ memberOptions,
56
+ serializerOptions,
57
+ ),
58
+ );
59
+ });
60
+ return result;
61
+ },
62
+ );
63
+ }
64
+
65
+ convertSingleValue(
66
+ sourceObject: any,
67
+ typeDescriptor: TypeDescriptor,
68
+ knownTypes: Map<string, Serializable<any>>,
69
+ memberName?: string,
70
+ memberOptions?: ObjectMemberMetadata,
71
+ serializerOptions?: any,
72
+ ): any {
73
+ if (this.retrievePreserveNull(memberOptions) && sourceObject === null) {
74
+ return null;
75
+ } else if (!TypedJSON.utils.isValueDefined(sourceObject)) {
76
+ return;
77
+ }
78
+
79
+ const deserializer = this.deserializationStrategy.get(typeDescriptor.ctor);
80
+ if (deserializer !== undefined) {
81
+ return deserializer(
82
+ sourceObject,
83
+ typeDescriptor,
84
+ knownTypes,
85
+ memberName,
86
+ this,
87
+ memberOptions,
88
+ serializerOptions,
89
+ );
90
+ }
91
+
92
+ if (typeof sourceObject === 'object') {
93
+ return this.convertAsObject(
94
+ sourceObject,
95
+ typeDescriptor,
96
+ knownTypes,
97
+ memberName,
98
+ this,
99
+ memberOptions,
100
+ serializerOptions,
101
+ );
102
+ }
103
+
104
+ let error = `Could not deserialize '${memberName}'; don't know how to deserialize type`;
105
+
106
+ if (typeDescriptor.hasFriendlyName()) {
107
+ error += ` '${typeDescriptor.ctor.name}'`;
108
+ }
109
+
110
+ this.errorHandler(new TypeError(`${error}.`));
111
+ }
112
+
113
+ convertAsObject<T>(
114
+ sourceObject: IndexedObject,
115
+ typeDescriptor: ConcreteTypeDescriptor,
116
+ knownTypes: Map<string, Serializable<any>>,
117
+ memberName: string,
118
+ deserializer: InternalProtobufDeserializer,
119
+ memberOptions?: ObjectMemberMetadata,
120
+ serializerOptions?: any,
121
+ ): IndexedObject | T | undefined {
122
+ let expectedSelfType = typeDescriptor.ctor;
123
+ let sourceObjectMetadata: ObjectMetadata = JsonObjectMetadata.getFromConstructor(expectedSelfType);
124
+ if (sourceObject.hasOwnProperty('_type') && sourceObject._type !== 0) {
125
+ const enumTypeClassname = sourceObjectMetadata.protobuf.enumMapping.get(sourceObject._type);
126
+ if (enumTypeClassname) {
127
+ const enumType = knownTypes.get(enumTypeClassname);
128
+ if (enumType !== expectedSelfType) {
129
+ expectedSelfType = enumType;
130
+ sourceObjectMetadata = JsonObjectMetadata.getFromConstructor(expectedSelfType);
131
+ }
132
+ }
133
+ } else if (sourceObject.type_url && sourceObject.value) {
134
+ const MessageType = serializerOptions.types.get(sourceObject.type_url) as protobuf.Type;
135
+ const message = MessageType.decode(sourceObject.value);
136
+ const data = this.convertAsObject(
137
+ message,
138
+ new ConcreteTypeDescriptor(knownTypes.get(sourceObject.type_url)),
139
+ knownTypes,
140
+ memberName,
141
+ deserializer,
142
+ memberOptions,
143
+ serializerOptions,
144
+ );
145
+ return data;
146
+ }
147
+
148
+ const sourceMetadata = sourceObjectMetadata;
149
+ // Strong-typed deserialization available, get to it.
150
+ // First deserialize properties into a temporary object.
151
+ const sourceObjectWithDeserializedProperties = {} as IndexedObject;
152
+
153
+ // Deserialize by expected properties.
154
+ sourceMetadata.dataMembers.forEach((objMemberMetadata, propKey) => {
155
+ const objMemberDebugName = `${TypedJSON.utils.nameof(sourceMetadata.classType)}.${propKey}`;
156
+ const objMemberOptions = TypedJSON.options.mergeOptions(sourceMetadata.options, objMemberMetadata.options);
157
+ const memberName =
158
+ (objMemberOptions && objMemberOptions.protobuf
159
+ ? objMemberOptions.protobuf.name
160
+ : objMemberMetadata.name) ?? objMemberMetadata.name;
161
+ const objMemberValue = sourceObject[memberName];
162
+
163
+ let revivedValue;
164
+ if (objMemberMetadata.name === 'uid') {
165
+ if (sourceObject.hasOwnProperty('uid_bytes') && sourceObject['uid_bytes'].byteLength > 0) {
166
+ revivedValue = UUID.fromBuffer(sourceObject['uid_bytes']).toString();
167
+ } else if (sourceObject.hasOwnProperty('uid_string')) {
168
+ revivedValue = sourceObject['uid_string'];
169
+ } else {
170
+ return;
171
+ }
172
+ } else if (!sourceObject.hasOwnProperty(memberName) || !objMemberValue) {
173
+ return;
174
+ } else if (objMemberMetadata.type() === AnyT && objMemberValue.type_url) {
175
+ const MessageType = serializerOptions.types.get(sourceObject[memberName].type_url) as protobuf.Type;
176
+ if (MessageType) {
177
+ const message = MessageType.decode(objMemberValue.value);
178
+ revivedValue = deserializer.convertSingleValue(
179
+ message,
180
+ new ConcreteTypeDescriptor(knownTypes.get(objMemberValue.type_url)),
181
+ knownTypes,
182
+ objMemberDebugName,
183
+ objMemberOptions,
184
+ serializerOptions,
185
+ );
186
+ } else if (objMemberValue.value) {
187
+ const message = InternalProtobufDeserializer.primitiveWrapper.decode(objMemberValue.value) as any;
188
+ switch (objMemberValue.type_url) {
189
+ case 'Boolean':
190
+ revivedValue = Boolean(message.value);
191
+ break;
192
+ case 'Number':
193
+ revivedValue = Number(message.value);
194
+ break;
195
+ case 'String':
196
+ default:
197
+ revivedValue = message.value;
198
+ }
199
+ }
200
+ } else {
201
+ revivedValue = deserializer.convertSingleValue(
202
+ objMemberValue,
203
+ objMemberMetadata.type(),
204
+ knownTypes,
205
+ objMemberDebugName,
206
+ objMemberOptions,
207
+ serializerOptions,
208
+ );
209
+ }
210
+
211
+ if (TypedJSON.utils.isValueDefined(revivedValue)) {
212
+ sourceObjectWithDeserializedProperties[objMemberMetadata.key] = revivedValue;
213
+ }
214
+ });
215
+
216
+ // Next, instantiate target object.
217
+ const targetObject: IndexedObject = deserializer.instantiateType(expectedSelfType);
218
+
219
+ // Finally, assign deserialized properties to target object.
220
+ Object.assign(targetObject, sourceObjectWithDeserializedProperties);
221
+
222
+ // Call onDeserialized method (if any).
223
+ const methodName = sourceObjectMetadata.onDeserializedMethodName;
224
+ if (methodName != null) {
225
+ if (typeof (targetObject as any)[methodName] === 'function') {
226
+ // check for member first
227
+ (targetObject as any)[methodName]();
228
+ } else if (typeof (targetObject.constructor as any)[methodName] === 'function') {
229
+ // check for static
230
+ (targetObject.constructor as any)[methodName]();
231
+ } else {
232
+ deserializer.getErrorHandler()(
233
+ new TypeError(
234
+ `onDeserialized callback` +
235
+ `'${TypedJSON.utils.nameof(
236
+ sourceObjectMetadata.classType,
237
+ )}.${methodName}' is not a method.`,
238
+ ),
239
+ );
240
+ }
241
+ }
242
+
243
+ return targetObject;
244
+ }
245
+ }
@@ -0,0 +1,212 @@
1
+ import {
2
+ ConcreteTypeDescriptor,
3
+ IndexedObject,
4
+ MapTypeDescriptor,
5
+ ObjectMemberMetadata,
6
+ ObjectMetadata,
7
+ Serializer,
8
+ TypeDescriptor,
9
+ TypedJSON,
10
+ UUID,
11
+ } from '@openhps/core';
12
+ import { Type } from 'protobufjs';
13
+ import { AnyT, JsonObjectMetadata } from 'typedjson';
14
+ import * as protobuf from 'protobufjs';
15
+
16
+ export class InternalProtobufSerializer extends Serializer {
17
+ protected static primitiveWrapper: Type;
18
+
19
+ constructor() {
20
+ super();
21
+ this.setSerializationStrategy(Map, this.convertAsMap.bind(this));
22
+ InternalProtobufSerializer.primitiveWrapper = new protobuf.Type('PrimitiveWrapperMessage');
23
+ InternalProtobufSerializer.primitiveWrapper.add(new protobuf.Field('value', 1, 'string'));
24
+ }
25
+
26
+ convertSingleValue(
27
+ sourceObject: any,
28
+ typeDescriptor: TypeDescriptor,
29
+ memberName?: string,
30
+ memberOptions?: ObjectMemberMetadata,
31
+ serializerOptions?: any,
32
+ ): any {
33
+ if (!TypedJSON.utils.isValueDefined(sourceObject)) {
34
+ return;
35
+ }
36
+
37
+ if (!TypedJSON.utils.isInstanceOf(sourceObject, typeDescriptor.ctor)) {
38
+ const expectedName = TypedJSON.utils.nameof(typeDescriptor.ctor);
39
+ const actualName = TypedJSON.utils.nameof(sourceObject.constructor);
40
+
41
+ this.errorHandler(
42
+ new TypeError(
43
+ `Could not serialize '${memberName}': expected '${expectedName}',` + ` got '${actualName}'.`,
44
+ ),
45
+ );
46
+ return;
47
+ }
48
+
49
+ const serializer = this.serializationStrategy.get(typeDescriptor.ctor);
50
+ if (serializer !== undefined) {
51
+ return serializer(sourceObject, typeDescriptor, memberName, this, memberOptions, serializerOptions);
52
+ }
53
+ // if not present in the strategy do property by property serialization
54
+ if (typeof sourceObject === 'object') {
55
+ return this.convertAsObject(
56
+ sourceObject,
57
+ typeDescriptor,
58
+ memberName,
59
+ this,
60
+ memberOptions,
61
+ serializerOptions,
62
+ );
63
+ }
64
+
65
+ let error = `Could not serialize '${memberName}'; don't know how to serialize type`;
66
+
67
+ if (typeDescriptor.hasFriendlyName()) {
68
+ error += ` '${typeDescriptor.ctor.name}'`;
69
+ }
70
+
71
+ this.errorHandler(new TypeError(`${error}.`));
72
+ }
73
+
74
+ convertAsObject(
75
+ sourceObject: IndexedObject,
76
+ typeDescriptor: ConcreteTypeDescriptor,
77
+ memberName: string,
78
+ serializer: InternalProtobufSerializer,
79
+ memberOptions?: ObjectMemberMetadata,
80
+ serializerOptions?: any,
81
+ ) {
82
+ const typeMetadata: ObjectMetadata | undefined = JsonObjectMetadata.getFromConstructor(typeDescriptor.ctor);
83
+ let sourceTypeMetadata: ObjectMetadata | undefined = JsonObjectMetadata.getFromConstructor(
84
+ sourceObject.constructor,
85
+ );
86
+
87
+ if (!sourceTypeMetadata) {
88
+ sourceTypeMetadata = typeMetadata;
89
+ }
90
+
91
+ let targetObject: IndexedObject;
92
+
93
+ const sourceMeta = sourceTypeMetadata;
94
+ targetObject = {};
95
+
96
+ const classOptions = TypedJSON.options.mergeOptions(serializer.options, sourceMeta.options);
97
+ sourceMeta.dataMembers.forEach((objMemberMetadata) => {
98
+ const objMemberOptions = TypedJSON.options.mergeOptions(classOptions, objMemberMetadata.options);
99
+ let serialized;
100
+ let memberName =
101
+ (objMemberOptions && objMemberOptions.protobuf
102
+ ? objMemberOptions.protobuf.name
103
+ : objMemberMetadata.name) ?? objMemberMetadata.name;
104
+
105
+ if (sourceObject[objMemberMetadata.key] === undefined) {
106
+ return;
107
+ }
108
+
109
+ if (objMemberMetadata.type == null) {
110
+ throw new TypeError(
111
+ `Could not serialize ${objMemberMetadata.name}, there is` +
112
+ ` no constructor nor serialization function to use.`,
113
+ );
114
+ } else if (objMemberMetadata.name === 'uid') {
115
+ const uuid = UUID.fromString(sourceObject[objMemberMetadata.key]);
116
+ if (uuid) {
117
+ serialized = uuid.toBuffer();
118
+ memberName += '_bytes';
119
+ } else {
120
+ serialized = sourceObject[objMemberMetadata.key];
121
+ memberName += '_string';
122
+ }
123
+ } else {
124
+ const MessageType = sourceTypeMetadata.protobuf.messageType;
125
+ const field = MessageType.get(objMemberMetadata.name);
126
+ serialized = this.convertSingleValue(
127
+ sourceObject[objMemberMetadata.key],
128
+ objMemberMetadata.type(),
129
+ `${TypedJSON.utils.nameof(sourceMeta.classType)}.${objMemberMetadata.key}`,
130
+ objMemberOptions,
131
+ {
132
+ ...serializerOptions,
133
+ field,
134
+ },
135
+ );
136
+ }
137
+
138
+ if (TypedJSON.utils.isValueDefined(serialized)) {
139
+ if (objMemberMetadata.type() === AnyT) {
140
+ const MessageType = serializerOptions.types.get(
141
+ sourceObject[objMemberMetadata.key].constructor.name,
142
+ ) as protobuf.Type;
143
+ if (MessageType) {
144
+ const message = MessageType.create(serialized);
145
+ serialized = {
146
+ type_url: sourceObject[objMemberMetadata.key].constructor.name,
147
+ value: MessageType.encode(message).finish(),
148
+ };
149
+ } else {
150
+ const message = InternalProtobufSerializer.primitiveWrapper.create({
151
+ value: String(sourceObject[objMemberMetadata.key]),
152
+ });
153
+ serialized = {
154
+ type_url: sourceObject[objMemberMetadata.key].constructor.name,
155
+ value: InternalProtobufSerializer.primitiveWrapper.encode(message).finish(),
156
+ };
157
+ }
158
+ }
159
+ targetObject[memberName] = serialized;
160
+ }
161
+ });
162
+
163
+ const isAnyField = serializerOptions.field && serializerOptions.field.type === 'google.protobuf.Any';
164
+ if (!isAnyField && typeMetadata.knownTypes.size > 1) {
165
+ const MessageType = sourceTypeMetadata.protobuf.messageType;
166
+ const message = MessageType.create({
167
+ ...targetObject,
168
+ _type: sourceTypeMetadata.protobuf.messageTypeEnum,
169
+ });
170
+ targetObject = message;
171
+ } else if (isAnyField) {
172
+ const MessageType = sourceTypeMetadata.protobuf.messageType;
173
+ const message = MessageType.create(targetObject);
174
+ targetObject = {
175
+ type_url: sourceObject.constructor.name,
176
+ value: MessageType.encode(message).finish(),
177
+ };
178
+ }
179
+ return targetObject;
180
+ }
181
+
182
+ /**
183
+ * Performs the conversion of a map of typed objects (or primitive values) into an array
184
+ * of simple javascript objects with `key` and `value` properties.
185
+ * @param sourceObject
186
+ * @param typeDescriptor
187
+ * @param memberName
188
+ * @param serializer
189
+ * @param memberOptions
190
+ * @param serializerOptions
191
+ */
192
+ convertAsMap(
193
+ sourceObject: Map<any, any>,
194
+ typeDescriptor: MapTypeDescriptor,
195
+ memberName: string,
196
+ serializer: Serializer,
197
+ memberOptions?: ObjectMemberMetadata,
198
+ serializerOptions?: any,
199
+ ): IndexedObject | Array<{ key: any; value: any }> {
200
+ const result = {};
201
+ sourceObject.forEach((value, key) => {
202
+ result[key] = serializer.convertSingleValue(
203
+ value,
204
+ typeDescriptor.valueType,
205
+ memberName,
206
+ memberOptions,
207
+ serializerOptions,
208
+ );
209
+ });
210
+ return result;
211
+ }
212
+ }